v2podman run
add the ability to run a container Signed-off-by: Brent Baude <bbaude@redhat.com>
This commit is contained in:
		
							parent
							
								
									843fa25890
								
							
						
					
					
						commit
						1bfb96b540
					
				|  | @ -29,7 +29,6 @@ func getDefaultContainerConfig() *config.Config { | |||
| } | ||||
| 
 | ||||
| func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { | ||||
| 	//createFlags := c.Flags()
 | ||||
| 	createFlags := pflag.FlagSet{} | ||||
| 	createFlags.StringSliceVar( | ||||
| 		&cf.Annotation, | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  | @ -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 | ||||
| } | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  |  | |||
|  | @ -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") | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue