From 6acd265306370ab5cfeaf2843bd359fe13216d92 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Thu, 18 Mar 2021 12:45:09 -0400 Subject: Add --requires flag to podman run/create Podman has, for a long time, had an internal concept of dependency management, used mainly to ensure that pod infra containers are started before any other container in the pod. We also have the ability to recursively start these dependencies, which we use to ensure that `podman start` on a container in a pod will not fail because the infra container is stopped. We have not, however, exposed these via the command line until now. Add a `--requires` flag to `podman run` and `podman create` to allow users to manually specify dependency containers. These containers must be running before the container will start. Also, make recursive starting with `podman start` default so we can start these containers and their dependencies easily. Fixes #9250 Signed-off-by: Matthew Heon --- pkg/api/handlers/compat/containers_start.go | 2 +- pkg/bindings/containers/types.go | 1 + pkg/bindings/containers/types_start_options.go | 16 ++++++++++++++++ pkg/domain/infra/abi/containers.go | 14 +++++--------- pkg/domain/infra/abi/terminal/terminal_linux.go | 4 ++-- pkg/domain/infra/tunnel/containers.go | 2 +- pkg/specgen/generate/container_create.go | 11 +++++++++++ pkg/specgen/specgen.go | 7 +++++++ 8 files changed, 44 insertions(+), 13 deletions(-) (limited to 'pkg') diff --git a/pkg/api/handlers/compat/containers_start.go b/pkg/api/handlers/compat/containers_start.go index 391aa752d..f1ed1b2b8 100644 --- a/pkg/api/handlers/compat/containers_start.go +++ b/pkg/api/handlers/compat/containers_start.go @@ -42,7 +42,7 @@ func StartContainer(w http.ResponseWriter, r *http.Request) { utils.WriteResponse(w, http.StatusNotModified, nil) return } - if err := con.Start(r.Context(), len(con.PodID()) > 0); err != nil { + if err := con.Start(r.Context(), true); err != nil { utils.InternalServerError(w, err) return } diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go index f63e35bf1..0d22c32f8 100644 --- a/pkg/bindings/containers/types.go +++ b/pkg/bindings/containers/types.go @@ -154,6 +154,7 @@ type RestartOptions struct { // StartOptions are optional options for starting containers type StartOptions struct { DetachKeys *string + Recursive *bool } //go:generate go run ../generator/generator.go StatsOptions diff --git a/pkg/bindings/containers/types_start_options.go b/pkg/bindings/containers/types_start_options.go index f8ba29623..d419c755c 100644 --- a/pkg/bindings/containers/types_start_options.go +++ b/pkg/bindings/containers/types_start_options.go @@ -35,3 +35,19 @@ func (o *StartOptions) GetDetachKeys() string { } return *o.DetachKeys } + +// WithRecursive +func (o *StartOptions) WithRecursive(value bool) *StartOptions { + v := &value + o.Recursive = v + return o +} + +// GetRecursive +func (o *StartOptions) GetRecursive() bool { + var recursive bool + if o.Recursive == nil { + return recursive + } + return *o.Recursive +} diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 637531ee9..3fe9ef637 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -585,7 +585,7 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, } // If the container is in a pod, also set to recursively start dependencies - err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false, ctr.PodID() != "") + err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false) if err != nil && errors.Cause(err) != define.ErrDetach { return errors.Wrapf(err, "error attaching to container %s", ctr.ID()) } @@ -708,7 +708,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri 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() != "") + err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning) if errors.Cause(err) == define.ErrDetach { // User manually detached // Exit cleanly immediately @@ -784,7 +784,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri RawInput: rawInput, ExitCode: 125, } - if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil { + if err := ctr.Start(ctx, true); err != nil { // if lastError != nil { // fmt.Fprintln(os.Stderr, lastError) // } @@ -845,10 +845,6 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } } - var joinPod bool - if len(ctr.PodID()) > 0 { - joinPod = true - } report := entities.ContainerRunReport{Id: ctr.ID()} if logrus.GetLevel() == logrus.DebugLevel { @@ -859,7 +855,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } if opts.Detach { // if the container was created as part of a pod, also start its dependencies, if any. - if err := ctr.Start(ctx, joinPod); err != nil { + if err := ctr.Start(ctx, true); err != nil { // This means the command did not exist report.ExitCode = define.ExitCode(err) return &report, err @@ -869,7 +865,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } // if the container was created as part of a pod, also start its dependencies, if any. - if err := terminal.StartAttachCtr(ctx, ctr, opts.OutputStream, opts.ErrorStream, opts.InputStream, opts.DetachKeys, opts.SigProxy, true, joinPod); err != nil { + if err := terminal.StartAttachCtr(ctx, ctr, opts.OutputStream, opts.ErrorStream, opts.InputStream, opts.DetachKeys, opts.SigProxy, true); err != nil { // We've manually detached from the container // Do not perform cleanup, or wait for container exit code // Just exit immediately diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_linux.go index 7a0c2907c..ab71f8f6f 100644 --- a/pkg/domain/infra/abi/terminal/terminal_linux.go +++ b/pkg/domain/infra/abi/terminal/terminal_linux.go @@ -39,7 +39,7 @@ func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, execConfig *libpo // StartAttachCtr starts and (if required) attaches to a container // if you change the signature of this function from os.File to io.Writer, it will trigger a downstream // error. we may need to just lint disable this one. -func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool, recursive bool) error { //nolint-interfacer +func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool) error { //nolint-interfacer resize := make(chan define.TerminalSize) haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) @@ -88,7 +88,7 @@ func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, return ctr.Attach(streams, detachKeys, resize) } - attachChan, err := ctr.StartAndAttach(ctx, streams, detachKeys, resize, recursive) + attachChan, err := ctr.StartAndAttach(ctx, streams, detachKeys, resize, true) if err != nil { return err } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index a0f65f11f..4545d266b 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -629,7 +629,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta if opts.Detach { // Detach and return early - err := containers.Start(ic.ClientCtx, con.ID, nil) + err := containers.Start(ic.ClientCtx, con.ID, new(containers.StartOptions).WithRecursive(true)) if err != nil { report.ExitCode = define.ExitCode(err) } diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 1d724ffb0..ef9975021 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -364,6 +364,17 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. if len(s.Secrets) != 0 { options = append(options, libpod.WithSecrets(s.Secrets)) } + if len(s.DependencyContainers) > 0 { + deps := make([]*libpod.Container, 0, len(s.DependencyContainers)) + for _, ctr := range s.DependencyContainers { + depCtr, err := rt.LookupContainer(ctr) + if err != nil { + return nil, errors.Wrapf(err, "%q is not a valid container, cannot be used as a dependency", ctr) + } + deps = append(deps, depCtr) + } + options = append(options, libpod.WithDependencyCtrs(deps)) + } return options, nil } diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index c10dc5ef5..28111f96d 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -160,10 +160,17 @@ type ContainerBasicConfig struct { // to 0, 1, 2) that will be passed to the executed process. The total FDs // passed will be 3 + PreserveFDs. // set tags as `json:"-"` for not supported remote + // Optional. PreserveFDs uint `json:"-"` // Timezone is the timezone inside the container. // Local means it has the same timezone as the host machine + // Optional. Timezone string `json:"timezone,omitempty"` + // DependencyContainers is an array of containers this container + // depends on. Dependency containers must be started before this + // container. Dependencies can be specified by name or full/partial ID. + // Optional. + DependencyContainers []string `json:"dependencyContainers,omitempty"` } // ContainerStorageConfig contains information on the storage configuration of a -- cgit v1.2.3-54-g00ecf