cli/internal/cmd/vm/cmd_container.go

346 lines
9.1 KiB
Go
Raw Normal View History

package vm
import (
"context"
"errors"
"fmt"
Migrate pkg/container to io.Medium abstraction (#292) * chore(io): migrate pkg/container to Medium abstraction Migrated State, Templates, and LinuxKitManager in pkg/container to use the io.Medium abstraction for storage operations. - Introduced TemplateManager struct to handle template logic with injected medium. - Updated State struct to use injected medium for persistence. - Updated LinuxKitManager to hold and use an io.Medium instance. - Updated all internal callers in internal/cmd/vm and pkg/devops to use new APIs. - Adapted and maintained comprehensive test coverage in linuxkit_test.go. - Fixed naming collision with standard io package by aliasing it as goio. * chore(io): migrate pkg/container to Medium abstraction (v2) - Migrated State, Templates, and LinuxKitManager in pkg/container to use io.Medium. - Introduced TemplateManager struct for dependency injection. - Updated all call sites in internal/cmd/vm and pkg/devops. - Restored and adapted comprehensive test suite in linuxkit_test.go. - Fixed naming collisions and followed project test naming conventions. * chore(io): address PR feedback for container Medium migration - Added Open method to io.Medium interface to support log streaming. - Implemented Open in local.Medium and MockMedium. - Fixed extension inconsistency in GetTemplate (.yml vs .yaml). - Refactored TemplateManager to use configurable WorkingDir and HomeDir. - Reused TemplateManager instance in cmd_templates.go. - Updated LinuxKitManager to use medium.Open for log access. - Maintained and updated all tests to verify these improvements.
2026-02-04 15:33:22 +00:00
goio "io"
"os"
"strings"
"text/tabwriter"
"time"
"forge.lthn.ai/core/cli/pkg/container"
"forge.lthn.ai/core/cli/pkg/i18n"
"forge.lthn.ai/core/cli/pkg/io"
"github.com/spf13/cobra"
)
var (
runName string
runDetach bool
runMemory int
runCPUs int
runSSHPort int
runTemplateName string
runVarFlags []string
)
// addVMRunCommand adds the 'run' command under vm.
func addVMRunCommand(parent *cobra.Command) {
runCmd := &cobra.Command{
Use: "run [image]",
Short: i18n.T("cmd.vm.run.short"),
Long: i18n.T("cmd.vm.run.long"),
RunE: func(cmd *cobra.Command, args []string) error {
opts := container.RunOptions{
Name: runName,
Detach: runDetach,
Memory: runMemory,
CPUs: runCPUs,
SSHPort: runSSHPort,
}
// If template is specified, build and run from template
if runTemplateName != "" {
vars := ParseVarFlags(runVarFlags)
return RunFromTemplate(runTemplateName, vars, opts)
}
// Otherwise, require an image path
if len(args) == 0 {
return errors.New(i18n.T("cmd.vm.run.error.image_required"))
}
image := args[0]
return runContainer(image, runName, runDetach, runMemory, runCPUs, runSSHPort)
},
}
runCmd.Flags().StringVar(&runName, "name", "", i18n.T("cmd.vm.run.flag.name"))
runCmd.Flags().BoolVarP(&runDetach, "detach", "d", false, i18n.T("cmd.vm.run.flag.detach"))
runCmd.Flags().IntVar(&runMemory, "memory", 0, i18n.T("cmd.vm.run.flag.memory"))
runCmd.Flags().IntVar(&runCPUs, "cpus", 0, i18n.T("cmd.vm.run.flag.cpus"))
runCmd.Flags().IntVar(&runSSHPort, "ssh-port", 0, i18n.T("cmd.vm.run.flag.ssh_port"))
runCmd.Flags().StringVar(&runTemplateName, "template", "", i18n.T("cmd.vm.run.flag.template"))
runCmd.Flags().StringArrayVar(&runVarFlags, "var", nil, i18n.T("cmd.vm.run.flag.var"))
parent.AddCommand(runCmd)
}
func runContainer(image, name string, detach bool, memory, cpus, sshPort int) error {
Migrate pkg/container to io.Medium abstraction (#292) * chore(io): migrate pkg/container to Medium abstraction Migrated State, Templates, and LinuxKitManager in pkg/container to use the io.Medium abstraction for storage operations. - Introduced TemplateManager struct to handle template logic with injected medium. - Updated State struct to use injected medium for persistence. - Updated LinuxKitManager to hold and use an io.Medium instance. - Updated all internal callers in internal/cmd/vm and pkg/devops to use new APIs. - Adapted and maintained comprehensive test coverage in linuxkit_test.go. - Fixed naming collision with standard io package by aliasing it as goio. * chore(io): migrate pkg/container to Medium abstraction (v2) - Migrated State, Templates, and LinuxKitManager in pkg/container to use io.Medium. - Introduced TemplateManager struct for dependency injection. - Updated all call sites in internal/cmd/vm and pkg/devops. - Restored and adapted comprehensive test suite in linuxkit_test.go. - Fixed naming collisions and followed project test naming conventions. * chore(io): address PR feedback for container Medium migration - Added Open method to io.Medium interface to support log streaming. - Implemented Open in local.Medium and MockMedium. - Fixed extension inconsistency in GetTemplate (.yml vs .yaml). - Refactored TemplateManager to use configurable WorkingDir and HomeDir. - Reused TemplateManager instance in cmd_templates.go. - Updated LinuxKitManager to use medium.Open for log access. - Maintained and updated all tests to verify these improvements.
2026-02-04 15:33:22 +00:00
manager, err := container.NewLinuxKitManager(io.Local)
if err != nil {
return fmt.Errorf(i18n.T("i18n.fail.init", "container manager")+": %w", err)
}
opts := container.RunOptions{
Name: name,
Detach: detach,
Memory: memory,
CPUs: cpus,
SSHPort: sshPort,
}
fmt.Printf("%s %s\n", dimStyle.Render(i18n.Label("image")), image)
if name != "" {
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.vm.label.name")), name)
}
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.vm.label.hypervisor")), manager.Hypervisor().Name())
fmt.Println()
ctx := context.Background()
c, err := manager.Run(ctx, image, opts)
if err != nil {
return fmt.Errorf(i18n.T("i18n.fail.run", "container")+": %w", err)
}
if detach {
fmt.Printf("%s %s\n", successStyle.Render(i18n.Label("started")), c.ID)
fmt.Printf("%s %d\n", dimStyle.Render(i18n.T("cmd.vm.label.pid")), c.PID)
fmt.Println()
fmt.Println(i18n.T("cmd.vm.hint.view_logs", map[string]interface{}{"ID": c.ID[:8]}))
fmt.Println(i18n.T("cmd.vm.hint.stop", map[string]interface{}{"ID": c.ID[:8]}))
} else {
fmt.Printf("\n%s %s\n", dimStyle.Render(i18n.T("cmd.vm.label.container_stopped")), c.ID)
}
return nil
}
var psAll bool
// addVMPsCommand adds the 'ps' command under vm.
func addVMPsCommand(parent *cobra.Command) {
psCmd := &cobra.Command{
Use: "ps",
Short: i18n.T("cmd.vm.ps.short"),
Long: i18n.T("cmd.vm.ps.long"),
RunE: func(cmd *cobra.Command, args []string) error {
return listContainers(psAll)
},
}
psCmd.Flags().BoolVarP(&psAll, "all", "a", false, i18n.T("cmd.vm.ps.flag.all"))
parent.AddCommand(psCmd)
}
func listContainers(all bool) error {
Migrate pkg/container to io.Medium abstraction (#292) * chore(io): migrate pkg/container to Medium abstraction Migrated State, Templates, and LinuxKitManager in pkg/container to use the io.Medium abstraction for storage operations. - Introduced TemplateManager struct to handle template logic with injected medium. - Updated State struct to use injected medium for persistence. - Updated LinuxKitManager to hold and use an io.Medium instance. - Updated all internal callers in internal/cmd/vm and pkg/devops to use new APIs. - Adapted and maintained comprehensive test coverage in linuxkit_test.go. - Fixed naming collision with standard io package by aliasing it as goio. * chore(io): migrate pkg/container to Medium abstraction (v2) - Migrated State, Templates, and LinuxKitManager in pkg/container to use io.Medium. - Introduced TemplateManager struct for dependency injection. - Updated all call sites in internal/cmd/vm and pkg/devops. - Restored and adapted comprehensive test suite in linuxkit_test.go. - Fixed naming collisions and followed project test naming conventions. * chore(io): address PR feedback for container Medium migration - Added Open method to io.Medium interface to support log streaming. - Implemented Open in local.Medium and MockMedium. - Fixed extension inconsistency in GetTemplate (.yml vs .yaml). - Refactored TemplateManager to use configurable WorkingDir and HomeDir. - Reused TemplateManager instance in cmd_templates.go. - Updated LinuxKitManager to use medium.Open for log access. - Maintained and updated all tests to verify these improvements.
2026-02-04 15:33:22 +00:00
manager, err := container.NewLinuxKitManager(io.Local)
if err != nil {
return fmt.Errorf(i18n.T("i18n.fail.init", "container manager")+": %w", err)
}
ctx := context.Background()
containers, err := manager.List(ctx)
if err != nil {
return fmt.Errorf(i18n.T("i18n.fail.list", "containers")+": %w", err)
}
// Filter if not showing all
if !all {
filtered := make([]*container.Container, 0)
for _, c := range containers {
if c.Status == container.StatusRunning {
filtered = append(filtered, c)
}
}
containers = filtered
}
if len(containers) == 0 {
if all {
fmt.Println(i18n.T("cmd.vm.ps.no_containers"))
} else {
fmt.Println(i18n.T("cmd.vm.ps.no_running"))
}
return nil
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
feat: infrastructure packages and lint cleanup (#281) * ci: consolidate duplicate workflows and merge CodeQL configs Remove 17 duplicate workflow files that were split copies of the combined originals. Each family (CI, CodeQL, Coverage, PR Build, Alpha Release) had the same job duplicated across separate push/pull_request/schedule/manual trigger files. Merge codeql.yml and codescan.yml into a single codeql.yml with a language matrix covering go, javascript-typescript, python, and actions — matching the previous default setup coverage. Remaining workflows (one per family): - ci.yml (push + PR + manual) - codeql.yml (push + PR + schedule, all languages) - coverage.yml (push + PR + manual) - alpha-release.yml (push + manual) - pr-build.yml (PR + manual) - release.yml (tag push) - agent-verify.yml, auto-label.yml, auto-project.yml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add collect, config, crypt, plugin packages and fix all lint issues Add four new infrastructure packages with CLI commands: - pkg/config: layered configuration (defaults → file → env → flags) - pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums) - pkg/plugin: plugin system with GitHub-based install/update/remove - pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate) Fix all golangci-lint issues across the entire codebase (~100 errcheck, staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that `core go qa` passes with 0 issues. Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
_, _ = fmt.Fprintln(w, i18n.T("cmd.vm.ps.header"))
_, _ = fmt.Fprintln(w, "--\t----\t-----\t------\t-------\t---")
for _, c := range containers {
// Shorten image path
imageName := c.Image
if len(imageName) > 30 {
imageName = "..." + imageName[len(imageName)-27:]
}
// Format duration
duration := formatDuration(time.Since(c.StartedAt))
// Status with color
status := string(c.Status)
switch c.Status {
case container.StatusRunning:
status = successStyle.Render(status)
case container.StatusStopped:
status = dimStyle.Render(status)
case container.StatusError:
status = errorStyle.Render(status)
}
feat: infrastructure packages and lint cleanup (#281) * ci: consolidate duplicate workflows and merge CodeQL configs Remove 17 duplicate workflow files that were split copies of the combined originals. Each family (CI, CodeQL, Coverage, PR Build, Alpha Release) had the same job duplicated across separate push/pull_request/schedule/manual trigger files. Merge codeql.yml and codescan.yml into a single codeql.yml with a language matrix covering go, javascript-typescript, python, and actions — matching the previous default setup coverage. Remaining workflows (one per family): - ci.yml (push + PR + manual) - codeql.yml (push + PR + schedule, all languages) - coverage.yml (push + PR + manual) - alpha-release.yml (push + manual) - pr-build.yml (PR + manual) - release.yml (tag push) - agent-verify.yml, auto-label.yml, auto-project.yml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add collect, config, crypt, plugin packages and fix all lint issues Add four new infrastructure packages with CLI commands: - pkg/config: layered configuration (defaults → file → env → flags) - pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums) - pkg/plugin: plugin system with GitHub-based install/update/remove - pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate) Fix all golangci-lint issues across the entire codebase (~100 errcheck, staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that `core go qa` passes with 0 issues. Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%d\n",
c.ID[:8], c.Name, imageName, status, duration, c.PID)
}
feat: infrastructure packages and lint cleanup (#281) * ci: consolidate duplicate workflows and merge CodeQL configs Remove 17 duplicate workflow files that were split copies of the combined originals. Each family (CI, CodeQL, Coverage, PR Build, Alpha Release) had the same job duplicated across separate push/pull_request/schedule/manual trigger files. Merge codeql.yml and codescan.yml into a single codeql.yml with a language matrix covering go, javascript-typescript, python, and actions — matching the previous default setup coverage. Remaining workflows (one per family): - ci.yml (push + PR + manual) - codeql.yml (push + PR + schedule, all languages) - coverage.yml (push + PR + manual) - alpha-release.yml (push + manual) - pr-build.yml (PR + manual) - release.yml (tag push) - agent-verify.yml, auto-label.yml, auto-project.yml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add collect, config, crypt, plugin packages and fix all lint issues Add four new infrastructure packages with CLI commands: - pkg/config: layered configuration (defaults → file → env → flags) - pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums) - pkg/plugin: plugin system with GitHub-based install/update/remove - pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate) Fix all golangci-lint issues across the entire codebase (~100 errcheck, staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that `core go qa` passes with 0 issues. Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
_ = w.Flush()
return nil
}
func formatDuration(d time.Duration) string {
if d < time.Minute {
return fmt.Sprintf("%ds", int(d.Seconds()))
}
if d < time.Hour {
return fmt.Sprintf("%dm", int(d.Minutes()))
}
if d < 24*time.Hour {
return fmt.Sprintf("%dh", int(d.Hours()))
}
return fmt.Sprintf("%dd", int(d.Hours()/24))
}
// addVMStopCommand adds the 'stop' command under vm.
func addVMStopCommand(parent *cobra.Command) {
stopCmd := &cobra.Command{
Use: "stop <container-id>",
Short: i18n.T("cmd.vm.stop.short"),
Long: i18n.T("cmd.vm.stop.long"),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New(i18n.T("cmd.vm.error.id_required"))
}
return stopContainer(args[0])
},
}
parent.AddCommand(stopCmd)
}
func stopContainer(id string) error {
Migrate pkg/container to io.Medium abstraction (#292) * chore(io): migrate pkg/container to Medium abstraction Migrated State, Templates, and LinuxKitManager in pkg/container to use the io.Medium abstraction for storage operations. - Introduced TemplateManager struct to handle template logic with injected medium. - Updated State struct to use injected medium for persistence. - Updated LinuxKitManager to hold and use an io.Medium instance. - Updated all internal callers in internal/cmd/vm and pkg/devops to use new APIs. - Adapted and maintained comprehensive test coverage in linuxkit_test.go. - Fixed naming collision with standard io package by aliasing it as goio. * chore(io): migrate pkg/container to Medium abstraction (v2) - Migrated State, Templates, and LinuxKitManager in pkg/container to use io.Medium. - Introduced TemplateManager struct for dependency injection. - Updated all call sites in internal/cmd/vm and pkg/devops. - Restored and adapted comprehensive test suite in linuxkit_test.go. - Fixed naming collisions and followed project test naming conventions. * chore(io): address PR feedback for container Medium migration - Added Open method to io.Medium interface to support log streaming. - Implemented Open in local.Medium and MockMedium. - Fixed extension inconsistency in GetTemplate (.yml vs .yaml). - Refactored TemplateManager to use configurable WorkingDir and HomeDir. - Reused TemplateManager instance in cmd_templates.go. - Updated LinuxKitManager to use medium.Open for log access. - Maintained and updated all tests to verify these improvements.
2026-02-04 15:33:22 +00:00
manager, err := container.NewLinuxKitManager(io.Local)
if err != nil {
return fmt.Errorf(i18n.T("i18n.fail.init", "container manager")+": %w", err)
}
// Support partial ID matching
fullID, err := resolveContainerID(manager, id)
if err != nil {
return err
}
fmt.Printf("%s %s\n", dimStyle.Render(i18n.T("cmd.vm.stop.stopping")), fullID[:8])
ctx := context.Background()
if err := manager.Stop(ctx, fullID); err != nil {
return fmt.Errorf(i18n.T("i18n.fail.stop", "container")+": %w", err)
}
fmt.Printf("%s\n", successStyle.Render(i18n.T("common.status.stopped")))
return nil
}
// resolveContainerID resolves a partial ID to a full ID.
func resolveContainerID(manager *container.LinuxKitManager, partialID string) (string, error) {
ctx := context.Background()
containers, err := manager.List(ctx)
if err != nil {
return "", err
}
var matches []*container.Container
for _, c := range containers {
if strings.HasPrefix(c.ID, partialID) || strings.HasPrefix(c.Name, partialID) {
matches = append(matches, c)
}
}
switch len(matches) {
case 0:
return "", errors.New(i18n.T("cmd.vm.error.no_match", map[string]interface{}{"ID": partialID}))
case 1:
return matches[0].ID, nil
default:
return "", errors.New(i18n.T("cmd.vm.error.multiple_match", map[string]interface{}{"ID": partialID}))
}
}
var logsFollow bool
// addVMLogsCommand adds the 'logs' command under vm.
func addVMLogsCommand(parent *cobra.Command) {
logsCmd := &cobra.Command{
Use: "logs <container-id>",
Short: i18n.T("cmd.vm.logs.short"),
Long: i18n.T("cmd.vm.logs.long"),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New(i18n.T("cmd.vm.error.id_required"))
}
return viewLogs(args[0], logsFollow)
},
}
logsCmd.Flags().BoolVarP(&logsFollow, "follow", "f", false, i18n.T("common.flag.follow"))
parent.AddCommand(logsCmd)
}
func viewLogs(id string, follow bool) error {
Migrate pkg/container to io.Medium abstraction (#292) * chore(io): migrate pkg/container to Medium abstraction Migrated State, Templates, and LinuxKitManager in pkg/container to use the io.Medium abstraction for storage operations. - Introduced TemplateManager struct to handle template logic with injected medium. - Updated State struct to use injected medium for persistence. - Updated LinuxKitManager to hold and use an io.Medium instance. - Updated all internal callers in internal/cmd/vm and pkg/devops to use new APIs. - Adapted and maintained comprehensive test coverage in linuxkit_test.go. - Fixed naming collision with standard io package by aliasing it as goio. * chore(io): migrate pkg/container to Medium abstraction (v2) - Migrated State, Templates, and LinuxKitManager in pkg/container to use io.Medium. - Introduced TemplateManager struct for dependency injection. - Updated all call sites in internal/cmd/vm and pkg/devops. - Restored and adapted comprehensive test suite in linuxkit_test.go. - Fixed naming collisions and followed project test naming conventions. * chore(io): address PR feedback for container Medium migration - Added Open method to io.Medium interface to support log streaming. - Implemented Open in local.Medium and MockMedium. - Fixed extension inconsistency in GetTemplate (.yml vs .yaml). - Refactored TemplateManager to use configurable WorkingDir and HomeDir. - Reused TemplateManager instance in cmd_templates.go. - Updated LinuxKitManager to use medium.Open for log access. - Maintained and updated all tests to verify these improvements.
2026-02-04 15:33:22 +00:00
manager, err := container.NewLinuxKitManager(io.Local)
if err != nil {
return fmt.Errorf(i18n.T("i18n.fail.init", "container manager")+": %w", err)
}
fullID, err := resolveContainerID(manager, id)
if err != nil {
return err
}
ctx := context.Background()
reader, err := manager.Logs(ctx, fullID, follow)
if err != nil {
return fmt.Errorf(i18n.T("i18n.fail.get", "logs")+": %w", err)
}
feat: infrastructure packages and lint cleanup (#281) * ci: consolidate duplicate workflows and merge CodeQL configs Remove 17 duplicate workflow files that were split copies of the combined originals. Each family (CI, CodeQL, Coverage, PR Build, Alpha Release) had the same job duplicated across separate push/pull_request/schedule/manual trigger files. Merge codeql.yml and codescan.yml into a single codeql.yml with a language matrix covering go, javascript-typescript, python, and actions — matching the previous default setup coverage. Remaining workflows (one per family): - ci.yml (push + PR + manual) - codeql.yml (push + PR + schedule, all languages) - coverage.yml (push + PR + manual) - alpha-release.yml (push + manual) - pr-build.yml (PR + manual) - release.yml (tag push) - agent-verify.yml, auto-label.yml, auto-project.yml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add collect, config, crypt, plugin packages and fix all lint issues Add four new infrastructure packages with CLI commands: - pkg/config: layered configuration (defaults → file → env → flags) - pkg/crypt: crypto primitives (Argon2id, AES-GCM, ChaCha20, HMAC, checksums) - pkg/plugin: plugin system with GitHub-based install/update/remove - pkg/collect: collection subsystem (GitHub, BitcoinTalk, market, papers, excavate) Fix all golangci-lint issues across the entire codebase (~100 errcheck, staticcheck SA1012/SA1019/ST1005, unused, ineffassign fixes) so that `core go qa` passes with 0 issues. Closes #167, #168, #170, #250, #251, #252, #253, #254, #255, #256 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:34:43 +00:00
defer func() { _ = reader.Close() }()
Migrate pkg/container to io.Medium abstraction (#292) * chore(io): migrate pkg/container to Medium abstraction Migrated State, Templates, and LinuxKitManager in pkg/container to use the io.Medium abstraction for storage operations. - Introduced TemplateManager struct to handle template logic with injected medium. - Updated State struct to use injected medium for persistence. - Updated LinuxKitManager to hold and use an io.Medium instance. - Updated all internal callers in internal/cmd/vm and pkg/devops to use new APIs. - Adapted and maintained comprehensive test coverage in linuxkit_test.go. - Fixed naming collision with standard io package by aliasing it as goio. * chore(io): migrate pkg/container to Medium abstraction (v2) - Migrated State, Templates, and LinuxKitManager in pkg/container to use io.Medium. - Introduced TemplateManager struct for dependency injection. - Updated all call sites in internal/cmd/vm and pkg/devops. - Restored and adapted comprehensive test suite in linuxkit_test.go. - Fixed naming collisions and followed project test naming conventions. * chore(io): address PR feedback for container Medium migration - Added Open method to io.Medium interface to support log streaming. - Implemented Open in local.Medium and MockMedium. - Fixed extension inconsistency in GetTemplate (.yml vs .yaml). - Refactored TemplateManager to use configurable WorkingDir and HomeDir. - Reused TemplateManager instance in cmd_templates.go. - Updated LinuxKitManager to use medium.Open for log access. - Maintained and updated all tests to verify these improvements.
2026-02-04 15:33:22 +00:00
_, err = goio.Copy(os.Stdout, reader)
return err
}
// addVMExecCommand adds the 'exec' command under vm.
func addVMExecCommand(parent *cobra.Command) {
execCmd := &cobra.Command{
Use: "exec <container-id> <command> [args...]",
Short: i18n.T("cmd.vm.exec.short"),
Long: i18n.T("cmd.vm.exec.long"),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
return errors.New(i18n.T("cmd.vm.error.id_and_cmd_required"))
}
return execInContainer(args[0], args[1:])
},
}
parent.AddCommand(execCmd)
}
func execInContainer(id string, cmd []string) error {
Migrate pkg/container to io.Medium abstraction (#292) * chore(io): migrate pkg/container to Medium abstraction Migrated State, Templates, and LinuxKitManager in pkg/container to use the io.Medium abstraction for storage operations. - Introduced TemplateManager struct to handle template logic with injected medium. - Updated State struct to use injected medium for persistence. - Updated LinuxKitManager to hold and use an io.Medium instance. - Updated all internal callers in internal/cmd/vm and pkg/devops to use new APIs. - Adapted and maintained comprehensive test coverage in linuxkit_test.go. - Fixed naming collision with standard io package by aliasing it as goio. * chore(io): migrate pkg/container to Medium abstraction (v2) - Migrated State, Templates, and LinuxKitManager in pkg/container to use io.Medium. - Introduced TemplateManager struct for dependency injection. - Updated all call sites in internal/cmd/vm and pkg/devops. - Restored and adapted comprehensive test suite in linuxkit_test.go. - Fixed naming collisions and followed project test naming conventions. * chore(io): address PR feedback for container Medium migration - Added Open method to io.Medium interface to support log streaming. - Implemented Open in local.Medium and MockMedium. - Fixed extension inconsistency in GetTemplate (.yml vs .yaml). - Refactored TemplateManager to use configurable WorkingDir and HomeDir. - Reused TemplateManager instance in cmd_templates.go. - Updated LinuxKitManager to use medium.Open for log access. - Maintained and updated all tests to verify these improvements.
2026-02-04 15:33:22 +00:00
manager, err := container.NewLinuxKitManager(io.Local)
if err != nil {
return fmt.Errorf(i18n.T("i18n.fail.init", "container manager")+": %w", err)
}
fullID, err := resolveContainerID(manager, id)
if err != nil {
return err
}
ctx := context.Background()
return manager.Exec(ctx, fullID, cmd)
}