summaryrefslogtreecommitdiff
path: root/pkg/adapter/containers.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/adapter/containers.go')
-rw-r--r--pkg/adapter/containers.go1393
1 files changed, 0 insertions, 1393 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
deleted file mode 100644
index c395ffc7f..000000000
--- a/pkg/adapter/containers.go
+++ /dev/null
@@ -1,1393 +0,0 @@
-// +build !remoteclient
-
-package adapter
-
-import (
- "bufio"
- "context"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "strconv"
- "strings"
- "sync"
- "syscall"
- "time"
-
- "github.com/containers/buildah"
- cfg "github.com/containers/common/pkg/config"
- "github.com/containers/image/v5/manifest"
- "github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/shared"
- "github.com/containers/libpod/libpod"
- "github.com/containers/libpod/libpod/define"
- "github.com/containers/libpod/libpod/events"
- "github.com/containers/libpod/libpod/image"
- "github.com/containers/libpod/libpod/logs"
- "github.com/containers/libpod/pkg/adapter/shortcuts"
- envLib "github.com/containers/libpod/pkg/env"
- "github.com/containers/libpod/pkg/systemd/generate"
- "github.com/containers/storage"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// GetLatestContainer gets the latest Container and wraps it in an adapter Container
-func (r *LocalRuntime) GetLatestContainer() (*Container, error) {
- Container := Container{}
- c, err := r.Runtime.GetLatestContainer()
- Container.Container = c
- return &Container, err
-}
-
-// GetAllContainers gets all Containers and wraps each one in an adapter Container
-func (r *LocalRuntime) GetAllContainers() ([]*Container, error) {
- var containers []*Container
- allContainers, err := r.Runtime.GetAllContainers()
- if err != nil {
- return nil, err
- }
-
- for _, c := range allContainers {
- containers = append(containers, &Container{c})
- }
- return containers, nil
-}
-
-// LookupContainer gets a Container by name or id and wraps it in an adapter Container
-func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
- ctr, err := r.Runtime.LookupContainer(idOrName)
- if err != nil {
- return nil, err
- }
- return &Container{ctr}, nil
-}
-
-// StopContainers stops container(s) based on CLI inputs.
-// Returns list of successful id(s), map of failed id(s) + error, or error not from container
-func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopValues) ([]string, map[string]error, error) {
- var timeout *uint
- if cli.Flags().Changed("timeout") || cli.Flags().Changed("time") {
- t := cli.Timeout
- timeout = &t
- }
-
- maxWorkers := shared.DefaultPoolSize("stop")
- if cli.GlobalIsSet("max-workers") {
- maxWorkers = cli.GlobalFlags.MaxWorks
- }
- logrus.Debugf("Setting maximum stop workers to %d", maxWorkers)
-
- names := cli.InputArgs
- for _, cidFile := range cli.CIDFiles {
- content, err := ioutil.ReadFile(cidFile)
- if err != nil {
- return nil, nil, errors.Wrap(err, "error reading CIDFile")
- }
- id := strings.Split(string(content), "\n")[0]
- names = append(names, id)
- }
-
- ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, names, r.Runtime)
- if err != nil && !(cli.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
- return nil, nil, err
- }
-
- pool := shared.NewPool("stop", maxWorkers, len(ctrs))
- for _, c := range ctrs {
- c := c
-
- if timeout == nil {
- t := c.StopTimeout()
- timeout = &t
- logrus.Debugf("Set timeout to container %s default (%d)", c.ID(), *timeout)
- }
-
- pool.Add(shared.Job{
- ID: c.ID(),
- Fn: func() error {
- err := c.StopWithTimeout(*timeout)
- if err != nil {
- if errors.Cause(err) == define.ErrCtrStopped {
- logrus.Debugf("Container %s is already stopped", c.ID())
- return nil
- } else if cli.All && errors.Cause(err) == define.ErrCtrStateInvalid {
- logrus.Debugf("Container %s is not running, could not stop", c.ID())
- return nil
- }
- logrus.Debugf("Failed to stop container %s: %s", c.ID(), err.Error())
- }
- return err
- },
- })
- }
- return pool.Run()
-}
-
-// KillContainers sends signal to container(s) based on CLI inputs.
-// Returns list of successful id(s), map of failed id(s) + error, or error not from container
-func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillValues, signal syscall.Signal) ([]string, map[string]error, error) {
- maxWorkers := shared.DefaultPoolSize("kill")
- if cli.GlobalIsSet("max-workers") {
- maxWorkers = cli.GlobalFlags.MaxWorks
- }
- logrus.Debugf("Setting maximum kill workers to %d", maxWorkers)
-
- ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
- if err != nil {
- return nil, nil, err
- }
-
- pool := shared.NewPool("kill", maxWorkers, len(ctrs))
- for _, c := range ctrs {
- c := c
-
- pool.Add(shared.Job{
- ID: c.ID(),
- Fn: func() error {
- return c.Kill(uint(signal))
- },
- })
- }
- return pool.Run()
-}
-
-// InitContainers initializes container(s) based on CLI inputs.
-// Returns list of successful id(s), map of failed id(s) to errors, or a general
-// error not from the container.
-func (r *LocalRuntime) InitContainers(ctx context.Context, cli *cliconfig.InitValues) ([]string, map[string]error, error) {
- maxWorkers := shared.DefaultPoolSize("init")
- if cli.GlobalIsSet("max-workers") {
- maxWorkers = cli.GlobalFlags.MaxWorks
- }
- logrus.Debugf("Setting maximum init workers to %d", maxWorkers)
-
- ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
- if err != nil {
- return nil, nil, err
- }
-
- pool := shared.NewPool("init", maxWorkers, len(ctrs))
- for _, c := range ctrs {
- ctr := c
-
- pool.Add(shared.Job{
- ID: ctr.ID(),
- Fn: func() error {
- err := ctr.Init(ctx)
- if err != nil {
- // If we're initializing all containers, ignore invalid state errors
- if cli.All && errors.Cause(err) == define.ErrCtrStateInvalid {
- return nil
- }
- return err
- }
- return nil
- },
- })
- }
- return pool.Run()
-}
-
-// RemoveContainers removes container(s) based on CLI inputs.
-func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmValues) ([]string, map[string]error, error) {
- var (
- ok = []string{}
- failures = map[string]error{}
- )
-
- maxWorkers := shared.DefaultPoolSize("rm")
- if cli.GlobalIsSet("max-workers") {
- maxWorkers = cli.GlobalFlags.MaxWorks
- }
- logrus.Debugf("Setting maximum rm workers to %d", maxWorkers)
-
- if cli.Storage {
- for _, ctr := range cli.InputArgs {
- if err := r.RemoveStorageContainer(ctr, cli.Force); err != nil {
- failures[ctr] = err
- }
- ok = append(ok, ctr)
- }
- return ok, failures, nil
- }
-
- names := cli.InputArgs
- for _, cidFile := range cli.CIDFiles {
- content, err := ioutil.ReadFile(cidFile)
- if err != nil {
- return nil, nil, errors.Wrap(err, "error reading CIDFile")
- }
- id := strings.Split(string(content), "\n")[0]
- names = append(names, id)
- }
-
- ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, names, r.Runtime)
- if err != nil && !(cli.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
- // Failed to get containers. If force is specified, get the containers ID
- // and evict them
- if !cli.Force {
- return ok, failures, err
- }
-
- for _, ctr := range cli.InputArgs {
- logrus.Debugf("Evicting container %q", ctr)
- id, err := r.EvictContainer(ctx, ctr, cli.Volumes)
- if err != nil {
- if cli.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
- logrus.Debugf("Ignoring error (--allow-missing): %v", err)
- continue
- }
- failures[ctr] = errors.Wrapf(err, "Failed to evict container: %q", id)
- continue
- }
- ok = append(ok, id)
- }
- return ok, failures, nil
- }
-
- pool := shared.NewPool("rm", maxWorkers, len(ctrs))
- for _, c := range ctrs {
- c := c
-
- pool.Add(shared.Job{
- ID: c.ID(),
- Fn: func() error {
- err := r.RemoveContainer(ctx, c, cli.Force, cli.Volumes)
- if err != nil {
- if cli.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
- logrus.Debugf("Ignoring error (--allow-missing): %v", err)
- return nil
- }
- logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error())
- }
- return err
- },
- })
- }
- return pool.Run()
-}
-
-// UmountRootFilesystems removes container(s) based on CLI inputs.
-func (r *LocalRuntime) UmountRootFilesystems(ctx context.Context, cli *cliconfig.UmountValues) ([]string, map[string]error, error) {
- var (
- ok = []string{}
- failures = map[string]error{}
- )
-
- ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
- if err != nil {
- return ok, failures, err
- }
-
- for _, ctr := range ctrs {
- state, err := ctr.State()
- if err != nil {
- logrus.Debugf("Error umounting container %s state: %s", ctr.ID(), err.Error())
- continue
- }
- if state == define.ContainerStateRunning {
- logrus.Debugf("Error umounting container %s, is running", ctr.ID())
- continue
- }
-
- if err := ctr.Unmount(cli.Force); err != nil {
- if cli.All && errors.Cause(err) == storage.ErrLayerNotMounted {
- logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID())
- continue
- }
- failures[ctr.ID()] = errors.Wrapf(err, "error unmounting container %s", ctr.ID())
- } else {
- ok = append(ok, ctr.ID())
- }
- }
- return ok, failures, nil
-}
-
-// WaitOnContainers waits for all given container(s) to stop
-func (r *LocalRuntime) WaitOnContainers(ctx context.Context, cli *cliconfig.WaitValues, interval time.Duration) ([]string, map[string]error, error) {
- var (
- ok = []string{}
- failures = map[string]error{}
- )
-
- ctrs, err := shortcuts.GetContainersByContext(false, cli.Latest, cli.InputArgs, r.Runtime)
- if err != nil {
- return ok, failures, err
- }
-
- for _, c := range ctrs {
- if returnCode, err := c.WaitWithInterval(interval); err == nil {
- ok = append(ok, strconv.Itoa(int(returnCode)))
- } else {
- failures[c.ID()] = err
- }
- }
- return ok, failures, err
-}
-
-// Log logs one or more containers
-func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *logs.LogOptions) error {
-
- var wg sync.WaitGroup
- options.WaitGroup = &wg
- if len(c.InputArgs) > 1 {
- options.Multi = true
- }
- tailLen := int(c.Tail)
- if tailLen < 0 {
- tailLen = 0
- }
- numContainers := len(c.InputArgs)
- if numContainers == 0 {
- numContainers = 1
- }
- logChannel := make(chan *logs.LogLine, tailLen*numContainers+1)
- containers, err := shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime)
- if err != nil {
- return err
- }
- if err := r.Runtime.Log(containers, options, logChannel); err != nil {
- return err
- }
- go func() {
- wg.Wait()
- close(logChannel)
- }()
- for line := range logChannel {
- fmt.Println(line.String(options))
- }
- return nil
-}
-
-// CreateContainer creates a libpod container
-func (r *LocalRuntime) CreateContainer(ctx context.Context, c *cliconfig.CreateValues) (string, error) {
- results := shared.NewIntermediateLayer(&c.PodmanCommand, false)
- ctr, _, err := shared.CreateContainer(ctx, &results, r.Runtime)
- if err != nil {
- return "", err
- }
- return ctr.ID(), nil
-}
-
-// Select the detach keys to use from user input flag, config file, or default value
-func (r *LocalRuntime) selectDetachKeys(flagValue string) (string, error) {
- if flagValue != "" {
- return flagValue, nil
- }
-
- config, err := r.GetConfig()
- if err != nil {
- return "", errors.Wrapf(err, "unable to retrieve runtime config")
- }
- if config.Engine.DetachKeys != "" {
- return config.Engine.DetachKeys, nil
- }
-
- return cfg.DefaultDetachKeys, nil
-}
-
-// Run a libpod container
-func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode int) (int, error) {
- results := shared.NewIntermediateLayer(&c.PodmanCommand, false)
-
- ctr, createConfig, err := shared.CreateContainer(ctx, &results, r.Runtime)
- if err != nil {
- return exitCode, err
- }
-
- if logrus.GetLevel() == logrus.DebugLevel {
- cgroupPath, err := ctr.CGroupPath()
- if err == nil {
- logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath)
- }
- }
-
- // Handle detached start
- if createConfig.Detach {
- // if the container was created as part of a pod, also start its dependencies, if any.
- if err := ctr.Start(ctx, c.IsSet("pod")); err != nil {
- // This means the command did not exist
- return define.ExitCode(err), err
- }
-
- fmt.Printf("%s\n", ctr.ID())
- exitCode = 0
- return exitCode, nil
- }
-
- outputStream := os.Stdout
- errorStream := os.Stderr
- inputStream := os.Stdin
-
- // If -i is not set, clear stdin
- if !c.Bool("interactive") {
- inputStream = nil
- }
-
- // If attach is set, clear stdin/stdout/stderr and only attach requested
- if c.IsSet("attach") || c.IsSet("a") {
- outputStream = nil
- errorStream = nil
- if !c.Bool("interactive") {
- inputStream = nil
- }
-
- attachTo := c.StringSlice("attach")
- for _, stream := range attachTo {
- switch strings.ToLower(stream) {
- case "stdout":
- outputStream = os.Stdout
- case "stderr":
- errorStream = os.Stderr
- case "stdin":
- inputStream = os.Stdin
- default:
- return exitCode, errors.Wrapf(define.ErrInvalidArg, "invalid stream %q for --attach - must be one of stdin, stdout, or stderr", stream)
- }
- }
- }
-
- keys := c.String("detach-keys")
- if !c.IsSet("detach-keys") {
- keys, err = r.selectDetachKeys(keys)
- if err != nil {
- return exitCode, err
- }
- }
-
- // if the container was created as part of a pod, also start its dependencies, if any.
- if err := StartAttachCtr(ctx, ctr, outputStream, errorStream, inputStream, keys, c.Bool("sig-proxy"), true, c.IsSet("pod")); 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 {
- return 0, nil
- }
- if c.IsSet("rm") {
- if deleteError := r.Runtime.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: %v", err)
- return define.ExitCode(err), errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
- }
- return define.ExitCode(err), err
- }
-
- if ecode, err := ctr.Wait(); err != nil {
- if errors.Cause(err) == define.ErrNoSuchCtr {
- // Check events
- event, err := r.Runtime.GetLastContainerEvent(ctr.ID(), events.Exited)
- if err != nil {
- logrus.Errorf("Cannot get exit code: %v", err)
- exitCode = define.ExecErrorCodeNotFound
- } else {
- exitCode = event.ContainerExitCode
- }
- }
- } else {
- exitCode = int(ecode)
- }
-
- if c.IsSet("rm") {
- if err := r.Runtime.RemoveContainer(ctx, ctr, false, true); err != nil {
- if errors.Cause(err) == define.ErrNoSuchCtr ||
- errors.Cause(err) == define.ErrCtrRemoved {
- logrus.Warnf("Container %s does not exist: %v", ctr.ID(), err)
- } else {
- logrus.Errorf("Error removing container %s: %v", ctr.ID(), err)
- }
- }
- }
-
- return exitCode, nil
-}
-
-// Ps ...
-func (r *LocalRuntime) Ps(c *cliconfig.PsValues, opts shared.PsOptions) ([]shared.PsContainerOutput, error) {
- maxWorkers := shared.Parallelize("ps")
- if c.GlobalIsSet("max-workers") {
- maxWorkers = c.GlobalFlags.MaxWorks
- }
- logrus.Debugf("Setting maximum workers to %d", maxWorkers)
- return shared.GetPsContainerOutput(r.Runtime, opts, c.Filter, maxWorkers)
-}
-
-// Attach ...
-func (r *LocalRuntime) Attach(ctx context.Context, c *cliconfig.AttachValues) error {
- var (
- ctr *libpod.Container
- err error
- )
-
- if c.Latest {
- ctr, err = r.Runtime.GetLatestContainer()
- } else {
- ctr, err = r.Runtime.LookupContainer(c.InputArgs[0])
- }
-
- if err != nil {
- return errors.Wrapf(err, "unable to exec into %s", c.InputArgs[0])
- }
-
- conState, err := ctr.State()
- if err != nil {
- return errors.Wrapf(err, "unable to determine state of %s", ctr.ID())
- }
- if conState != define.ContainerStateRunning {
- return errors.Errorf("you can only attach to running containers")
- }
-
- inputStream := os.Stdin
- if c.NoStdin {
- inputStream = nil
- }
-
- keys := c.DetachKeys
- if !c.IsSet("detach-keys") {
- keys, err = r.selectDetachKeys(keys)
- if err != nil {
- return err
- }
- }
-
- // If the container is in a pod, also set to recursively start dependencies
- if err := StartAttachCtr(ctx, ctr, os.Stdout, os.Stderr, inputStream, keys, c.SigProxy, false, ctr.PodID() != ""); err != nil && errors.Cause(err) != define.ErrDetach {
- return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
- }
- return nil
-}
-
-// Checkpoint one or more containers
-func (r *LocalRuntime) Checkpoint(c *cliconfig.CheckpointValues) error {
- var (
- containers []*libpod.Container
- err, lastError error
- )
-
- options := libpod.ContainerCheckpointOptions{
- Keep: c.Keep,
- KeepRunning: c.LeaveRunning,
- TCPEstablished: c.TcpEstablished,
- TargetFile: c.Export,
- IgnoreRootfs: c.IgnoreRootfs,
- }
- if c.Export == "" && c.IgnoreRootfs {
- return errors.Errorf("--ignore-rootfs can only be used with --export")
- }
- if c.All {
- containers, err = r.Runtime.GetRunningContainers()
- } else {
- containers, err = shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime)
- }
- if err != nil {
- return err
- }
-
- for _, ctr := range containers {
- if err = ctr.Checkpoint(context.TODO(), options); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to checkpoint container %v", ctr.ID())
- } else {
- fmt.Println(ctr.ID())
- }
- }
- return lastError
-}
-
-// Restore one or more containers
-func (r *LocalRuntime) Restore(ctx context.Context, c *cliconfig.RestoreValues) error {
- var (
- containers []*libpod.Container
- err, lastError error
- filterFuncs []libpod.ContainerFilter
- )
-
- options := libpod.ContainerCheckpointOptions{
- Keep: c.Keep,
- TCPEstablished: c.TcpEstablished,
- TargetFile: c.Import,
- Name: c.Name,
- IgnoreRootfs: c.IgnoreRootfs,
- IgnoreStaticIP: c.IgnoreStaticIP,
- IgnoreStaticMAC: c.IgnoreStaticMAC,
- }
-
- filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
- state, _ := c.State()
- return state == define.ContainerStateExited
- })
-
- switch {
- case c.Import != "":
- containers, err = crImportCheckpoint(ctx, r.Runtime, c.Import, c.Name)
- case c.All:
- containers, err = r.GetContainers(filterFuncs...)
- default:
- containers, err = shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime)
- }
- if err != nil {
- return err
- }
-
- for _, ctr := range containers {
- if err = ctr.Restore(context.TODO(), options); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to restore container %v", ctr.ID())
- } else {
- fmt.Println(ctr.ID())
- }
- }
- return lastError
-}
-
-// Start will start a container
-func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigProxy bool) (int, error) {
- var (
- exitCode = define.ExecErrorCodeGeneric
- lastError error
- )
-
- args := c.InputArgs
- if c.Latest {
- lastCtr, err := r.GetLatestContainer()
- if err != nil {
- return 0, errors.Wrapf(err, "unable to get latest container")
- }
- args = append(args, lastCtr.ID())
- }
-
- for _, container := range args {
- ctr, err := r.LookupContainer(container)
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "unable to find container %s", container)
- continue
- }
-
- ctrState, err := ctr.State()
- if err != nil {
- return exitCode, errors.Wrapf(err, "unable to get container state")
- }
-
- ctrRunning := ctrState == define.ContainerStateRunning
-
- if c.Attach {
- inputStream := os.Stdin
- if !c.Interactive {
- if !ctr.Stdin() {
- inputStream = nil
- }
- }
-
- keys := c.DetachKeys
- if !c.IsSet("detach-keys") {
- keys, err = r.selectDetachKeys(keys)
- if err != nil {
- return exitCode, err
- }
- }
-
- // attach to the container and also start it not already running
- // If the container is in a pod, also set to recursively start dependencies
- err = StartAttachCtr(ctx, ctr.Container, os.Stdout, os.Stderr, inputStream, keys, sigProxy, !ctrRunning, ctr.PodID() != "")
- if errors.Cause(err) == define.ErrDetach {
- // User manually detached
- // Exit cleanly immediately
- exitCode = 0
- return exitCode, nil
- }
-
- if errors.Cause(err) == define.ErrWillDeadlock {
- logrus.Debugf("Deadlock error: %v", err)
- return define.ExitCode(err), errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
- }
-
- if ctrRunning {
- return 0, err
- }
-
- if err != nil {
- return exitCode, errors.Wrapf(err, "unable to start container %s", ctr.ID())
- }
-
- if ecode, err := ctr.Wait(); err != nil {
- if errors.Cause(err) == define.ErrNoSuchCtr {
- // Check events
- event, err := r.Runtime.GetLastContainerEvent(ctr.ID(), events.Exited)
- if err != nil {
- logrus.Errorf("Cannot get exit code: %v", err)
- exitCode = define.ExecErrorCodeNotFound
- } else {
- exitCode = event.ContainerExitCode
- }
- }
- } else {
- exitCode = int(ecode)
- }
-
- return exitCode, nil
- }
- // Start the container if it's not running already.
- if !ctrRunning {
- // Handle non-attach start
- // If the container is in a pod, also set to recursively start dependencies
- if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- if errors.Cause(err) == define.ErrWillDeadlock {
- lastError = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks")
- continue
- }
- lastError = errors.Wrapf(err, "unable to start container %q", container)
- continue
- }
- }
- // Check if the container is referenced by ID or by name and print
- // it accordingly.
- if strings.HasPrefix(ctr.ID(), container) {
- fmt.Println(ctr.ID())
- } else {
- fmt.Println(container)
- }
- }
- return exitCode, lastError
-}
-
-// PauseContainers removes container(s) based on CLI inputs.
-func (r *LocalRuntime) PauseContainers(ctx context.Context, cli *cliconfig.PauseValues) ([]string, map[string]error, error) {
- var (
- ok = []string{}
- failures = map[string]error{}
- ctrs []*libpod.Container
- err error
- )
-
- maxWorkers := shared.DefaultPoolSize("pause")
- if cli.GlobalIsSet("max-workers") {
- maxWorkers = cli.GlobalFlags.MaxWorks
- }
- logrus.Debugf("Setting maximum rm workers to %d", maxWorkers)
-
- if cli.All {
- ctrs, err = r.GetRunningContainers()
- } else {
- ctrs, err = shortcuts.GetContainersByContext(false, false, cli.InputArgs, r.Runtime)
- }
- if err != nil {
- return ok, failures, err
- }
-
- pool := shared.NewPool("pause", maxWorkers, len(ctrs))
- for _, c := range ctrs {
- ctr := c
- pool.Add(shared.Job{
- ID: ctr.ID(),
- Fn: func() error {
- err := ctr.Pause()
- if err != nil {
- logrus.Debugf("Failed to pause container %s: %s", ctr.ID(), err.Error())
- }
- return err
- },
- })
- }
- return pool.Run()
-}
-
-// UnpauseContainers removes container(s) based on CLI inputs.
-func (r *LocalRuntime) UnpauseContainers(ctx context.Context, cli *cliconfig.UnpauseValues) ([]string, map[string]error, error) {
- var (
- ok = []string{}
- failures = map[string]error{}
- ctrs []*libpod.Container
- err error
- )
-
- maxWorkers := shared.DefaultPoolSize("pause")
- if cli.GlobalIsSet("max-workers") {
- maxWorkers = cli.GlobalFlags.MaxWorks
- }
- logrus.Debugf("Setting maximum rm workers to %d", maxWorkers)
-
- if cli.All {
- var filterFuncs []libpod.ContainerFilter
- filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
- state, _ := c.State()
- return state == define.ContainerStatePaused
- })
- ctrs, err = r.GetContainers(filterFuncs...)
- } else {
- ctrs, err = shortcuts.GetContainersByContext(false, false, cli.InputArgs, r.Runtime)
- }
- if err != nil {
- return ok, failures, err
- }
-
- pool := shared.NewPool("pause", maxWorkers, len(ctrs))
- for _, c := range ctrs {
- ctr := c
- pool.Add(shared.Job{
- ID: ctr.ID(),
- Fn: func() error {
- err := ctr.Unpause()
- if err != nil {
- logrus.Debugf("Failed to unpause container %s: %s", ctr.ID(), err.Error())
- }
- return err
- },
- })
- }
- return pool.Run()
-}
-
-// Restart containers without or without a timeout
-func (r *LocalRuntime) Restart(ctx context.Context, c *cliconfig.RestartValues) ([]string, map[string]error, error) {
- var (
- containers []*libpod.Container
- restartContainers []*libpod.Container
- err error
- )
- useTimeout := c.Flag("timeout").Changed || c.Flag("time").Changed
- inputTimeout := c.Timeout
-
- // Handle --latest
- switch {
- case c.Latest:
- lastCtr, err := r.Runtime.GetLatestContainer()
- if err != nil {
- return nil, nil, errors.Wrapf(err, "unable to get latest container")
- }
- restartContainers = append(restartContainers, lastCtr)
- case c.Running:
- containers, err = r.GetRunningContainers()
- if err != nil {
- return nil, nil, err
- }
- restartContainers = append(restartContainers, containers...)
- case c.All:
- containers, err = r.Runtime.GetAllContainers()
- if err != nil {
- return nil, nil, err
- }
- restartContainers = append(restartContainers, containers...)
- default:
- for _, id := range c.InputArgs {
- ctr, err := r.Runtime.LookupContainer(id)
- if err != nil {
- return nil, nil, err
- }
- restartContainers = append(restartContainers, ctr)
- }
- }
-
- maxWorkers := shared.DefaultPoolSize("restart")
- if c.GlobalIsSet("max-workers") {
- maxWorkers = c.GlobalFlags.MaxWorks
- }
-
- logrus.Debugf("Setting maximum workers to %d", maxWorkers)
-
- // We now have a slice of all the containers to be restarted. Iterate them to
- // create restart Funcs with a timeout as needed
- pool := shared.NewPool("restart", maxWorkers, len(restartContainers))
- for _, c := range restartContainers {
- ctr := c
- timeout := ctr.StopTimeout()
- if useTimeout {
- timeout = inputTimeout
- }
- pool.Add(shared.Job{
- ID: ctr.ID(),
- Fn: func() error {
- err := ctr.RestartWithTimeout(ctx, timeout)
- if err != nil {
- logrus.Debugf("Failed to restart container %s: %s", ctr.ID(), err.Error())
- }
- return err
- },
- })
- }
- return pool.Run()
-}
-
-// Top display the running processes of a container
-func (r *LocalRuntime) Top(cli *cliconfig.TopValues) ([]string, error) {
- var (
- descriptors []string
- container *libpod.Container
- err error
- )
- if cli.Latest {
- descriptors = cli.InputArgs
- container, err = r.Runtime.GetLatestContainer()
- } else {
- descriptors = cli.InputArgs[1:]
- container, err = r.Runtime.LookupContainer(cli.InputArgs[0])
- }
- if err != nil {
- return nil, errors.Wrapf(err, "unable to lookup requested container")
- }
-
- return container.Top(descriptors)
-}
-
-// ExecContainer executes a command in the container
-func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecValues) (int, error) {
- var (
- ctr *Container
- err error
- cmd []string
- )
- // default invalid command exit code
- ec := define.ExecErrorCodeGeneric
-
- if cli.Latest {
- if ctr, err = r.GetLatestContainer(); err != nil {
- return ec, err
- }
- cmd = cli.InputArgs[0:]
- } else {
- if ctr, err = r.LookupContainer(cli.InputArgs[0]); err != nil {
- return ec, err
- }
- cmd = cli.InputArgs[1:]
- }
-
- if cli.PreserveFDs > 0 {
- entries, err := ioutil.ReadDir("/proc/self/fd")
- if err != nil {
- return ec, errors.Wrapf(err, "unable to read /proc/self/fd")
- }
-
- m := make(map[int]bool)
- for _, e := range entries {
- i, err := strconv.Atoi(e.Name())
- if err != nil {
- return ec, errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
- }
- m[i] = true
- }
-
- for i := 3; i < 3+cli.PreserveFDs; i++ {
- if _, found := m[i]; !found {
- return ec, errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
- }
- }
- }
-
- // Validate given environment variables
- env := map[string]string{}
- if len(cli.EnvFile) > 0 {
- for _, f := range cli.EnvFile {
- fileEnv, err := envLib.ParseFile(f)
- if err != nil {
- return ec, err
- }
- env = envLib.Join(env, fileEnv)
- }
- }
- cliEnv, err := envLib.ParseSlice(cli.Env)
- if err != nil {
- return ec, errors.Wrap(err, "error parsing environment variables")
- }
- env = envLib.Join(env, cliEnv)
-
- streams := new(libpod.AttachStreams)
- streams.OutputStream = os.Stdout
- streams.ErrorStream = os.Stderr
- if cli.Interactive {
- streams.InputStream = bufio.NewReader(os.Stdin)
- streams.AttachInput = true
- }
- streams.AttachOutput = true
- streams.AttachError = true
-
- keys := cli.DetachKeys
- if !cli.IsSet("detach-keys") {
- keys, err = r.selectDetachKeys(keys)
- if err != nil {
- return ec, err
- }
- }
-
- ec, err = ExecAttachCtr(ctx, ctr.Container, cli.Tty, cli.Privileged, env, cmd, cli.User, cli.Workdir, streams, uint(cli.PreserveFDs), keys)
- return define.TranslateExecErrorToExitCode(ec, err), err
-}
-
-// Prune removes stopped containers
-func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, filters []string) ([]string, map[string]error, error) {
- var (
- ok = []string{}
- failures = map[string]error{}
- err error
- filterFunc []libpod.ContainerFilter
- )
-
- logrus.Debugf("Setting maximum rm workers to %d", maxWorkers)
-
- for _, filter := range filters {
- filterSplit := strings.SplitN(filter, "=", 2)
- if len(filterSplit) < 2 {
- return ok, failures, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", filter)
- }
-
- f, err := shared.GenerateContainerFilterFuncs(filterSplit[0], filterSplit[1], r.Runtime)
- if err != nil {
- return ok, failures, err
- }
- filterFunc = append(filterFunc, f)
- }
-
- containerStateFilter := func(c *libpod.Container) bool {
- state, err := c.State()
- if err != nil {
- logrus.Error(err)
- return false
- }
- if c.PodID() != "" {
- return false
- }
- if state == define.ContainerStateStopped || state == define.ContainerStateExited ||
- state == define.ContainerStateCreated || state == define.ContainerStateConfigured {
- return true
- }
- return false
- }
- filterFunc = append(filterFunc, containerStateFilter)
-
- delContainers, err := r.Runtime.GetContainers(filterFunc...)
- if err != nil {
- return ok, failures, err
- }
- if len(delContainers) < 1 {
- return ok, failures, err
- }
- pool := shared.NewPool("prune", maxWorkers, len(delContainers))
- for _, c := range delContainers {
- ctr := c
- pool.Add(shared.Job{
- ID: ctr.ID(),
- Fn: func() error {
- err := r.Runtime.RemoveContainer(ctx, ctr, false, false)
- if err != nil {
- logrus.Debugf("Failed to prune container %s: %s", ctr.ID(), err.Error())
- }
- return err
- },
- })
- }
- return pool.Run()
-}
-
-// CleanupContainers any leftovers bits of stopped containers
-func (r *LocalRuntime) CleanupContainers(ctx context.Context, cli *cliconfig.CleanupValues) ([]string, map[string]error, error) {
- var (
- ok = []string{}
- failures = map[string]error{}
- )
-
- ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
- if err != nil {
- return ok, failures, err
- }
-
- for _, ctr := range ctrs {
- if cli.Remove {
- err = removeContainer(ctx, ctr, r)
- } else {
- err = cleanupContainer(ctx, ctr, r)
- }
-
- if err == nil {
- ok = append(ok, ctr.ID())
- } else {
- failures[ctr.ID()] = err
- }
-
- if cli.RemoveImage {
- _, imageName := ctr.Image()
- if err := removeContainerImage(ctx, ctr, r); err != nil {
- failures[imageName] = err
- } else {
- ok = append(ok, imageName)
- }
- }
- }
- return ok, failures, nil
-}
-
-// Only used when cleaning up containers
-func removeContainer(ctx context.Context, ctr *libpod.Container, runtime *LocalRuntime) error {
- if err := runtime.RemoveContainer(ctx, ctr, false, true); err != nil {
- return errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
- }
- return nil
-}
-
-func cleanupContainer(ctx context.Context, ctr *libpod.Container, runtime *LocalRuntime) error {
- if err := ctr.Cleanup(ctx); err != nil {
- return errors.Wrapf(err, "failed to cleanup container %v", ctr.ID())
- }
- return nil
-}
-
-func removeContainerImage(ctx context.Context, ctr *libpod.Container, runtime *LocalRuntime) error {
- _, imageName := ctr.Image()
- ctrImage, err := runtime.NewImageFromLocal(imageName)
- if err != nil {
- return err
- }
- _, err = runtime.RemoveImage(ctx, ctrImage, false)
- return err
-}
-
-// Port displays port information about existing containers
-func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) {
- var (
- portContainers []*Container
- containers []*libpod.Container
- err error
- )
-
- if !c.All {
- names := []string{}
- if len(c.InputArgs) >= 1 {
- names = []string{c.InputArgs[0]}
- }
- containers, err = shortcuts.GetContainersByContext(false, c.Latest, names, r.Runtime)
- } else {
- containers, err = r.Runtime.GetRunningContainers()
- }
- if err != nil {
- return nil, err
- }
-
- //Convert libpod containers to adapter Containers
- for _, con := range containers {
- if state, _ := con.State(); state != define.ContainerStateRunning {
- continue
- }
- portContainers = append(portContainers, &Container{con})
- }
- return portContainers, nil
-}
-
-// generateServiceName generates the container name and the service name for systemd service.
-func generateServiceName(c *cliconfig.GenerateSystemdValues, ctr *libpod.Container, pod *libpod.Pod) (string, string) {
- var kind, name, ctrName string
- if pod == nil {
- kind = "container"
- name = ctr.ID()
- if c.Name {
- name = ctr.Name()
- }
- ctrName = name
- } else {
- kind = "pod"
- name = pod.ID()
- ctrName = ctr.ID()
- if c.Name {
- name = pod.Name()
- ctrName = ctr.Name()
- }
- }
- return ctrName, fmt.Sprintf("%s-%s", kind, name)
-}
-
-// generateSystemdgenContainerInfo is a helper to generate a
-// systemdgen.ContainerInfo for `GenerateSystemd`.
-func (r *LocalRuntime) generateSystemdgenContainerInfo(c *cliconfig.GenerateSystemdValues, nameOrID string, pod *libpod.Pod) (*generate.ContainerInfo, bool, error) {
- ctr, err := r.Runtime.LookupContainer(nameOrID)
- if err != nil {
- return nil, false, err
- }
-
- timeout := ctr.StopTimeout()
- if c.Flags().Changed("timeout") || c.Flags().Changed("time") {
- timeout = c.StopTimeout
- }
-
- config := ctr.Config()
- conmonPidFile := config.ConmonPidFile
- if conmonPidFile == "" {
- return nil, true, errors.Errorf("conmon PID file path is empty, try to recreate the container with --conmon-pidfile flag")
- }
-
- name, serviceName := generateServiceName(c, ctr, pod)
- info := &generate.ContainerInfo{
- ServiceName: serviceName,
- ContainerName: name,
- RestartPolicy: c.RestartPolicy,
- PIDFile: conmonPidFile,
- StopTimeout: timeout,
- GenerateTimestamp: true,
- CreateCommand: config.CreateCommand,
- }
-
- return info, true, nil
-}
-
-// GenerateSystemd creates a unit file for a container or pod.
-func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) {
- opts := generate.Options{
- Files: c.Files,
- New: c.New,
- }
-
- // First assume it's a container.
- if info, found, err := r.generateSystemdgenContainerInfo(c, c.InputArgs[0], nil); found && err != nil {
- return "", err
- } else if found && err == nil {
- return generate.CreateContainerSystemdUnit(info, opts)
- }
-
- // --new does not support pods.
- if c.New {
- return "", errors.Errorf("error generating systemd unit files: cannot generate generic files for a pod")
- }
-
- // We're either having a pod or garbage.
- pod, err := r.Runtime.LookupPod(c.InputArgs[0])
- if err != nil {
- return "", err
- }
-
- // Error out if the pod has no infra container, which we require to be the
- // main service.
- if !pod.HasInfraContainer() {
- return "", fmt.Errorf("error generating systemd unit files: Pod %q has no infra container", pod.Name())
- }
-
- // Generate a systemdgen.ContainerInfo for the infra container. This
- // ContainerInfo acts as the main service of the pod.
- infraID, err := pod.InfraContainerID()
- if err != nil {
- return "", nil
- }
- podInfo, _, err := r.generateSystemdgenContainerInfo(c, infraID, pod)
- if err != nil {
- return "", nil
- }
-
- // Compute the container-dependency graph for the Pod.
- containers, err := pod.AllContainers()
- if err != nil {
- return "", err
- }
- if len(containers) == 0 {
- return "", fmt.Errorf("error generating systemd unit files: Pod %q has no containers", pod.Name())
- }
- graph, err := libpod.BuildContainerGraph(containers)
- if err != nil {
- return "", err
- }
-
- // Traverse the dependency graph and create systemdgen.ContainerInfo's for
- // each container.
- containerInfos := []*generate.ContainerInfo{podInfo}
- for ctr, dependencies := range graph.DependencyMap() {
- // Skip the infra container as we already generated it.
- if ctr.ID() == infraID {
- continue
- }
- ctrInfo, _, err := r.generateSystemdgenContainerInfo(c, ctr.ID(), nil)
- if err != nil {
- return "", err
- }
- // Now add the container's dependencies and at the container as a
- // required service of the infra container.
- for _, dep := range dependencies {
- if dep.ID() == infraID {
- ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, podInfo.ServiceName)
- } else {
- _, serviceName := generateServiceName(c, dep, nil)
- ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, serviceName)
- }
- }
- podInfo.RequiredServices = append(podInfo.RequiredServices, ctrInfo.ServiceName)
- containerInfos = append(containerInfos, ctrInfo)
- }
-
- // Now generate the systemd service for all containers.
- builder := strings.Builder{}
- for i, info := range containerInfos {
- if i > 0 {
- builder.WriteByte('\n')
- }
- out, err := generate.CreateContainerSystemdUnit(info, opts)
- if err != nil {
- return "", err
- }
- builder.WriteString(out)
- }
-
- return builder.String(), nil
-}
-
-// GetNamespaces returns namespace information about a container for PS
-func (r *LocalRuntime) GetNamespaces(container shared.PsContainerOutput) *shared.Namespace {
- return shared.GetNamespaces(container.Pid)
-}
-
-// Commit creates a local image from a container
-func (r *LocalRuntime) Commit(ctx context.Context, c *cliconfig.CommitValues, container, imageName string) (string, error) {
- var (
- writer io.Writer
- mimeType string
- )
- switch c.Format {
- case "oci":
- mimeType = buildah.OCIv1ImageManifest
- if c.Flag("message").Changed {
- return "", errors.Errorf("messages are only compatible with the docker image format (-f docker)")
- }
- case "docker":
- mimeType = manifest.DockerV2Schema2MediaType
- default:
- return "", errors.Errorf("unrecognized image format %q", c.Format)
- }
- if !c.Quiet {
- writer = os.Stderr
- }
- ctr, err := r.Runtime.LookupContainer(container)
- if err != nil {
- return "", errors.Wrapf(err, "error looking up container %q", container)
- }
-
- rtc, err := r.Runtime.GetConfig()
- if err != nil {
- return "", err
- }
-
- sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
- coptions := buildah.CommitOptions{
- SignaturePolicyPath: rtc.Engine.SignaturePolicyPath,
- ReportWriter: writer,
- SystemContext: sc,
- PreferredManifestType: mimeType,
- }
- options := libpod.ContainerCommitOptions{
- CommitOptions: coptions,
- Pause: c.Pause,
- IncludeVolumes: c.IncludeVolumes,
- Message: c.Message,
- Changes: c.Change,
- Author: c.Author,
- }
- newImage, err := ctr.Commit(ctx, imageName, options)
- if err != nil {
- return "", err
- }
- return newImage.ID(), nil
-}