spiegel_podman/cmd/podman/containers/run.go
cdoern d28e85741f InfraContainer Rework
InfraContainer should go through the same creation process as regular containers. This change was from the cmd level
down, involving new container CLI opts and specgen creating functions. What now happens is that both container and pod
cli options are populated in cmd and used to create a podSpecgen and a containerSpecgen. The process then goes as follows

FillOutSpecGen (infra) -> MapSpec (podOpts -> infraOpts) -> PodCreate -> MakePod -> createPodOptions -> NewPod -> CompleteSpec (infra) -> MakeContainer -> NewContainer -> newContainer -> AddInfra (to pod state)

Signed-off-by: cdoern <cdoern@redhat.com>
2021-08-26 16:05:16 -04:00

217 lines
6.5 KiB
Go

package containers
import (
"fmt"
"os"
"strings"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
)
var (
runDescription = "Runs a command in a new container from the given image"
runCommand = &cobra.Command{
Args: cobra.MinimumNArgs(1),
Use: "run [options] IMAGE [COMMAND [ARG...]]",
Short: "Run a command in a new container",
Long: runDescription,
RunE: run,
ValidArgsFunction: common.AutocompleteCreateRun,
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`,
}
containerRunCommand = &cobra.Command{
Args: cobra.MinimumNArgs(1),
Use: runCommand.Use,
Short: runCommand.Short,
Long: runCommand.Long,
RunE: runCommand.RunE,
ValidArgsFunction: runCommand.ValidArgsFunction,
Example: `podman container run imageID ls -alF /etc
podman container run --network=host imageID dnf -y install java
podman container 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 runFlags(cmd *cobra.Command) {
flags := cmd.Flags()
flags.SetInterspersed(false)
common.DefineCreateFlags(cmd, &cliVals, false)
common.DefineNetFlags(cmd)
flags.SetNormalizeFunc(utils.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")
preserveFdsFlagName := "preserve-fds"
flags.UintVar(&runOpts.PreserveFDs, "preserve-fds", 0, "Pass a number of additional file descriptors into the container")
_ = cmd.RegisterFlagCompletionFunc(preserveFdsFlagName, completion.AutocompleteNone)
flags.BoolVarP(&runOpts.Detach, "detach", "d", false, "Run container in background and print container ID")
detachKeysFlagName := "detach-keys"
flags.StringVar(&runOpts.DetachKeys, detachKeysFlagName, containerConfig.DetachKeys(), "Override 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-cf`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`")
_ = cmd.RegisterFlagCompletionFunc(detachKeysFlagName, common.AutocompleteDetachKeys)
gpuFlagName := "gpus"
flags.String(gpuFlagName, "", "This is a Docker specific option and is a NOOP")
_ = cmd.RegisterFlagCompletionFunc(gpuFlagName, completion.AutocompleteNone)
_ = flags.MarkHidden("gpus")
if registry.IsRemote() {
_ = flags.MarkHidden("preserve-fds")
_ = flags.MarkHidden("conmon-pidfile")
_ = flags.MarkHidden("pidfile")
}
}
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: runCommand,
})
runFlags(runCommand)
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: containerRunCommand,
Parent: containerCmd,
})
runFlags(containerRunCommand)
}
func run(cmd *cobra.Command, args []string) error {
var err error
// TODO: Breaking change should be made fatal in next major Release
if cliVals.TTY && cliVals.Interactive && !terminal.IsTerminal(int(os.Stdin.Fd())) {
logrus.Warnf("The input device is not a TTY. The --tty and --interactive flags might not work properly")
}
if af := cliVals.Authfile; len(af) > 0 {
if _, err := os.Stat(af); err != nil {
return err
}
}
flags := cmd.Flags()
cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags, cliVals.Pod == "" && cliVals.PodIDFile == "")
if err != nil {
return err
}
runOpts.CIDFile = cliVals.CIDFile
runOpts.Rm = cliVals.Rm
if cliVals, err = CreateInit(cmd, cliVals, false); err != nil {
return err
}
for fd := 3; fd < int(3+runOpts.PreserveFDs); fd++ {
if !rootless.IsFdInherited(fd) {
return errors.Errorf("file descriptor %d is not available - the preserve-fds option requires that file descriptors must be passed", fd)
}
}
imageName := args[0]
rawImageName := ""
if !cliVals.RootFS {
rawImageName = args[0]
name, err := PullImage(args[0], cliVals)
if err != nil {
return err
}
imageName = name
}
if cliVals.Replace {
if err := replaceContainer(cliVals.Name); 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)
}
}
}
cliVals.PreserveFDs = runOpts.PreserveFDs
s := specgen.NewSpecGenerator(imageName, cliVals.RootFS)
if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil {
return err
}
s.RawImageName = rawImageName
runOpts.Spec = s
if _, err := createPodIfNecessary(s, cliVals.Net); err != nil {
return err
}
report, err := registry.ContainerEngine().ContainerRun(registry.GetContext(), runOpts)
// report.ExitCode is set by ContainerRun even it it returns an error
if report != nil {
registry.SetExitCode(report.ExitCode)
}
if err != nil {
return err
}
if runOpts.Detach {
fmt.Println(report.Id)
return nil
}
if runRmi {
_, rmErrors := registry.ImageEngine().Remove(registry.GetContext(), []string{imageName}, entities.ImageRemoveOptions{})
if len(rmErrors) > 0 {
logrus.Errorf("%s", errorhandling.JoinErrors(rmErrors))
}
}
if cmd.Flag("gpus").Changed {
logrus.Info("--gpus is a Docker specific option and is a NOOP")
}
return nil
}