mirror of https://github.com/containers/podman.git
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 {
|
func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
||||||
//createFlags := c.Flags()
|
|
||||||
createFlags := pflag.FlagSet{}
|
createFlags := pflag.FlagSet{}
|
||||||
createFlags.StringSliceVar(
|
createFlags.StringSliceVar(
|
||||||
&cf.Annotation,
|
&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"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WaitOptions struct {
|
type WaitOptions struct {
|
||||||
|
@ -224,3 +225,23 @@ type ContainerListOptions struct {
|
||||||
Sync bool
|
Sync bool
|
||||||
Watch uint
|
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)
|
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
|
||||||
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
|
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
|
||||||
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, 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)
|
ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
|
||||||
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
|
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
|
||||||
ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, 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) {
|
func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
|
||||||
return ps.GetContainerLists(ic.Libpod, options)
|
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) {
|
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)
|
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