summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrent Baude <bbaude@redhat.com>2020-04-05 15:52:59 -0500
committerBrent Baude <bbaude@redhat.com>2020-04-06 15:23:04 -0500
commit1bfb96b54010b048e9bea155a75d150f4bf8853c (patch)
treeb4eedb293bef91f2416164de76d93b1e37dd7481
parent843fa25890199c04b8419833d39bdedf4ead391c (diff)
downloadpodman-1bfb96b54010b048e9bea155a75d150f4bf8853c.tar.gz
podman-1bfb96b54010b048e9bea155a75d150f4bf8853c.tar.bz2
podman-1bfb96b54010b048e9bea155a75d150f4bf8853c.zip
v2podman run
add the ability to run a container Signed-off-by: Brent Baude <bbaude@redhat.com>
-rw-r--r--cmd/podmanV2/common/create.go1
-rw-r--r--cmd/podmanV2/containers/run.go125
-rw-r--r--pkg/domain/entities/containers.go21
-rw-r--r--pkg/domain/entities/engine_container.go1
-rw-r--r--pkg/domain/infra/abi/containers.go74
-rw-r--r--pkg/domain/infra/tunnel/containers.go4
6 files changed, 225 insertions, 1 deletions
diff --git a/cmd/podmanV2/common/create.go b/cmd/podmanV2/common/create.go
index f81d021c8..e2eb8cbda 100644
--- a/cmd/podmanV2/common/create.go
+++ b/cmd/podmanV2/common/create.go
@@ -29,7 +29,6 @@ func getDefaultContainerConfig() *config.Config {
}
func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
- //createFlags := c.Flags()
createFlags := pflag.FlagSet{}
createFlags.StringSliceVar(
&cf.Annotation,
diff --git a/cmd/podmanV2/containers/run.go b/cmd/podmanV2/containers/run.go
new file mode 100644
index 000000000..bd90aee2f
--- /dev/null
+++ b/cmd/podmanV2/containers/run.go
@@ -0,0 +1,125 @@
+package containers
+
+import (
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/sirupsen/logrus"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+
+ "github.com/containers/libpod/cmd/podmanV2/common"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/specgen"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ runDescription = "Runs a command in a new container from the given image"
+ runCommand = &cobra.Command{
+ Use: "run [flags] IMAGE [COMMAND [ARG...]]",
+ Short: "Run a command in a new container",
+ Long: runDescription,
+ PreRunE: preRunE,
+ RunE: run,
+ Example: `podman run imageID ls -alF /etc
+ podman run --network=host imageID dnf -y install java
+ podman run --volume /var/hostdir:/var/ctrdir -i -t fedora /bin/bash`,
+ }
+)
+
+var (
+ runOpts = entities.ContainerRunOptions{
+ OutputStream: os.Stdout,
+ InputStream: os.Stdin,
+ ErrorStream: os.Stderr,
+ }
+ runRmi bool
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: runCommand,
+ })
+ flags := runCommand.Flags()
+ flags.AddFlagSet(common.GetCreateFlags(&cliVals))
+ flags.AddFlagSet(common.GetNetFlags())
+ flags.SetNormalizeFunc(common.AliasFlags)
+ flags.BoolVar(&runOpts.SigProxy, "sig-proxy", true, "Proxy received signals to the process")
+ flags.BoolVar(&runRmi, "rmi", false, "Remove container image unless used by other containers")
+ if registry.IsRemote() {
+ _ = flags.MarkHidden("authfile")
+ }
+}
+
+func run(cmd *cobra.Command, args []string) error {
+ var (
+ err error
+ )
+ cliVals.Net, err = common.NetFlagsToNetOptions(cmd)
+ if err != nil {
+ return err
+ }
+ if af := cliVals.Authfile; len(af) > 0 {
+ if _, err := os.Stat(af); err != nil {
+ return errors.Wrapf(err, "error checking authfile path %s", af)
+ }
+ }
+ runOpts.Rm = cliVals.Rm
+ if err := createInit(cmd); err != nil {
+ return err
+ }
+
+ // If -i is not set, clear stdin
+ if !cliVals.Interactive {
+ runOpts.InputStream = nil
+ }
+
+ // If attach is set, clear stdin/stdout/stderr and only attach requested
+ if cmd.Flag("attach").Changed {
+ runOpts.OutputStream = nil
+ runOpts.ErrorStream = nil
+ if !cliVals.Interactive {
+ runOpts.InputStream = nil
+ }
+
+ for _, stream := range cliVals.Attach {
+ switch strings.ToLower(stream) {
+ case "stdout":
+ runOpts.OutputStream = os.Stdout
+ case "stderr":
+ runOpts.ErrorStream = os.Stderr
+ case "stdin":
+ runOpts.InputStream = os.Stdin
+ default:
+ return errors.Wrapf(define.ErrInvalidArg, "invalid stream %q for --attach - must be one of stdin, stdout, or stderr", stream)
+ }
+ }
+ }
+ runOpts.Detach = cliVals.Detach
+ runOpts.DetachKeys = cliVals.DetachKeys
+ s := specgen.NewSpecGenerator(args[0])
+ if err := common.FillOutSpecGen(s, &cliVals, args); err != nil {
+ return err
+ }
+ runOpts.Spec = s
+ report, err := registry.ContainerEngine().ContainerRun(registry.GetContext(), runOpts)
+ if err != nil {
+ return err
+ }
+ if cliVals.Detach {
+ fmt.Println(report.Id)
+ }
+ registry.SetExitCode(report.ExitCode)
+ if runRmi {
+ _, err := registry.ImageEngine().Delete(registry.GetContext(), []string{report.Id}, entities.ImageDeleteOptions{})
+ if err != nil {
+ logrus.Errorf("%s", errors.Wrapf(err, "failed removing image"))
+ }
+ }
+ return nil
+}
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 4f94e009f..5d302058b 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -6,6 +6,7 @@ import (
"time"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/specgen"
)
type WaitOptions struct {
@@ -224,3 +225,23 @@ type ContainerListOptions struct {
Sync bool
Watch uint
}
+
+// ContainerRunOptions describes the options needed
+// to run a container from the CLI
+type ContainerRunOptions struct {
+ Detach bool
+ DetachKeys string
+ ErrorStream *os.File
+ InputStream *os.File
+ OutputStream *os.File
+ Rm bool
+ SigProxy bool
+ Spec *specgen.SpecGenerator
+}
+
+// ContainerRunReport describes the results of running
+//a container
+type ContainerRunReport struct {
+ ExitCode int
+ Id string
+}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 36c20c38d..576ce1658 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -23,6 +23,7 @@ type ContainerEngine interface {
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)
+ ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, 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 54f91a189..828ee56f0 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -622,3 +622,77 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
return ps.GetContainerLists(ic.Libpod, options)
}
+
+func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
+ var (
+ joinPod bool
+ )
+ if err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec); err != nil {
+ return nil, err
+ }
+ ctr, err := generate.MakeContainer(ic.Libpod, opts.Spec)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(ctr.PodID()) > 0 {
+ joinPod = true
+ }
+ report := entities.ContainerRunReport{Id: ctr.ID()}
+
+ if logrus.GetLevel() == logrus.DebugLevel {
+ cgroupPath, err := ctr.CGroupPath()
+ if err == nil {
+ logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath)
+ }
+ }
+ 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 {
+ // This means the command did not exist
+ report.ExitCode = define.ExitCode(err)
+ return &report, err
+ }
+
+ return &report, nil
+ }
+
+ // 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 {
+ // We've manually detached from the container
+ // Do not perform cleanup, or wait for container exit code
+ // Just exit immediately
+ if errors.Cause(err) == define.ErrDetach {
+ report.ExitCode = 0
+ return &report, nil
+ }
+ if opts.Rm {
+ if deleteError := ic.Libpod.RemoveContainer(ctx, ctr, true, false); deleteError != nil {
+ logrus.Debugf("unable to remove container %s after failing to start and attach to it", ctr.ID())
+ }
+ }
+ if errors.Cause(err) == define.ErrWillDeadlock {
+ logrus.Debugf("Deadlock error on %q: %v", ctr.ID(), err)
+ report.ExitCode = define.ExitCode(err)
+ return &report, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
+ }
+ report.ExitCode = define.ExitCode(err)
+ return &report, err
+ }
+
+ 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)
+ report.ExitCode = define.ExecErrorCodeNotFound
+ } else {
+ report.ExitCode = event.ContainerExitCode
+ }
+ }
+ } else {
+ report.ExitCode = int(ecode)
+ }
+ return &report, nil
+}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index b6807d5b6..e96200c5b 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -320,3 +320,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
return containers.List(ic.ClientCxt, options.Filters, &options.All, &options.Last, &options.Pod, &options.Size, &options.Sync)
}
+
+func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
+ return nil, errors.New("not implemented")
+}