Merge pull request #5581 from baude/v2containers
podmanv2 add core container commands
This commit is contained in:
		
						commit
						3dbf2cb5af
					
				|  | @ -0,0 +1,71 @@ | |||
| package containers | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/parse" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/registry" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/utils" | ||||
| 	"github.com/containers/libpod/pkg/domain/entities" | ||||
| 	"github.com/containers/libpod/pkg/signal" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	killDescription = "The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal." | ||||
| 	killCommand     = &cobra.Command{ | ||||
| 		Use:   "kill [flags] CONTAINER [CONTAINER...]", | ||||
| 		Short: "Kill one or more running containers with a specific signal", | ||||
| 		Long:  killDescription, | ||||
| 		RunE:  kill, | ||||
| 		Args: func(cmd *cobra.Command, args []string) error { | ||||
| 			return parse.CheckAllLatestAndCIDFile(cmd, args, false, false) | ||||
| 		}, | ||||
| 		Example: `podman kill mywebserver | ||||
|   podman kill 860a4b23 | ||||
|   podman kill --signal TERM ctrID`, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	killOptions = entities.KillOptions{} | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	registry.Commands = append(registry.Commands, registry.CliCommand{ | ||||
| 		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, | ||||
| 		Command: killCommand, | ||||
| 	}) | ||||
| 	flags := killCommand.Flags() | ||||
| 	flags.BoolVarP(&killOptions.All, "all", "a", false, "Signal all running containers") | ||||
| 	flags.StringVarP(&killOptions.Signal, "signal", "s", "KILL", "Signal to send to the container") | ||||
| 	flags.BoolVarP(&killOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of") | ||||
| 	if utils.IsRemote() { | ||||
| 		_ = flags.MarkHidden("latest") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func kill(cmd *cobra.Command, args []string) error { | ||||
| 	var ( | ||||
| 		err  error | ||||
| 		errs utils.OutputErrors | ||||
| 	) | ||||
| 	// Check if the signalString provided by the user is valid
 | ||||
| 	// Invalid signals will return err
 | ||||
| 	if _, err = signal.ParseSignalNameOrNumber(killOptions.Signal); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	responses, err := registry.ContainerEngine().ContainerKill(context.Background(), args, killOptions) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, r := range responses { | ||||
| 		if r.Err == nil { | ||||
| 			fmt.Println(r.Id) | ||||
| 		} else { | ||||
| 			errs = append(errs, r.Err) | ||||
| 		} | ||||
| 	} | ||||
| 	return errs.PrintErrors() | ||||
| } | ||||
|  | @ -0,0 +1,63 @@ | |||
| package containers | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/registry" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/utils" | ||||
| 	"github.com/containers/libpod/pkg/domain/entities" | ||||
| 	"github.com/containers/libpod/pkg/rootless" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	pauseDescription = `Pauses one or more running containers.  The container name or ID can be used.` | ||||
| 	pauseCommand     = &cobra.Command{ | ||||
| 		Use:   "pause [flags] CONTAINER [CONTAINER...]", | ||||
| 		Short: "Pause all the processes in one or more containers", | ||||
| 		Long:  pauseDescription, | ||||
| 		RunE:  pause, | ||||
| 		Example: `podman pause mywebserver | ||||
|   podman pause 860a4b23 | ||||
|   podman pause -a`, | ||||
| 	} | ||||
| 
 | ||||
| 	pauseOpts = entities.PauseUnPauseOptions{} | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	registry.Commands = append(registry.Commands, registry.CliCommand{ | ||||
| 		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, | ||||
| 		Command: pauseCommand, | ||||
| 	}) | ||||
| 	flags := pauseCommand.Flags() | ||||
| 	flags.BoolVarP(&pauseOpts.All, "all", "a", false, "Pause all running containers") | ||||
| 	pauseCommand.SetHelpTemplate(registry.HelpTemplate()) | ||||
| 	pauseCommand.SetUsageTemplate(registry.UsageTemplate()) | ||||
| } | ||||
| 
 | ||||
| func pause(cmd *cobra.Command, args []string) error { | ||||
| 	var ( | ||||
| 		errs utils.OutputErrors | ||||
| 	) | ||||
| 	if rootless.IsRootless() && !utils.IsRemote() { | ||||
| 		return errors.New("pause is not supported for rootless containers") | ||||
| 	} | ||||
| 	if len(args) < 1 && !pauseOpts.All { | ||||
| 		return errors.Errorf("you must provide at least one container name or id") | ||||
| 	} | ||||
| 	responses, err := registry.ContainerEngine().ContainerPause(context.Background(), args, pauseOpts) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, r := range responses { | ||||
| 		if r.Err == nil { | ||||
| 			fmt.Println(r.Id) | ||||
| 		} else { | ||||
| 			errs = append(errs, r.Err) | ||||
| 		} | ||||
| 	} | ||||
| 	return errs.PrintErrors() | ||||
| } | ||||
|  | @ -0,0 +1,78 @@ | |||
| package containers | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/parse" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/registry" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/utils" | ||||
| 	"github.com/containers/libpod/libpod/define" | ||||
| 	"github.com/containers/libpod/pkg/domain/entities" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	restartDescription = `Restarts one or more running containers. The container ID or name can be used. | ||||
| 
 | ||||
|   A timeout before forcibly stopping can be set, but defaults to 10 seconds.` | ||||
| 	restartCommand = &cobra.Command{ | ||||
| 		Use:   "restart [flags] CONTAINER [CONTAINER...]", | ||||
| 		Short: "Restart one or more containers", | ||||
| 		Long:  restartDescription, | ||||
| 		RunE:  restart, | ||||
| 		Args: func(cmd *cobra.Command, args []string) error { | ||||
| 			return parse.CheckAllLatestAndCIDFile(cmd, args, false, false) | ||||
| 		}, | ||||
| 		Example: `podman restart ctrID | ||||
|   podman restart --latest | ||||
|   podman restart ctrID1 ctrID2`, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	restartOptions = entities.RestartOptions{} | ||||
| 	restartTimeout uint | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	registry.Commands = append(registry.Commands, registry.CliCommand{ | ||||
| 		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, | ||||
| 		Command: restartCommand, | ||||
| 	}) | ||||
| 	flags := restartCommand.Flags() | ||||
| 	flags.BoolVarP(&restartOptions.All, "all", "a", false, "Restart all non-running containers") | ||||
| 	flags.BoolVarP(&restartOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of") | ||||
| 	flags.BoolVar(&restartOptions.Running, "running", false, "Restart only running containers when --all is used") | ||||
| 	flags.UintVarP(&restartTimeout, "timeout", "t", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container") | ||||
| 	flags.UintVar(&restartTimeout, "time", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container") | ||||
| 	if utils.IsRemote() { | ||||
| 		_ = flags.MarkHidden("latest") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func restart(cmd *cobra.Command, args []string) error { | ||||
| 	var ( | ||||
| 		errs utils.OutputErrors | ||||
| 	) | ||||
| 	if len(args) < 1 && !restartOptions.Latest && !restartOptions.All { | ||||
| 		return errors.Wrapf(define.ErrInvalidArg, "you must provide at least one container name or ID") | ||||
| 	} | ||||
| 
 | ||||
| 	if cmd.Flag("timeout").Changed || cmd.Flag("time").Changed { | ||||
| 		restartOptions.Timeout = &restartTimeout | ||||
| 	} | ||||
| 	responses, err := registry.ContainerEngine().ContainerRestart(context.Background(), args, restartOptions) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, r := range responses { | ||||
| 		if r.Err == nil { | ||||
| 			fmt.Println(r.Id) | ||||
| 		} else { | ||||
| 			errs = append(errs, r.Err) | ||||
| 		} | ||||
| 	} | ||||
| 	return errs.PrintErrors() | ||||
| } | ||||
|  | @ -0,0 +1,93 @@ | |||
| package containers | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/parse" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/registry" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/utils" | ||||
| 	"github.com/containers/libpod/libpod/define" | ||||
| 	"github.com/containers/libpod/pkg/domain/entities" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	rmDescription = `Removes one or more containers from the host. The container name or ID can be used. | ||||
| 
 | ||||
|   Command does not remove images. Running or unusable containers will not be removed without the -f option.` | ||||
| 	rmCommand = &cobra.Command{ | ||||
| 		Use:   "rm [flags] CONTAINER [CONTAINER...]", | ||||
| 		Short: "Remove one or more containers", | ||||
| 		Long:  rmDescription, | ||||
| 		RunE:  rm, | ||||
| 		Args: func(cmd *cobra.Command, args []string) error { | ||||
| 			return parse.CheckAllLatestAndCIDFile(cmd, args, false, true) | ||||
| 		}, | ||||
| 		Example: `podman rm imageID | ||||
|   podman rm mywebserver myflaskserver 860a4b23 | ||||
|   podman rm --force --all | ||||
|   podman rm -f c684f0d469f2`, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	rmOptions = entities.RmOptions{} | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	registry.Commands = append(registry.Commands, registry.CliCommand{ | ||||
| 		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, | ||||
| 		Command: rmCommand, | ||||
| 	}) | ||||
| 	flags := rmCommand.Flags() | ||||
| 	flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all containers") | ||||
| 	flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing") | ||||
| 	flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Force removal of a running or unusable container.  The default is false") | ||||
| 	flags.BoolVarP(&rmOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of") | ||||
| 	flags.BoolVar(&rmOptions.Storage, "storage", false, "Remove container from storage library") | ||||
| 	flags.BoolVarP(&rmOptions.Volumes, "volumes", "v", false, "Remove anonymous volumes associated with the container") | ||||
| 	flags.StringArrayVarP(&rmOptions.CIDFiles, "cidfile", "", nil, "Read the container ID from the file") | ||||
| 	if utils.IsRemote() { | ||||
| 		_ = flags.MarkHidden("latest") | ||||
| 		_ = flags.MarkHidden("ignore") | ||||
| 		_ = flags.MarkHidden("cidfile") | ||||
| 		_ = flags.MarkHidden("storage") | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func rm(cmd *cobra.Command, args []string) error { | ||||
| 	var ( | ||||
| 		errs utils.OutputErrors | ||||
| 	) | ||||
| 	// Storage conflicts with --all/--latest/--volumes/--cidfile/--ignore
 | ||||
| 	if rmOptions.Storage { | ||||
| 		if rmOptions.All || rmOptions.Ignore || rmOptions.Latest || rmOptions.Volumes || rmOptions.CIDFiles != nil { | ||||
| 			return errors.Errorf("--storage conflicts with --volumes, --all, --latest, --ignore and --cidfile") | ||||
| 		} | ||||
| 	} | ||||
| 	responses, err := registry.ContainerEngine().ContainerRm(context.Background(), args, rmOptions) | ||||
| 	if err != nil { | ||||
| 		// TODO exitcode is a global main variable to track exit codes.
 | ||||
| 		// we need this enabled
 | ||||
| 		//if len(c.InputArgs) < 2 {
 | ||||
| 		//	exitCode = setExitCode(err)
 | ||||
| 		//}
 | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, r := range responses { | ||||
| 		if r.Err != nil { | ||||
| 			// TODO this will not work with the remote client
 | ||||
| 			if errors.Cause(err) == define.ErrWillDeadlock { | ||||
| 				logrus.Errorf("Potential deadlock detected - please run 'podman system renumber' to resolve") | ||||
| 			} | ||||
| 			errs = append(errs, r.Err) | ||||
| 		} else { | ||||
| 			fmt.Println(r.Id) | ||||
| 		} | ||||
| 	} | ||||
| 	return errs.PrintErrors() | ||||
| } | ||||
|  | @ -0,0 +1,87 @@ | |||
| package containers | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/parse" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/registry" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/utils" | ||||
| 	"github.com/containers/libpod/libpod/define" | ||||
| 	"github.com/containers/libpod/pkg/domain/entities" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	stopDescription = `Stops one or more running containers.  The container name or ID can be used. | ||||
| 
 | ||||
|   A timeout to forcibly stop the container can also be set but defaults to 10 seconds otherwise.` | ||||
| 	stopCommand = &cobra.Command{ | ||||
| 		Use:   "stop [flags] CONTAINER [CONTAINER...]", | ||||
| 		Short: "Stop one or more containers", | ||||
| 		Long:  stopDescription, | ||||
| 		RunE:  stop, | ||||
| 		Args: func(cmd *cobra.Command, args []string) error { | ||||
| 			return parse.CheckAllLatestAndCIDFile(cmd, args, false, true) | ||||
| 		}, | ||||
| 		Example: `podman stop ctrID | ||||
|   podman stop --latest | ||||
|   podman stop --timeout 2 mywebserver 6e534f14da9d`, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	stopOptions = entities.StopOptions{} | ||||
| 	stopTimeout uint | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	registry.Commands = append(registry.Commands, registry.CliCommand{ | ||||
| 		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, | ||||
| 		Command: stopCommand, | ||||
| 	}) | ||||
| 	flags := stopCommand.Flags() | ||||
| 	flags.BoolVarP(&stopOptions.All, "all", "a", false, "Stop all running containers") | ||||
| 	flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing") | ||||
| 	flags.StringArrayVarP(&stopOptions.CIDFiles, "cidfile", "", nil, "Read the container ID from the file") | ||||
| 	flags.BoolVarP(&stopOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of") | ||||
| 	flags.UintVar(&stopTimeout, "time", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container") | ||||
| 	flags.UintVarP(&stopTimeout, "timeout", "t", define.CtrRemoveTimeout, "Seconds to wait for stop before killing the container") | ||||
| 	if registry.EngineOpts.EngineMode == entities.ABIMode { | ||||
| 		_ = flags.MarkHidden("latest") | ||||
| 		_ = flags.MarkHidden("cidfile") | ||||
| 		_ = flags.MarkHidden("ignore") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func stop(cmd *cobra.Command, args []string) error { | ||||
| 	var ( | ||||
| 		errs utils.OutputErrors | ||||
| 	) | ||||
| 	if cmd.Flag("timeout").Changed && cmd.Flag("time").Changed { | ||||
| 		return errors.New("the --timeout and --time flags are mutually exclusive") | ||||
| 	} | ||||
| 	stopOptions.Timeout = define.CtrRemoveTimeout | ||||
| 	if cmd.Flag("timeout").Changed || cmd.Flag("time").Changed { | ||||
| 		stopOptions.Timeout = stopTimeout | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO How do we access global attributes?
 | ||||
| 	//if c.Bool("trace") {
 | ||||
| 	//	span, _ := opentracing.StartSpanFromContext(Ctx, "stopCmd")
 | ||||
| 	//	defer span.Finish()
 | ||||
| 	//}
 | ||||
| 	responses, err := registry.ContainerEngine().ContainerStop(context.Background(), args, stopOptions) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, r := range responses { | ||||
| 		if r.Err == nil { | ||||
| 			fmt.Println(r.Id) | ||||
| 		} else { | ||||
| 			errs = append(errs, r.Err) | ||||
| 		} | ||||
| 	} | ||||
| 	return errs.PrintErrors() | ||||
| } | ||||
|  | @ -0,0 +1,60 @@ | |||
| package containers | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/registry" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/utils" | ||||
| 	"github.com/containers/libpod/pkg/domain/entities" | ||||
| 	"github.com/containers/libpod/pkg/rootless" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	unpauseDescription = `Unpauses one or more previously paused containers.  The container name or ID can be used.` | ||||
| 	unpauseCommand     = &cobra.Command{ | ||||
| 		Use:   "unpause [flags] CONTAINER [CONTAINER...]", | ||||
| 		Short: "Unpause the processes in one or more containers", | ||||
| 		Long:  unpauseDescription, | ||||
| 		RunE:  unpause, | ||||
| 		Example: `podman unpause ctrID | ||||
|   podman unpause --all`, | ||||
| 	} | ||||
| 	unPauseOptions = entities.PauseUnPauseOptions{} | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	registry.Commands = append(registry.Commands, registry.CliCommand{ | ||||
| 		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, | ||||
| 		Command: unpauseCommand, | ||||
| 		Parent:  containerCmd, | ||||
| 	}) | ||||
| 	flags := unpauseCommand.Flags() | ||||
| 	flags.BoolVarP(&unPauseOptions.All, "all", "a", false, "Pause all running containers") | ||||
| } | ||||
| 
 | ||||
| func unpause(cmd *cobra.Command, args []string) error { | ||||
| 	var ( | ||||
| 		errs utils.OutputErrors | ||||
| 	) | ||||
| 	if rootless.IsRootless() && !utils.IsRemote() { | ||||
| 		return errors.New("unpause is not supported for rootless containers") | ||||
| 	} | ||||
| 	if len(args) < 1 && !unPauseOptions.All { | ||||
| 		return errors.Errorf("you must provide at least one container name or id") | ||||
| 	} | ||||
| 	responses, err := registry.ContainerEngine().ContainerUnpause(context.Background(), args, unPauseOptions) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, r := range responses { | ||||
| 		if r.Err == nil { | ||||
| 			fmt.Println(r.Id) | ||||
| 		} else { | ||||
| 			errs = append(errs, r.Err) | ||||
| 		} | ||||
| 	} | ||||
| 	return errs.PrintErrors() | ||||
| } | ||||
|  | @ -0,0 +1 @@ | |||
| package containers | ||||
|  | @ -5,7 +5,9 @@ import ( | |||
| 	"fmt" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/parse" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/registry" | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/utils" | ||||
| 	"github.com/containers/libpod/libpod/define" | ||||
| 	"github.com/containers/libpod/pkg/domain/entities" | ||||
| 	"github.com/pkg/errors" | ||||
|  | @ -20,6 +22,9 @@ var ( | |||
| 		Short: "Block on one or more containers", | ||||
| 		Long:  waitDescription, | ||||
| 		RunE:  wait, | ||||
| 		Args: func(cmd *cobra.Command, args []string) error { | ||||
| 			return parse.CheckAllLatestAndCIDFile(cmd, args, false, false) | ||||
| 		}, | ||||
| 		Example: `podman wait --latest | ||||
|   podman wait --interval 5000 ctrID | ||||
|   podman wait ctrID1 ctrID2`, | ||||
|  | @ -27,7 +32,7 @@ var ( | |||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	waitFlags     = entities.WaitOptions{} | ||||
| 	waitOptions   = entities.WaitOptions{} | ||||
| 	waitCondition string | ||||
| ) | ||||
| 
 | ||||
|  | @ -35,12 +40,11 @@ func init() { | |||
| 	registry.Commands = append(registry.Commands, registry.CliCommand{ | ||||
| 		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, | ||||
| 		Command: waitCommand, | ||||
| 		Parent:  containerCmd, | ||||
| 	}) | ||||
| 
 | ||||
| 	flags := waitCommand.Flags() | ||||
| 	flags.DurationVarP(&waitFlags.Interval, "interval", "i", time.Duration(250), "Milliseconds to wait before polling for completion") | ||||
| 	flags.BoolVarP(&waitFlags.Latest, "latest", "l", false, "Act on the latest container podman is aware of") | ||||
| 	flags.DurationVarP(&waitOptions.Interval, "interval", "i", time.Duration(250), "Milliseconds to wait before polling for completion") | ||||
| 	flags.BoolVarP(&waitOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of") | ||||
| 	flags.StringVar(&waitCondition, "condition", "stopped", "Condition to wait on") | ||||
| 	if registry.EngineOpts.EngineMode == entities.ABIMode { | ||||
| 		// TODO: This is the same as V1.  We could skip creating the flag altogether in V2...
 | ||||
|  | @ -50,33 +54,28 @@ func init() { | |||
| 
 | ||||
| func wait(cmd *cobra.Command, args []string) error { | ||||
| 	var ( | ||||
| 		err error | ||||
| 		err  error | ||||
| 		errs utils.OutputErrors | ||||
| 	) | ||||
| 	if waitFlags.Latest && len(args) > 0 { | ||||
| 		return errors.New("cannot combine latest flag and arguments") | ||||
| 	} | ||||
| 	if waitFlags.Interval == 0 { | ||||
| 	if waitOptions.Interval == 0 { | ||||
| 		return errors.New("interval must be greater then 0") | ||||
| 	} | ||||
| 
 | ||||
| 	waitFlags.Condition, err = define.StringToContainerStatus(waitCondition) | ||||
| 	waitOptions.Condition, err = define.StringToContainerStatus(waitCondition) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	responses, err := registry.ContainerEngine().ContainerWait(context.Background(), args, waitFlags) | ||||
| 	responses, err := registry.ContainerEngine().ContainerWait(context.Background(), args, waitOptions) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, r := range responses { | ||||
| 		if r.Error == nil { | ||||
| 			fmt.Println(r.Id) | ||||
| 		} else { | ||||
| 			errs = append(errs, r.Error) | ||||
| 		} | ||||
| 	} | ||||
| 	for _, r := range responses { | ||||
| 		if r.Error != nil { | ||||
| 			fmt.Println(err) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| 	return errs.PrintErrors() | ||||
| } | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ import ( | |||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
|  | @ -186,3 +187,47 @@ func ValidURL(urlStr string) error { | |||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // checkAllLatestAndCIDFile checks that --all and --latest are used correctly.
 | ||||
| // If cidfile is set, also check for the --cidfile flag.
 | ||||
| func CheckAllLatestAndCIDFile(c *cobra.Command, args []string, ignoreArgLen bool, cidfile bool) error { | ||||
| 	argLen := len(args) | ||||
| 	if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil { | ||||
| 		if !cidfile { | ||||
| 			return errors.New("unable to lookup values for 'latest' or 'all'") | ||||
| 		} else if c.Flags().Lookup("cidfile") == nil { | ||||
| 			return errors.New("unable to lookup values for 'latest', 'all' or 'cidfile'") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	specifiedAll, _ := c.Flags().GetBool("all") | ||||
| 	specifiedLatest, _ := c.Flags().GetBool("latest") | ||||
| 	specifiedCIDFile := false | ||||
| 	if cid, _ := c.Flags().GetStringArray("cidfile"); len(cid) > 0 { | ||||
| 		specifiedCIDFile = true | ||||
| 	} | ||||
| 
 | ||||
| 	if specifiedCIDFile && (specifiedAll || specifiedLatest) { | ||||
| 		return errors.Errorf("--all, --latest and --cidfile cannot be used together") | ||||
| 	} else if specifiedAll && specifiedLatest { | ||||
| 		return errors.Errorf("--all and --latest cannot be used together") | ||||
| 	} | ||||
| 
 | ||||
| 	if ignoreArgLen { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if (argLen > 0) && (specifiedAll || specifiedLatest) { | ||||
| 		return errors.Errorf("no arguments are needed with --all or --latest") | ||||
| 	} else if cidfile && (argLen > 0) && (specifiedAll || specifiedLatest || specifiedCIDFile) { | ||||
| 		return errors.Errorf("no arguments are needed with --all, --latest or --cidfile") | ||||
| 	} | ||||
| 
 | ||||
| 	if specifiedCIDFile { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedCIDFile { | ||||
| 		return errors.Errorf("you must provide at least one name or id") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -23,8 +23,9 @@ var rootCmd = &cobra.Command{ | |||
| func init() { | ||||
| 	// Override default --help information of `--version` global flag}
 | ||||
| 	var dummyVersion bool | ||||
| 	rootCmd.PersistentFlags().BoolVarP(&dummyVersion, "version", "v", false, "Version of podman") | ||||
| 	rootCmd.PersistentFlags().StringVarP(®istry.EngineOpts.Uri, "remote", "r", "", "URL to access podman service") | ||||
| 	// TODO had to disable shorthand -v for version due to -v rm with volume
 | ||||
| 	rootCmd.PersistentFlags().BoolVar(&dummyVersion, "version", false, "Version of Podman") | ||||
| 	rootCmd.PersistentFlags().StringVarP(®istry.EngineOpts.Uri, "remote", "r", "", "URL to access Podman service") | ||||
| 	rootCmd.PersistentFlags().StringSliceVar(®istry.EngineOpts.Identities, "identity", []string{}, "path to SSH identity file") | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,16 @@ | |||
| package utils | ||||
| 
 | ||||
| import "fmt" | ||||
| 
 | ||||
| type OutputErrors []error | ||||
| 
 | ||||
| func (o OutputErrors) PrintErrors() (lastError error) { | ||||
| 	if len(o) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	lastError = o[len(o)-1] | ||||
| 	for e := 0; e < len(o)-1; e++ { | ||||
| 		fmt.Println(o[e]) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | @ -0,0 +1,10 @@ | |||
| package utils | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/containers/libpod/cmd/podmanV2/registry" | ||||
| 	"github.com/containers/libpod/pkg/domain/entities" | ||||
| ) | ||||
| 
 | ||||
| func IsRemote() bool { | ||||
| 	return registry.EngineOpts.EngineMode == entities.TunnelMode | ||||
| } | ||||
|  | @ -7,7 +7,6 @@ import ( | |||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/libpod" | ||||
|  | @ -15,6 +14,7 @@ import ( | |||
| 	"github.com/containers/libpod/libpod/logs" | ||||
| 	"github.com/containers/libpod/pkg/api/handlers" | ||||
| 	"github.com/containers/libpod/pkg/api/handlers/utils" | ||||
| 	"github.com/containers/libpod/pkg/signal" | ||||
| 	"github.com/containers/libpod/pkg/util" | ||||
| 	"github.com/gorilla/schema" | ||||
| 	"github.com/pkg/errors" | ||||
|  | @ -145,14 +145,20 @@ func KillContainer(w http.ResponseWriter, r *http.Request) { | |||
| 	runtime := r.Context().Value("runtime").(*libpod.Runtime) | ||||
| 	decoder := r.Context().Value("decoder").(*schema.Decoder) | ||||
| 	query := struct { | ||||
| 		Signal syscall.Signal `schema:"signal"` | ||||
| 		Signal string `schema:"signal"` | ||||
| 	}{ | ||||
| 		Signal: syscall.SIGKILL, | ||||
| 		Signal: "KILL", | ||||
| 	} | ||||
| 	if err := decoder.Decode(&query, r.URL.Query()); err != nil { | ||||
| 		utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	sig, err := signal.ParseSignalNameOrNumber(query.Signal) | ||||
| 	if err != nil { | ||||
| 		utils.InternalServerError(w, err) | ||||
| 		return | ||||
| 	} | ||||
| 	name := utils.GetName(r) | ||||
| 	con, err := runtime.LookupContainer(name) | ||||
| 	if err != nil { | ||||
|  | @ -172,7 +178,7 @@ func KillContainer(w http.ResponseWriter, r *http.Request) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	err = con.Kill(uint(query.Signal)) | ||||
| 	err = con.Kill(uint(sig)) | ||||
| 	if err != nil { | ||||
| 		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "unable to kill Container %s", name)) | ||||
| 	} | ||||
|  |  | |||
|  | @ -1,11 +1,9 @@ | |||
| package compat | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/libpod" | ||||
| 	"github.com/containers/libpod/libpod/define" | ||||
| 	"github.com/containers/libpod/pkg/api/handlers/utils" | ||||
| 	"github.com/gorilla/schema" | ||||
| 	"github.com/pkg/errors" | ||||
|  | @ -32,20 +30,6 @@ func RestartContainer(w http.ResponseWriter, r *http.Request) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	state, err := con.State() | ||||
| 	if err != nil { | ||||
| 		utils.InternalServerError(w, err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// FIXME: This is not in the swagger.yml...
 | ||||
| 	// If the Container is stopped already, send a 409
 | ||||
| 	if state == define.ContainerStateStopped || state == define.ContainerStateExited { | ||||
| 		msg := fmt.Sprintf("Container %s is not running", name) | ||||
| 		utils.Error(w, msg, http.StatusConflict, errors.New(msg)) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	timeout := con.StopTimeout() | ||||
| 	if _, found := r.URL.Query()["t"]; found { | ||||
| 		timeout = uint(query.Timeout) | ||||
|  |  | |||
|  | @ -126,13 +126,13 @@ func Inspect(ctx context.Context, nameOrID string, size *bool) (*libpod.InspectC | |||
| // Kill sends a given signal to a given container.  The signal should be the string
 | ||||
| // representation of a signal like 'SIGKILL'. The nameOrID can be a container name
 | ||||
| // or a partial/full ID
 | ||||
| func Kill(ctx context.Context, nameOrID string, signal string) error { | ||||
| func Kill(ctx context.Context, nameOrID string, sig string) error { | ||||
| 	conn, err := bindings.GetClient(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	params := url.Values{} | ||||
| 	params.Set("signal", signal) | ||||
| 	params.Set("signal", sig) | ||||
| 	response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nameOrID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|  | @ -247,14 +247,14 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) { | |||
| 
 | ||||
| // Stop stops a running container.  The timeout is optional. The nameOrID can be a container name
 | ||||
| // or a partial/full ID
 | ||||
| func Stop(ctx context.Context, nameOrID string, timeout *int) error { | ||||
| func Stop(ctx context.Context, nameOrID string, timeout *uint) error { | ||||
| 	params := url.Values{} | ||||
| 	conn, err := bindings.GetClient(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if timeout != nil { | ||||
| 		params.Set("t", strconv.Itoa(*timeout)) | ||||
| 		params.Set("t", strconv.Itoa(int(*timeout))) | ||||
| 	} | ||||
| 	response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/stop", params, nameOrID) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -102,7 +102,7 @@ var _ = Describe("Podman volumes", func() { | |||
| 		Expect(code).To(BeNumerically("==", http.StatusConflict)) | ||||
| 
 | ||||
| 		// Removing with a volume in use with force should work with a stopped container
 | ||||
| 		zero := 0 | ||||
| 		zero := uint(0) | ||||
| 		err = containers.Stop(connText, "vtest", &zero) | ||||
| 		Expect(err).To(BeNil()) | ||||
| 		err = volumes.Remove(connText, vol.Name, &bindings.PTrue) | ||||
|  |  | |||
|  | @ -21,3 +21,63 @@ type WaitReport struct { | |||
| type BoolReport struct { | ||||
| 	Value bool | ||||
| } | ||||
| 
 | ||||
| type PauseUnPauseOptions struct { | ||||
| 	All bool | ||||
| } | ||||
| 
 | ||||
| type PauseUnpauseReport struct { | ||||
| 	Err error | ||||
| 	Id  string | ||||
| } | ||||
| 
 | ||||
| type StopOptions struct { | ||||
| 	All      bool | ||||
| 	CIDFiles []string | ||||
| 	Ignore   bool | ||||
| 	Latest   bool | ||||
| 	Timeout  uint | ||||
| } | ||||
| 
 | ||||
| type StopReport struct { | ||||
| 	Err error | ||||
| 	Id  string | ||||
| } | ||||
| 
 | ||||
| type KillOptions struct { | ||||
| 	All    bool | ||||
| 	Latest bool | ||||
| 	Signal string | ||||
| } | ||||
| 
 | ||||
| type KillReport struct { | ||||
| 	Err error | ||||
| 	Id  string | ||||
| } | ||||
| 
 | ||||
| type RestartOptions struct { | ||||
| 	All     bool | ||||
| 	Latest  bool | ||||
| 	Running bool | ||||
| 	Timeout *uint | ||||
| } | ||||
| 
 | ||||
| type RestartReport struct { | ||||
| 	Err error | ||||
| 	Id  string | ||||
| } | ||||
| 
 | ||||
| type RmOptions struct { | ||||
| 	All      bool | ||||
| 	CIDFiles []string | ||||
| 	Force    bool | ||||
| 	Ignore   bool | ||||
| 	Latest   bool | ||||
| 	Storage  bool | ||||
| 	Volumes  bool | ||||
| } | ||||
| 
 | ||||
| type RmReport struct { | ||||
| 	Err error | ||||
| 	Id  string | ||||
| } | ||||
|  |  | |||
|  | @ -5,9 +5,14 @@ import ( | |||
| ) | ||||
| 
 | ||||
| type ContainerEngine interface { | ||||
| 	ContainerDelete(ctx context.Context, opts ContainerDeleteOptions) (*ContainerDeleteReport, error) | ||||
| 	ContainerPrune(ctx context.Context) (*ContainerPruneReport, error) | ||||
| 	ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error) | ||||
| 	ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error) | ||||
| 	ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) | ||||
| 	ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error) | ||||
| 	ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error) | ||||
| 	ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) | ||||
| 	ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error) | ||||
| 	ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error) | ||||
| 	PodDelete(ctx context.Context, opts PodPruneOptions) (*PodDeleteReport, error) | ||||
| 	PodExists(ctx context.Context, nameOrId string) (*BoolReport, error) | ||||
|  |  | |||
|  | @ -4,11 +4,16 @@ package abi | |||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"io/ioutil" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/libpod" | ||||
| 	"github.com/containers/libpod/libpod/define" | ||||
| 	"github.com/containers/libpod/pkg/adapter/shortcuts" | ||||
| 	"github.com/containers/libpod/pkg/domain/entities" | ||||
| 	"github.com/containers/libpod/pkg/signal" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
| 
 | ||||
| // TODO: Should return *entities.ContainerExistsReport, error
 | ||||
|  | @ -41,8 +46,198 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin | |||
| 	return responses, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerDelete(ctx context.Context, opts entities.ContainerDeleteOptions) (*entities.ContainerDeleteReport, error) { | ||||
| 	panic("implement me") | ||||
| func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { | ||||
| 	var ( | ||||
| 		ctrs   []*libpod.Container | ||||
| 		err    error | ||||
| 		report []*entities.PauseUnpauseReport | ||||
| 	) | ||||
| 	if options.All { | ||||
| 		ctrs, err = ic.Libpod.GetAllContainers() | ||||
| 	} else { | ||||
| 		ctrs, err = shortcuts.GetContainersByContext(false, false, namesOrIds, ic.Libpod) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, c := range ctrs { | ||||
| 		err := c.Pause() | ||||
| 		report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err}) | ||||
| 	} | ||||
| 	return report, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { | ||||
| 	var ( | ||||
| 		ctrs   []*libpod.Container | ||||
| 		err    error | ||||
| 		report []*entities.PauseUnpauseReport | ||||
| 	) | ||||
| 	if options.All { | ||||
| 		ctrs, err = ic.Libpod.GetAllContainers() | ||||
| 	} else { | ||||
| 		ctrs, err = shortcuts.GetContainersByContext(false, false, namesOrIds, ic.Libpod) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, c := range ctrs { | ||||
| 		err := c.Unpause() | ||||
| 		report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err}) | ||||
| 	} | ||||
| 	return report, nil | ||||
| } | ||||
| func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.StopReport | ||||
| 	) | ||||
| 	names := namesOrIds | ||||
| 	for _, cidFile := range options.CIDFiles { | ||||
| 		content, err := ioutil.ReadFile(cidFile) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrap(err, "error reading CIDFile") | ||||
| 		} | ||||
| 		id := strings.Split(string(content), "\n")[0] | ||||
| 		names = append(names, id) | ||||
| 	} | ||||
| 	ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, names, ic.Libpod) | ||||
| 	if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, con := range ctrs { | ||||
| 		report := entities.StopReport{Id: con.ID()} | ||||
| 		err = con.StopWithTimeout(options.Timeout) | ||||
| 		if err != nil { | ||||
| 			// These first two are considered non-fatal under the right conditions
 | ||||
| 			if errors.Cause(err) == define.ErrCtrStopped { | ||||
| 				logrus.Debugf("Container %s is already stopped", con.ID()) | ||||
| 				reports = append(reports, &report) | ||||
| 				continue | ||||
| 
 | ||||
| 			} else if options.All && errors.Cause(err) == define.ErrCtrStateInvalid { | ||||
| 				logrus.Debugf("Container %s is not running, could not stop", con.ID()) | ||||
| 				reports = append(reports, &report) | ||||
| 				continue | ||||
| 			} | ||||
| 			report.Err = err | ||||
| 			reports = append(reports, &report) | ||||
| 			continue | ||||
| 		} | ||||
| 		reports = append(reports, &report) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.KillReport | ||||
| 	) | ||||
| 	sig, err := signal.ParseSignalNameOrNumber(options.Signal) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, con := range ctrs { | ||||
| 		reports = append(reports, &entities.KillReport{ | ||||
| 			Id:  con.ID(), | ||||
| 			Err: con.Kill(uint(sig)), | ||||
| 		}) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
| func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.RestartReport | ||||
| 	) | ||||
| 	ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, con := range ctrs { | ||||
| 		timeout := con.StopTimeout() | ||||
| 		if options.Timeout != nil { | ||||
| 			timeout = *options.Timeout | ||||
| 		} | ||||
| 		reports = append(reports, &entities.RestartReport{ | ||||
| 			Id:  con.ID(), | ||||
| 			Err: con.RestartWithTimeout(ctx, timeout), | ||||
| 		}) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.RmReport | ||||
| 	) | ||||
| 	if options.Storage { | ||||
| 		for _, ctr := range namesOrIds { | ||||
| 			report := entities.RmReport{Id: ctr} | ||||
| 			if err := ic.Libpod.RemoveStorageContainer(ctr, options.Force); err != nil { | ||||
| 				report.Err = err | ||||
| 			} | ||||
| 			reports = append(reports, &report) | ||||
| 		} | ||||
| 		return reports, nil | ||||
| 	} | ||||
| 
 | ||||
| 	names := namesOrIds | ||||
| 	for _, cidFile := range options.CIDFiles { | ||||
| 		content, err := ioutil.ReadFile(cidFile) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrap(err, "error reading CIDFile") | ||||
| 		} | ||||
| 		id := strings.Split(string(content), "\n")[0] | ||||
| 		names = append(names, id) | ||||
| 	} | ||||
| 
 | ||||
| 	ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, names, ic.Libpod) | ||||
| 	if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) { | ||||
| 		// Failed to get containers. If force is specified, get the containers ID
 | ||||
| 		// and evict them
 | ||||
| 		if !options.Force { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		for _, ctr := range namesOrIds { | ||||
| 			logrus.Debugf("Evicting container %q", ctr) | ||||
| 			report := entities.RmReport{Id: ctr} | ||||
| 			id, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes) | ||||
| 			if err != nil { | ||||
| 				if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr { | ||||
| 					logrus.Debugf("Ignoring error (--allow-missing): %v", err) | ||||
| 					reports = append(reports, &report) | ||||
| 					continue | ||||
| 				} | ||||
| 				report.Err = errors.Wrapf(err, "Failed to evict container: %q", id) | ||||
| 				reports = append(reports, &report) | ||||
| 				continue | ||||
| 			} | ||||
| 			reports = append(reports, &report) | ||||
| 		} | ||||
| 		return reports, nil | ||||
| 	} | ||||
| 
 | ||||
| 	for _, c := range ctrs { | ||||
| 		report := entities.RmReport{Id: c.ID()} | ||||
| 		err := ic.Libpod.RemoveContainer(ctx, c, options.Force, options.Volumes) | ||||
| 		if err != nil { | ||||
| 			if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr { | ||||
| 				logrus.Debugf("Ignoring error (--allow-missing): %v", err) | ||||
| 				reports = append(reports, &report) | ||||
| 				continue | ||||
| 			} | ||||
| 			logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error()) | ||||
| 			report.Err = err | ||||
| 			reports = append(reports, &report) | ||||
| 			continue | ||||
| 		} | ||||
| 		reports = append(reports, &report) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerPrune(ctx context.Context) (*entities.ContainerPruneReport, error) { | ||||
|  |  | |||
|  | @ -40,3 +40,108 @@ func (r *ContainerEngine) ContainerDelete(ctx context.Context, opts entities.Con | |||
| func (r *ContainerEngine) ContainerPrune(ctx context.Context) (*entities.ContainerPruneReport, error) { | ||||
| 	panic("implement me") | ||||
| } | ||||
| func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.PauseUnpauseReport | ||||
| 	) | ||||
| 	ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, c := range ctrs { | ||||
| 		err := containers.Pause(ic.ClientCxt, c.ID) | ||||
| 		reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err}) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.PauseUnpauseReport | ||||
| 	) | ||||
| 	ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, c := range ctrs { | ||||
| 		err := containers.Unpause(ic.ClientCxt, c.ID) | ||||
| 		reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err}) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.StopReport | ||||
| 	) | ||||
| 	ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, c := range ctrs { | ||||
| 		report := entities.StopReport{Id: c.ID} | ||||
| 		report.Err = containers.Stop(ic.ClientCxt, c.ID, &options.Timeout) | ||||
| 		// TODO we need to associate errors returned by http with common
 | ||||
| 		// define.errors so that we can equity tests. this will allow output
 | ||||
| 		// to be the same as the native client
 | ||||
| 		reports = append(reports, &report) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.KillReport | ||||
| 	) | ||||
| 	ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, c := range ctrs { | ||||
| 		reports = append(reports, &entities.KillReport{ | ||||
| 			Id:  c.ID, | ||||
| 			Err: containers.Kill(ic.ClientCxt, c.ID, options.Signal), | ||||
| 		}) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.RestartReport | ||||
| 		timeout *int | ||||
| 	) | ||||
| 	if options.Timeout != nil { | ||||
| 		t := int(*options.Timeout) | ||||
| 		timeout = &t | ||||
| 	} | ||||
| 	ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, c := range ctrs { | ||||
| 		reports = append(reports, &entities.RestartReport{ | ||||
| 			Id:  c.ID, | ||||
| 			Err: containers.Restart(ic.ClientCxt, c.ID, timeout), | ||||
| 		}) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) { | ||||
| 	var ( | ||||
| 		reports []*entities.RmReport | ||||
| 	) | ||||
| 	ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// TODO there is no endpoint for container eviction.  Need to discuss
 | ||||
| 	for _, c := range ctrs { | ||||
| 		reports = append(reports, &entities.RmReport{ | ||||
| 			Id:  c.ID, | ||||
| 			Err: containers.Remove(ic.ClientCxt, c.ID, &options.Force, &options.Volumes), | ||||
| 		}) | ||||
| 	} | ||||
| 	return reports, nil | ||||
| } | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ package tunnel | |||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/pkg/api/handlers/libpod" | ||||
| 	"github.com/containers/libpod/pkg/bindings" | ||||
|  | @ -27,7 +28,7 @@ func getContainersByContext(contextWithConnection context.Context, all bool, nam | |||
| 	for _, id := range namesOrIds { | ||||
| 		var found bool | ||||
| 		for _, con := range c { | ||||
| 			if id == con.ID || util.StringInSlice(id, con.Names) { | ||||
| 			if id == con.ID || strings.HasPrefix(con.ID, id) || util.StringInSlice(id, con.Names) { | ||||
| 				cons = append(cons, con) | ||||
| 				found = true | ||||
| 				break | ||||
|  |  | |||
|  | @ -104,11 +104,11 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) { | |||
| 		} | ||||
| 		return syscall.Signal(s), nil | ||||
| 	} | ||||
| 	signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")] | ||||
| 	sig, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")] | ||||
| 	if !ok { | ||||
| 		return -1, fmt.Errorf("invalid signal: %s", rawSignal) | ||||
| 	} | ||||
| 	return signal, nil | ||||
| 	return sig, nil | ||||
| } | ||||
| 
 | ||||
| // CatchAll catches all signals and relays them to the specified channel.
 | ||||
|  | @ -125,3 +125,18 @@ func StopCatch(sigc chan os.Signal) { | |||
| 	signal.Stop(sigc) | ||||
| 	close(sigc) | ||||
| } | ||||
| 
 | ||||
| // ParseSignalNameOrNumber translates a string to a valid syscall signal.  Input
 | ||||
| // can be a name or number representation i.e. "KILL" "9"
 | ||||
| func ParseSignalNameOrNumber(rawSignal string) (syscall.Signal, error) { | ||||
| 	s, err := ParseSignal(rawSignal) | ||||
| 	if err == nil { | ||||
| 		return s, nil | ||||
| 	} | ||||
| 	for k, v := range signalMap { | ||||
| 		if k == strings.ToUpper(rawSignal) { | ||||
| 			return v, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return -1, fmt.Errorf("invalid signal: %s", rawSignal) | ||||
| } | ||||
|  |  | |||
|  | @ -26,3 +26,9 @@ func CatchAll(sigc chan os.Signal) { | |||
| func StopCatch(sigc chan os.Signal) { | ||||
| 	panic("Unsupported on non-linux platforms") | ||||
| } | ||||
| 
 | ||||
| // ParseSignalNameOrNumber translates a string to a valid syscall signal.  Input
 | ||||
| // can be a name or number representation i.e. "KILL" "9"
 | ||||
| func ParseSignalNameOrNumber(rawSignal string) (syscall.Signal, error) { | ||||
| 	return 0, fmt.Errorf("unsupported on non-linux platforms") | ||||
| } | ||||
|  |  | |||
|  | @ -309,15 +309,15 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) { | |||
| 	// Strip off leading dash, to allow -1 or -HUP
 | ||||
| 	basename := strings.TrimPrefix(rawSignal, "-") | ||||
| 
 | ||||
| 	signal, err := signal.ParseSignal(basename) | ||||
| 	sig, err := signal.ParseSignal(basename) | ||||
| 	if err != nil { | ||||
| 		return -1, err | ||||
| 	} | ||||
| 	// 64 is SIGRTMAX; wish we could get this from a standard Go library
 | ||||
| 	if signal < 1 || signal > 64 { | ||||
| 	if sig < 1 || sig > 64 { | ||||
| 		return -1, errors.Errorf("valid signals are 1 through 64") | ||||
| 	} | ||||
| 	return signal, nil | ||||
| 	return sig, nil | ||||
| } | ||||
| 
 | ||||
| // ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue