diff options
author | Brent Baude <bbaude@redhat.com> | 2020-04-04 08:35:23 -0500 |
---|---|---|
committer | Brent Baude <bbaude@redhat.com> | 2020-04-06 09:26:11 -0500 |
commit | 5e0b4497365f9b3c2d795e5771a3abec7cd24cbb (patch) | |
tree | 169fd388ae4b8576c7a4e451276447a88343e79c | |
parent | ba64186750a23675f42744ca4203b524e7b1b378 (diff) | |
download | podman-5e0b4497365f9b3c2d795e5771a3abec7cd24cbb.tar.gz podman-5e0b4497365f9b3c2d795e5771a3abec7cd24cbb.tar.bz2 podman-5e0b4497365f9b3c2d795e5771a3abec7cd24cbb.zip |
podmanv2 start
add the ability to start containers
Signed-off-by: Brent Baude <bbaude@redhat.com>
-rw-r--r-- | cmd/podmanV2/containers/start.go | 87 | ||||
-rw-r--r-- | pkg/domain/entities/containers.go | 21 | ||||
-rw-r--r-- | pkg/domain/entities/engine_container.go | 1 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 108 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 4 |
5 files changed, 221 insertions, 0 deletions
diff --git a/cmd/podmanV2/containers/start.go b/cmd/podmanV2/containers/start.go new file mode 100644 index 000000000..0ae2f6d50 --- /dev/null +++ b/cmd/podmanV2/containers/start.go @@ -0,0 +1,87 @@ +package containers + +import ( + "fmt" + "os" + + "github.com/containers/libpod/cmd/podmanV2/common" + "github.com/containers/libpod/cmd/podmanV2/registry" + "github.com/containers/libpod/cmd/podmanV2/utils" + "github.com/containers/libpod/libpod/define" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + startDescription = `Starts one or more containers. The container name or ID can be used.` + startCommand = &cobra.Command{ + Use: "start [flags] CONTAINER [CONTAINER...]", + Short: "Start one or more containers", + Long: startDescription, + RunE: start, + PreRunE: preRunE, + Args: cobra.MinimumNArgs(1), + Example: `podman start --latest + podman start 860a4b231279 5421ab43b45 + podman start --interactive --attach imageID`, + } +) + +var ( + startOptions entities.ContainerStartOptions +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: startCommand, + }) + flags := startCommand.Flags() + flags.BoolVarP(&startOptions.Attach, "attach", "a", false, "Attach container's STDOUT and STDERR") + flags.StringVar(&startOptions.DetachKeys, "detach-keys", common.GetDefaultDetachKeys(), "Select the key sequence for detaching a container. Format is a single character `[a-Z]` or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-z`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`") + flags.BoolVarP(&startOptions.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached") + flags.BoolVarP(&startOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + flags.BoolVar(&startOptions.SigProxy, "sig-proxy", false, "Proxy received signals to the process (default true if attaching, false otherwise)") + if registry.IsRemote() { + _ = flags.MarkHidden("latest") + _ = flags.MarkHidden("sig-proxy") + } + +} + +func start(cmd *cobra.Command, args []string) error { + var errs utils.OutputErrors + if len(args) > 1 && startOptions.Attach { + return errors.Errorf("you cannot start and attach multiple containers at once") + } + + sigProxy := startOptions.SigProxy || startOptions.Attach + if cmd.Flag("sig-proxy").Changed { + sigProxy = startOptions.SigProxy + } + + if sigProxy && !startOptions.Attach { + return errors.Wrapf(define.ErrInvalidArg, "you cannot use sig-proxy without --attach") + } + if startOptions.Attach { + startOptions.Stdin = os.Stdin + startOptions.Stderr = os.Stderr + startOptions.Stdout = os.Stdout + } + + responses, err := registry.ContainerEngine().ContainerStart(registry.GetContext(), args, startOptions) + if err != nil { + return err + } + + for _, r := range responses { + if r.Err == nil { + fmt.Println(r.Id) + } else { + errs = append(errs, r.Err) + } + } + // TODO need to understand an implement exitcodes + return errs.PrintErrors() +} diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index cf907eb1b..6b4bb9ba2 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -186,3 +186,24 @@ type ExecOptions struct { User string WorkDir string } + +// ContainerStartOptions describes the val from the +// CLI needed to start a container +type ContainerStartOptions struct { + Attach bool + DetachKeys string + Interactive bool + Latest bool + SigProxy bool + Stdout *os.File + Stderr *os.File + Stdin *os.File +} + +// ContainerStartReport describes the response from starting +// containers from the cli +type ContainerStartReport struct { + Id string + Err error + ExitCode int +} diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 9bf3d51de..264780771 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -21,6 +21,7 @@ type ContainerEngine interface { ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error) ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error) + ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error) ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error) ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error) ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index b93e7665a..929c3f335 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -12,6 +12,7 @@ import ( "github.com/containers/image/v5/manifest" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" + "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/checkpoint" "github.com/containers/libpod/pkg/domain/entities" @@ -509,3 +510,110 @@ func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, o ec, err = terminal.ExecAttachCtr(ctx, ctr, options.Tty, options.Privileged, options.Envs, options.Cmd, options.User, options.WorkDir, &options.Streams, options.PreserveFDs, options.DetachKeys) return define.TranslateExecErrorToExitCode(ec, err), err } + +func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) { + var reports []*entities.ContainerStartReport + var exitCode = define.ExecErrorCodeGeneric + ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) + if err != nil { + return nil, err + } + // There can only be one container if attach was used + for _, ctr := range ctrs { + ctrState, err := ctr.State() + if err != nil { + return nil, err + } + ctrRunning := ctrState == define.ContainerStateRunning + + if options.Attach { + err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning, ctr.PodID() != "") + if errors.Cause(err) == define.ErrDetach { + // User manually detached + // Exit cleanly immediately + reports = append(reports, &entities.ContainerStartReport{ + Id: ctr.ID(), + Err: nil, + ExitCode: 0, + }) + return reports, nil + } + + if errors.Cause(err) == define.ErrWillDeadlock { + logrus.Debugf("Deadlock error: %v", err) + reports = append(reports, &entities.ContainerStartReport{ + Id: ctr.ID(), + Err: err, + ExitCode: define.ExitCode(err), + }) + return reports, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID()) + } + + if ctrRunning { + reports = append(reports, &entities.ContainerStartReport{ + Id: ctr.ID(), + Err: nil, + ExitCode: 0, + }) + return reports, err + } + + if err != nil { + reports = append(reports, &entities.ContainerStartReport{ + Id: ctr.ID(), + Err: err, + ExitCode: exitCode, + }) + return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID()) + } + + if ecode, err := ctr.Wait(); err != nil { + if errors.Cause(err) == define.ErrNoSuchCtr { + // Check events + event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited) + if err != nil { + logrus.Errorf("Cannot get exit code: %v", err) + exitCode = define.ExecErrorCodeNotFound + } else { + exitCode = event.ContainerExitCode + } + } + } else { + exitCode = int(ecode) + } + reports = append(reports, &entities.ContainerStartReport{ + Id: ctr.ID(), + Err: err, + ExitCode: exitCode, + }) + return reports, nil + } // end attach + + // Start the container if it's not running already. + if !ctrRunning { + // Handle non-attach start + // If the container is in a pod, also set to recursively start dependencies + report := &entities.ContainerStartReport{ + Id: ctr.ID(), + ExitCode: 125, + } + if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil { + //if lastError != nil { + // fmt.Fprintln(os.Stderr, lastError) + //} + report.Err = err + if errors.Cause(err) == define.ErrWillDeadlock { + report.Err = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks") + reports = append(reports, report) + continue + } + report.Err = errors.Wrapf(err, "unable to start container %q", ctr.ID()) + reports = append(reports, report) + continue + } + report.ExitCode = 0 + reports = append(reports, report) + } + } + return reports, nil +} diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 1e71cba2c..4101068ba 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -313,3 +313,7 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string, func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions) (int, error) { return 125, errors.New("not implemented") } + +func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) { + return nil, errors.New("not implemented") +} |