diff options
42 files changed, 782 insertions, 247 deletions
diff --git a/.copr/prepare.sh b/.copr/prepare.sh index d8ad34d08..713cdc2ee 100644 --- a/.copr/prepare.sh +++ b/.copr/prepare.sh @@ -1,12 +1,14 @@ #!/bin/sh -euf -set -x +set -euxo pipefail OS_TEST=${OS_TEST:=0} if [ ! -e /usr/bin/git ]; then dnf -y install git-core fi -git fetch --unshallow || : +if [ -f $(git rev-parse --git-dir)/shallow ]; then + git fetch --unshallow +fi COMMIT=$(git rev-parse HEAD) COMMIT_SHORT=$(git rev-parse --short=8 HEAD) @@ -26,7 +28,12 @@ if [ ${OS_TEST} -eq 0 ]; then sed -i "s/${BR}/${NEWBR}/g" contrib/spec/podman.spec fi -mkdir build/ +mkdir -p build/ git archive --prefix "libpod-${COMMIT_SHORT}/" --format "tar.gz" HEAD -o "build/libpod-${COMMIT_SHORT}.tar.gz" -git clone https://github.com/containers/conmon -cd conmon && git checkout 6f3572558b97bc60dd8f8c7f0807748e6ce2c440 && git archive --prefix "conmon/" --format "tar.gz" HEAD -o "../build/conmon.tar.gz" +if [ ! -d conmon ]; then + git clone -n --quiet https://github.com/containers/conmon +fi +pushd conmon +git checkout 6f3572558b97bc60dd8f8c7f0807748e6ce2c440 +git archive --prefix "conmon/" --format "tar.gz" HEAD -o "../build/conmon.tar.gz" +popd @@ -149,6 +149,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [func RemovePod(name: string, force: bool) string](#RemovePod) +[func Reset() ](#Reset) + [func RestartContainer(name: string, timeout: int) string](#RestartContainer) [func RestartPod(name: string) string](#RestartPod) @@ -1059,6 +1061,12 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.RemovePod '{"name": "62f4 "pod": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20" } ~~~ +### <a name="Reset"></a>func Reset +<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> + +method Reset() </div> +Reset resets Podman back to its initial state. +Removes all Pods, Containers, Images and Volumes ### <a name="RestartContainer"></a>func RestartContainer <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -318,7 +318,7 @@ $(MANPAGES): %: %.md .gopathok docdir: mkdir -p docs/build/man -docs: docdir $(MANPAGES) ## Generate documentation +docs: .install.md2man docdir $(MANPAGES) ## Generate documentation install-podman-remote-%-docs: podman-remote docs $(MANPAGES) rm -rf docs/build/remote @@ -532,19 +532,23 @@ vendor-in-container: .PHONY: \ .gopathok \ binaries \ + changelog \ clean \ - validate.completions \ default \ docs \ gofmt \ + golangci-lint \ help \ install \ - golangci-lint \ + install.libseccomp.sudo \ lint \ pause \ - uninstall \ shell \ - changelog \ + uninstall \ validate \ - install.libseccomp.sudo \ + validate.completions \ vendor + +rpm: + @echo "Building rpms ..." + ./contrib/build_rpm.sh diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index a34afa827..c15ce8829 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -183,7 +183,8 @@ type PruneImagesValues struct { type PruneContainersValues struct { PodmanCommand - Force bool + Force bool + Filter []string } type PodPruneValues struct { @@ -658,6 +659,11 @@ type SystemPruneValues struct { Volume bool } +type SystemResetValues struct { + PodmanCommand + Force bool +} + type SystemRenumberValues struct { PodmanCommand } diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go index 3d0fef37d..78c50268c 100644 --- a/cmd/podman/containers_prune.go +++ b/cmd/podman/containers_prune.go @@ -1,6 +1,11 @@ package main import ( + "bufio" + "fmt" + "os" + "strings" + "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod/define" @@ -36,9 +41,23 @@ func init() { pruneContainersCommand.SetUsageTemplate(UsageTemplate()) flags := pruneContainersCommand.Flags() flags.BoolVarP(&pruneContainersCommand.Force, "force", "f", false, "Force removal of a running container. The default is false") + flags.StringArrayVar(&pruneContainersCommand.Filter, "filter", []string{}, "Provide filter values (e.g. 'until=<timestamp>')") } func pruneContainersCmd(c *cliconfig.PruneContainersValues) error { + if !c.Force { + reader := bufio.NewReader(os.Stdin) + fmt.Printf(`WARNING! This will remove all stopped containers. +Are you sure you want to continue? [y/N] `) + ans, err := reader.ReadString('\n') + if err != nil { + return errors.Wrapf(err, "error reading input") + } + if strings.ToLower(ans)[0] != 'y' { + return nil + } + } + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") @@ -49,7 +68,7 @@ func pruneContainersCmd(c *cliconfig.PruneContainersValues) error { if c.GlobalIsSet("max-workers") { maxWorkers = c.GlobalFlags.MaxWorks } - ok, failures, err := runtime.Prune(getContext(), maxWorkers, c.Force) + ok, failures, err := runtime.Prune(getContext(), maxWorkers, c.Force, c.Filter) if err != nil { if errors.Cause(err) == define.ErrNoSuchCtr { if len(c.InputArgs) > 1 { diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go index 968d7331a..bc46e4652 100644 --- a/cmd/podman/main_local.go +++ b/cmd/podman/main_local.go @@ -159,7 +159,7 @@ func setupRootless(cmd *cobra.Command, args []string) error { Remote: remoteclient, } - runtime, err := libpodruntime.GetRuntime(getContext(), &podmanCmd) + runtime, err := libpodruntime.GetRuntimeNoStore(getContext(), &podmanCmd) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/reset.go b/cmd/podman/reset.go new file mode 100644 index 000000000..9d16dc978 --- /dev/null +++ b/cmd/podman/reset.go @@ -0,0 +1,71 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/pkg/adapter" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + systemResetCommand cliconfig.SystemResetValues + systemResetDescription = `Reset podman storage back to default state" + + All containers will be stopped and removed, and all images, volumes and container content will be removed. +` + _systemResetCommand = &cobra.Command{ + Use: "reset", + Args: noSubArgs, + Short: "Reset podman storage", + Long: systemResetDescription, + RunE: func(cmd *cobra.Command, args []string) error { + systemResetCommand.InputArgs = args + systemResetCommand.GlobalFlags = MainGlobalOpts + systemResetCommand.Remote = remoteclient + return systemResetCmd(&systemResetCommand) + }, + } +) + +func init() { + systemResetCommand.Command = _systemResetCommand + flags := systemResetCommand.Flags() + flags.BoolVarP(&systemResetCommand.Force, "force", "f", false, "Do not prompt for confirmation") + + systemResetCommand.SetHelpTemplate(HelpTemplate()) + systemResetCommand.SetUsageTemplate(UsageTemplate()) +} + +func systemResetCmd(c *cliconfig.SystemResetValues) error { + // Prompt for confirmation if --force is not set + if !c.Force { + reader := bufio.NewReader(os.Stdin) + fmt.Print(` +WARNING! This will remove: + - all containers + - all pods + - all images + - all build cache +Are you sure you want to continue? [y/N] `) + ans, err := reader.ReadString('\n') + if err != nil { + return errors.Wrapf(err, "error reading input") + } + if strings.ToLower(ans)[0] != 'y' { + return nil + } + } + + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) + if err != nil { + return errors.Wrapf(err, "error creating libpod runtime") + } + // No shutdown, since storage will be destroyed when command completes + + return runtime.Reset() +} diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go index f49943477..4f2002992 100644 --- a/cmd/podman/shared/container.go +++ b/cmd/podman/shared/container.go @@ -17,6 +17,7 @@ import ( "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/timetype" "github.com/containers/libpod/pkg/util" "github.com/cri-o/ocicni/pkg/ocicni" "github.com/docker/go-units" @@ -195,6 +196,8 @@ func NewBatchContainer(ctr *libpod.Container, opts PsOptions) (PsContainerOutput status = "Paused" case define.ContainerStateCreated.String(), define.ContainerStateConfigured.String(): status = "Created" + case define.ContainerStateRemoving.String(): + status = "Removing" default: status = "Error" } @@ -272,7 +275,8 @@ func worker(wg *sync.WaitGroup, jobs <-chan workerInput, results chan<- PsContai } } -func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) { +// GenerateContainerFilterFuncs return ContainerFilter functions based of filter. +func GenerateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) { switch filter { case "id": return func(c *libpod.Container) bool { @@ -394,6 +398,22 @@ func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime) } return hcStatus == filterValue }, nil + case "until": + ts, err := timetype.GetTimestamp(filterValue, time.Now()) + if err != nil { + return nil, err + } + seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0) + if err != nil { + return nil, err + } + until := time.Unix(seconds, nanoseconds) + return func(c *libpod.Container) bool { + if !until.IsZero() && c.CreatedTime().After((until)) { + return true + } + return false + }, nil } return nil, errors.Errorf("%s is an invalid filter", filter) } @@ -411,7 +431,7 @@ func GetPsContainerOutput(r *libpod.Runtime, opts PsOptions, filters []string, m if len(filterSplit) < 2 { return nil, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) } - generatedFunc, err := generateContainerFilterFuncs(filterSplit[0], filterSplit[1], r) + generatedFunc, err := GenerateContainerFilterFuncs(filterSplit[0], filterSplit[1], r) if err != nil { return nil, errors.Wrapf(err, "invalid filter") } diff --git a/cmd/podman/system.go b/cmd/podman/system.go index 80080bf44..921d0c037 100644 --- a/cmd/podman/system.go +++ b/cmd/podman/system.go @@ -19,6 +19,7 @@ var ( ) var systemCommands = []*cobra.Command{ + _systemResetCommand, _infoCommand, _pruneSystemCommand, } diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go index ae5d7ed2d..74fdcde99 100644 --- a/cmd/podman/system_prune.go +++ b/cmd/podman/system_prune.go @@ -92,7 +92,7 @@ Are you sure you want to continue? [y/N] `, volumeString) rmWorkers := shared.Parallelize("rm") fmt.Println("Deleted Containers") - ok, failures, err = runtime.Prune(ctx, rmWorkers, false) + ok, failures, err = runtime.Prune(ctx, rmWorkers, false, []string{}) if err != nil { if lasterr != nil { logrus.Errorf("%q", err) diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index e76b9627e..a3fd27ed6 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -536,6 +536,10 @@ method GetVersion() -> ( remote_api_version: int ) +# Reset resets Podman back to its initial state. +# Removes all Pods, Containers, Images and Volumes +method Reset() -> () + # GetInfo returns a [PodmanInfo](#PodmanInfo) struct that describes podman and its host such as storage stats, # build information of Podman, and system-wide registries. method GetInfo() -> (info: PodmanInfo) diff --git a/cmd/podman/version.go b/cmd/podman/version.go index 314b2e266..5907241ff 100644 --- a/cmd/podman/version.go +++ b/cmd/podman/version.go @@ -37,13 +37,40 @@ func init() { flags := versionCommand.Flags() flags.StringVarP(&versionCommand.Format, "format", "f", "", "Change the output format to JSON or a Go template") } +func getRemoteVersion(c *cliconfig.VersionValues) (version define.Version, err error) { + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) + if err != nil { + return version, errors.Wrapf(err, "could not get runtime") + } + defer runtime.DeferredShutdown(false) + + return runtime.GetVersion() +} + +type versionStruct struct { + Client define.Version + Server define.Version +} // versionCmd gets and prints version info for version command func versionCmd(c *cliconfig.VersionValues) error { - clientVersion, err := define.GetVersion() + + var ( + v versionStruct + err error + ) + v.Client, err = define.GetVersion() if err != nil { return errors.Wrapf(err, "unable to determine version") } + if remote { + v.Server, err = getRemoteVersion(c) + if err != nil { + return err + } + } else { + v.Server = v.Client + } versionOutputFormat := c.Format if versionOutputFormat != "" { @@ -53,11 +80,20 @@ func versionCmd(c *cliconfig.VersionValues) error { var out formats.Writer switch versionOutputFormat { case formats.JSONString: - out = formats.JSONStruct{Output: clientVersion} + out = formats.JSONStruct{Output: v} + return out.Out() default: - out = formats.StdoutTemplate{Output: clientVersion, Template: versionOutputFormat} + out = formats.StdoutTemplate{Output: v, Template: versionOutputFormat} + err := out.Out() + if err != nil { + // On Failure, assume user is using older version of podman version --format and check client + out = formats.StdoutTemplate{Output: v.Client, Template: versionOutputFormat} + if err1 := out.Out(); err1 != nil { + return err + } + } } - return out.Out() + return nil } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) defer w.Flush() @@ -66,25 +102,13 @@ func versionCmd(c *cliconfig.VersionValues) error { if _, err := fmt.Fprintf(w, "Client:\n"); err != nil { return err } - } - formatVersion(w, clientVersion) - - if remote { - if _, err := fmt.Fprintf(w, "\nService:\n"); err != nil { - return err - } - - runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) - if err != nil { - return errors.Wrapf(err, "could not get runtime") - } - defer runtime.DeferredShutdown(false) - - serviceVersion, err := runtime.GetVersion() - if err != nil { + formatVersion(w, v.Client) + if _, err := fmt.Fprintf(w, "\nServer:\n"); err != nil { return err } - formatVersion(w, serviceVersion) + formatVersion(w, v.Server) + } else { + formatVersion(w, v.Client) } return nil } diff --git a/commands.md b/commands.md index c035b011f..de9169a4b 100644 --- a/commands.md +++ b/commands.md @@ -6,89 +6,95 @@ | Command | Description | Demo | Script | | :----------------------------------------------------------------------- | :------------------------------------------------------------------------- | :-------------------------------------------------------------------------- | :---------------------------------------------------------------------------------- | -| [podman(1)](/docs/podman.1.md) | Simple management tool for pods and images | -| [podman-attach(1)](/docs/podman-attach.1.md) | Attach to a running container | -| [podman-build(1)](/docs/podman-build.1.md) | Build an image using instructions from Dockerfiles | -| [podman-commit(1)](/docs/podman-commit.1.md) | Create new image based on the changed container | -| [podman-container(1)](/docs/podman-container.1.md) | Manage Containers | -| [podman-container-checkpoint(1)](/docs/podman-container-checkpoint.1.md) | Checkpoints one or more running containers | -| [podman-container-cleanup(1)](/docs/podman-container-cleanup.1.md) | Cleanup Container storage and networks | -| [podman-container-exists(1)](/docs/podman-container-exists.1.md) | Check if an container exists in local storage | -| [podman-container-prune(1)](/docs/podman-container-prune.1.md) | Remove all stopped containers | -| [podman-container-refresh(1)](/docs/podman-container-refresh.1.md) | Refresh all containers state in database | -| [podman-container-restore(1)](/docs/podman-container-restore.1.md) | Restores one or more running containers | -| [podman-container-runlabel(1)](/docs/podman-container-runlabel.1.md) | Execute Image Label Method | -| [podman-cp(1)](/docs/podman-cp.1.md) | Copy files/folders between a container and the local filesystem | -| [podman-create(1)](/docs/podman-create.1.md) | Create a new container | -| [podman-diff(1)](/docs/podman-diff.1.md) | Inspect changes on a container or image's filesystem | -| [podman-events(1)](/docs/podman-events.1.md) | Monitor Podman events | -| [podman-exec(1)](/docs/podman-exec.1.md) | Execute a command in a running container | -| [podman-export(1)](/docs/podman-export.1.md) | Export container's filesystem contents as a tar archive | -| [podman-generate(1)](/docs/podman-generate.1.md) | Generate structured output based on Podman containers and pods | -| [podman-generate-kube(1)](/docs/podman-generate-kube.1.md) | Generate Kubernetes YAML based on a container or Pod | -| [podman-generate-systemd(1)](/docs/podman-generate-systemd.1.md) | Generate a Systemd unit file for a container | -| [podman-history(1)](/docs/podman-history.1.md) | Shows the history of an image | -| [podman-image(1)](/docs/podman-image.1.md) | Manage Images | -| [podman-image-exists(1)](/docs/podman-image-exists.1.md) | Check if an image exists in local storage | -| [podman-image-prune(1)](/docs/podman-image-prune.1.md) | Remove all unused images | -| [podman-image-sign(1)](/docs/podman-image-sign.1.md) | Create a signature for an image | -| [podman-image-trust(1)](/docs/podman-image-trust.1.md) | Manage container registry image trust policy | -| [podman-images(1)](/docs/podman-images.1.md) | List images in local storage | [![...](/docs/play.png)](https://podman.io/asciinema/podman/images/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_images.sh) | -| [podman-import(1)](/docs/podman-import.1.md) | Import a tarball and save it as a filesystem image | -| [podman-info(1)](/docs/podman-info.1.md) | Display system information | -| [podman-init(1)](/docs/podman-init.1.md) | Initialize a container | -| [podman-inspect(1)](/docs/podman-inspect.1.md) | Display the configuration of a container or image | [![...](/docs/play.png)](https://asciinema.org/a/133418) | -| [podman-kill(1)](/docs/podman-kill.1.md) | Kill the main process in one or more running containers | -| [podman-load(1)](/docs/podman-load.1.md) | Load an image from a container image archive | -| [podman-login(1)](/docs/podman-login.1.md) | Login to a container registry | -| [podman-logout(1)](/docs/podman-logout.1.md) | Logout of a container registry | -| [podman-logs(1)](/docs/podman-logs.1.md) | Display the logs of a container | -| [podman-mount(1)](/docs/podman-mount.1.md) | Mount a working container's root filesystem | -| [podman-network(1)](/docs/podman-network.1.md) | Manage Podman CNI networks | -| [podman-network-create(1)](/docs/podman-network-create.1.md) | Create a CNI network | -| [podman-network-inspect(1)](/docs/podman-network-inspect.1.md) | Inspect one or more Podman networks | -| [podman-network-ls(1)](/docs/podman-network-ls.1.md) | Display a summary of Podman networks | -| [podman-network-rm(1)](/docs/podman-network-rm.1.md) | Remove one or more Podman networks | -| [podman-pause(1)](/docs/podman-pause.1.md) | Pause one or more running containers | [![...](/docs/play.png)](https://podman.io/asciinema/podman/pause_unpause/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_pause_unpause.sh) | -| [podman-play(1)](/docs/podman-play.1.md) | Play pods and containers based on a structured input file | -| [podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods | -| [podman-pod-create(1)](/docs/podman-pod-create.1.md) | Create a new pod | -| [podman-pod-inspect(1)](/docs/podman-pod-inspect.1.md) | Inspect a pod | +| [podman(1)](/docs/source/markdown/podman.1.md) | Simple management tool for pods and images | +| [podman-attach(1)](/docs/source/markdown/podman-attach.1.md) | Attach to a running container | +| [podman-build(1)](/docs/source/markdown/podman-build.1.md) | Build an image using instructions from Dockerfiles | +| [podman-commit(1)](/docs/source/markdown/podman-commit.1.md) | Create new image based on the changed container | +| [podman-container(1)](/docs/source/markdown/podman-container.1.md) | Manage Containers | +| [podman-container-checkpoint(1)](/docs/source/markdown/podman-container-checkpoint.1.md) | Checkpoints one or more running containers | +| [podman-container-cleanup(1)](/docs/source/markdown/podman-container-cleanup.1.md) | Cleanup Container storage and networks | +| [podman-container-exists(1)](/docs/source/markdown/podman-container-exists.1.md) | Check if an container exists in local storage | +| [podman-container-prune(1)](/docs/source/markdown/podman-container-prune.1.md) | Remove all stopped containers | +| [podman-container-refresh(1)](/docs/source/markdown/podman-container-refresh.1.md) | Refresh all containers state in database | +| [podman-container-restore(1)](/docs/source/markdown/podman-container-restore.1.md) | Restores one or more running containers | +| [podman-container-runlabel(1)](/docs/source/markdown/podman-container-runlabel.1.md) | Execute Image Label Method | +| [podman-cp(1)](/docs/source/markdown/podman-cp.1.md) | Copy files/folders between a container and the local filesystem | +| [podman-create(1)](/docs/source/markdown/podman-create.1.md) | Create a new container | +| [podman-diff(1)](/docs/source/markdown/podman-diff.1.md) | Inspect changes on a container or image's filesystem | +| [podman-events(1)](/docs/source/markdown/podman-events.1.md) | Monitor Podman events | +| [podman-exec(1)](/docs/source/markdown/podman-exec.1.md) | Execute a command in a running container | +| [podman-export(1)](/docs/source/markdown/podman-export.1.md) | Export container's filesystem contents as a tar archive | +| [podman-generate(1)](/docs/source/markdown/podman-generate.1.md) | Generate structured output based on Podman containers and pods | +| [podman-generate-kube(1)](/docs/source/markdown/podman-generate-kube.1.md) | Generate Kubernetes YAML based on a container or Pod | +| [podman-generate-systemd(1)](/docs/source/markdown/podman-generate-systemd.1.md) | Generate a Systemd unit file for a container | +| [podman-history(1)](/docs/source/markdown/podman-history.1.md) | Shows the history of an image | +| [podman-image(1)](/docs/source/markdown/podman-image.1.md) | Manage Images | +| [podman-image-exists(1)](/docs/source/markdown/podman-image-exists.1.md) | Check if an image exists in local storage | +| [podman-image-prune(1)](/docs/source/markdown/podman-image-prune.1.md) | Remove all unused images | +| [podman-image-sign(1)](/docs/source/markdown/podman-image-sign.1.md) | Create a signature for an image | +| [podman-image-trust(1)](/docs/source/markdown/podman-image-trust.1.md) | Manage container registry image trust policy | +| [podman-images(1)](/docs/source/markdown/podman-images.1.md) | List images in local storage | [![...](/docs/source/markdown/play.png)](https://podman.io/asciinema/podman/images/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_images.sh) | +| [podman-import(1)](/docs/source/markdown/podman-import.1.md) | Import a tarball and save it as a filesystem image | +| [podman-info(1)](/docs/source/markdown/podman-info.1.md) | Display system information | +| [podman-init(1)](/docs/source/markdown/podman-init.1.md) | Initialize a container | +| [podman-inspect(1)](/docs/source/markdown/podman-inspect.1.md) | Display the configuration of a container or image | [![...](/docs/source/markdown/play.png)](https://asciinema.org/a/133418) | +| [podman-kill(1)](/docs/source/markdown/podman-kill.1.md) | Kill the main process in one or more running containers | +| [podman-load(1)](/docs/source/markdown/podman-load.1.md) | Load an image from a container image archive | +| [podman-login(1)](/docs/source/markdown/podman-login.1.md) | Login to a container registry | +| [podman-logout(1)](/docs/source/markdown/podman-logout.1.md) | Logout of a container registry | +| [podman-logs(1)](/docs/source/markdown/podman-logs.1.md) | Display the logs of a container | +| [podman-mount(1)](/docs/source/markdown/podman-mount.1.md) | Mount a working container's root filesystem | +| [podman-network(1)](/docs/source/markdown/podman-network.1.md) | Manage Podman CNI networks | +| [podman-network-create(1)](/docs/source/markdown/podman-network-create.1.md) | Create a CNI network | +| [podman-network-inspect(1)](/docs/source/markdown/podman-network-inspect.1.md) | Inspect one or more Podman networks | +| [podman-network-ls(1)](/docs/source/markdown/podman-network-ls.1.md) | Display a summary of Podman networks | +| [podman-network-rm(1)](/docs/source/markdown/podman-network-rm.1.md) | Remove one or more Podman networks | +| [podman-pause(1)](/docs/source/markdown/podman-pause.1.md) | Pause one or more running containers | [![...](/docs/source/markdown/play.png)](https://podman.io/asciinema/podman/pause_unpause/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_pause_unpause.sh) | +| [podman-play(1)](/docs/source/markdown/podman-play.1.md) | Play pods and containers based on a structured input file | +| [podman-pod(1)](/docs/source/markdown/podman-pod.1.md) | Simple management tool for groups of containers, called pods | +| [podman-pod-create(1)](/docs/source/markdown/podman-pod-create.1.md) | Create a new pod | +| [podman-pod-inspect(1)](/docs/source/markdown/podman-pod-inspect.1.md) | Inspect a pod | | [podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in pod. | -| [podman-pod-ps(1)](/docs/podman-pod-ps.1.md) | List the pods on the system | +| [podman-pod-ps(1)](/docs/source/markdown/podman-pod-ps.1.md) | List the pods on the system | | [podman-pod-pause(1)](podman-pod-pause.1.md) | Pause one or more pods. | -| [podman-pod-restart](/docs/podman-pod-restart.1.md) | Restart one or more pods | -| [podman-pod-rm(1)](/docs/podman-pod-rm.1.md) | Remove one or more pods | -| [podman-pod-start(1)](/docs/podman-pod-start.1.md) | Start one or more pods | -| [podman-pod-stats(1)](/docs/podman-pod-stats.1.md) | Display a live stream of one or more pods' resource usage statistics | | | -| [podman-pod-stop(1)](/docs/podman-pod-stop.1.md) | Stop one or more pods | -| [podman-pod-top(1)](/docs/podman-pod-top.1.md) | Display the running processes of a pod | +| [podman-pod-restart](/docs/source/markdown/podman-pod-restart.1.md) | Restart one or more pods | +| [podman-pod-rm(1)](/docs/source/markdown/podman-pod-rm.1.md) | Remove one or more pods | +| [podman-pod-start(1)](/docs/source/markdown/podman-pod-start.1.md) | Start one or more pods | +| [podman-pod-stats(1)](/docs/source/markdown/podman-pod-stats.1.md) | Display a live stream of one or more pods' resource usage statistics | | | +| [podman-pod-stop(1)](/docs/source/markdown/podman-pod-stop.1.md) | Stop one or more pods | +| [podman-pod-top(1)](/docs/source/markdown/podman-pod-top.1.md) | Display the running processes of a pod | | [podman-pod-unpause(1)](podman-pod-unpause.1.md) | Unpause one or more pods. | -| [podman-port(1)](/docs/podman-port.1.md) | List port mappings for running containers | -| [podman-ps(1)](/docs/podman-ps.1.md) | Prints out information about containers | -| [podman-pull(1)](/docs/podman-pull.1.md) | Pull an image from a registry | -| [podman-push(1)](/docs/podman-push.1.md) | Push an image to a specified destination | [![...](/docs/play.png)](https://asciinema.org/a/133276) | -| [podman-restart](/docs/podman-restart.1.md) | Restarts one or more containers | [![...](/docs/play.png)](https://asciinema.org/a/jiqxJAxcVXw604xdzMLTkQvHM) | -| [podman-rm(1)](/docs/podman-rm.1.md) | Removes one or more containers | -| [podman-rmi(1)](/docs/podman-rmi.1.md) | Removes one or more images | -| [podman-run(1)](/docs/podman-run.1.md) | Run a command in a container | -| [podman-save(1)](/docs/podman-save.1.md) | Saves an image to an archive | -| [podman-search(1)](/docs/podman-search.1.md) | Search a registry for an image | -| [podman-start(1)](/docs/podman-start.1.md) | Starts one or more containers | -| [podman-stats(1)](/docs/podman-stats.1.md) | Display a live stream of one or more containers' resource usage statistics | -| [podman-stop(1)](/docs/podman-stop.1.md) | Stops one or more running containers | -| [podman-system(1)](/docs/podman-system.1.md) | Manage podman | -| [podman-tag(1)](/docs/podman-tag.1.md) | Add an additional name to a local image | [![...](/docs/play.png)](https://asciinema.org/a/133803) | -| [podman-top(1)](/docs/podman-top.1.md) | Display the running processes of a container | -| [podman-umount(1)](/docs/podman-umount.1.md) | Unmount a working container's root filesystem | -| [podman-unpause(1)](/docs/podman-unpause.1.md) | Unpause one or more running containers | [![...](/docs/play.png)](https://podman.io/asciinema/podman/pause_unpause/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_pause_unpause.sh) | -| [podman-unshare(1)](/docs/podman-unshare.1.md) | Run a command inside of a modified user namespace. | -| [podman-varlink(1)](/docs/podman-varlink.1.md) | Run the varlink backend | -| [podman-version(1)](/docs/podman-version.1.md) | Display the version information | -| [podman-volume(1)](/docs/podman-volume.1.md) | Manage Volumes | -| [podman-volume-create(1)](/docs/podman-volume-create.1.md) | Create a volume | -| [podman-volume-inspect(1)](/docs/podman-volume-inspect.1.md) | Get detailed information on one or more volumes | -| [podman-volume-ls(1)](/docs/podman-volume-ls.1.md) | List all the available volumes | -| [podman-volume-rm(1)](/docs/podman-volume-rm.1.md) | Remove one or more volumes | -| [podman-volume-prune(1)](/docs/podman-volume-prune.1.md) | Remove all unused volumes | -| [podman-wait(1)](/docs/podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes | +| [podman-port(1)](/docs/source/markdown/podman-port.1.md) | List port mappings for running containers | +| [podman-ps(1)](/docs/source/markdown/podman-ps.1.md) | Prints out information about containers | +| [podman-pull(1)](/docs/source/markdown/podman-pull.1.md) | Pull an image from a registry | +| [podman-push(1)](/docs/source/markdown/podman-push.1.md) | Push an image to a specified destination | [![...](/docs/source/markdown/play.png)](https://asciinema.org/a/133276) | +| [podman-restart](/docs/source/markdown/podman-restart.1.md) | Restarts one or more containers | [![...](/docs/source/markdown/play.png)](https://asciinema.org/a/jiqxJAxcVXw604xdzMLTkQvHM) | +| [podman-rm(1)](/docs/source/markdown/podman-rm.1.md) | Removes one or more containers | +| [podman-rmi(1)](/docs/source/markdown/podman-rmi.1.md) | Removes one or more images | +| [podman-run(1)](/docs/source/markdown/podman-run.1.md) | Run a command in a container | +| [podman-save(1)](/docs/source/markdown/podman-save.1.md) | Saves an image to an archive | +| [podman-search(1)](/docs/source/markdown/podman-search.1.md) | Search a registry for an image | +| [podman-start(1)](/docs/source/markdown/podman-start.1.md) | Starts one or more containers | +| [podman-stats(1)](/docs/source/markdown/podman-stats.1.md) | Display a live stream of one or more containers' resource usage statistics | +| [podman-stop(1)](/docs/source/markdown/podman-stop.1.md) | Stops one or more running containers | +| [podman-system(1)](/docs/source/markdown/podman-system.1.md) | Manage podman | +| [podman-system-df(1)](/docs/source/markdown/podman-system-df.1.md) | Show podman disk usage. | +| [podman-system-info(1)](/docs/source/markdown/podman-info.1.md) | Displays Podman related system information. | +| [podman-system-migrate(1)](/docs/source/markdown/podman-system-migrate.1.md) | Migrate existing containers to a new podman version. | +| [podman-system-prune(1)](/docs/source/markdown/podman-system-prune.1.md) | Remove all unused container, image and volume data. | +| [podman-system-renumber(1)](/docs/source/markdown/podman-system-renumber.1.md) | Migrate lock numbers to handle a change in maximum number of locks. | +| [podman-system-reset(1)](/docs/source/markdown/podman-system-reset.1.md) | Reset storage back to original state. Remove all pods, containers, images, volumes. | +| [podman-tag(1)](/docs/source/markdown/podman-tag.1.md) | Add an additional name to a local image | [![...](/docs/source/markdown/play.png)](https://asciinema.org/a/133803) | +| [podman-top(1)](/docs/source/markdown/podman-top.1.md) | Display the running processes of a container | +| [podman-umount(1)](/docs/source/markdown/podman-umount.1.md) | Unmount a working container's root filesystem | +| [podman-unpause(1)](/docs/source/markdown/podman-unpause.1.md) | Unpause one or more running containers | [![...](/docs/source/markdown/play.png)](https://podman.io/asciinema/podman/pause_unpause/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_pause_unpause.sh) | +| [podman-unshare(1)](/docs/source/markdown/podman-unshare.1.md) | Run a command inside of a modified user namespace. | +| [podman-varlink(1)](/docs/source/markdown/podman-varlink.1.md) | Run the varlink backend | +| [podman-version(1)](/docs/source/markdown/podman-version.1.md) | Display the version information | +| [podman-volume(1)](/docs/source/markdown/podman-volume.1.md) | Manage Volumes | +| [podman-volume-create(1)](/docs/source/markdown/podman-volume-create.1.md) | Create a volume | +| [podman-volume-inspect(1)](/docs/source/markdown/podman-volume-inspect.1.md) | Get detailed information on one or more volumes | +| [podman-volume-ls(1)](/docs/source/markdown/podman-volume-ls.1.md) | List all the available volumes | +| [podman-volume-rm(1)](/docs/source/markdown/podman-volume-rm.1.md) | Remove one or more volumes | +| [podman-volume-prune(1)](/docs/source/markdown/podman-volume-prune.1.md) | Remove all unused volumes | +| [podman-wait(1)](/docs/source/markdown/podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes | diff --git a/completions/bash/podman b/completions/bash/podman index 6d145030f..18e2460ec 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1142,6 +1142,21 @@ _podman_container() { esac } +_podman_system_reset() { + local options_with_args=" + " + local boolean_options=" + -h + --help + --force + " + case "$cur" in + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + esac +} + _podman_system_df() { local options_with_args=" --format @@ -1193,6 +1208,7 @@ _podman_system() { df info prune + reset " __podman_subcommands "$subcommands" && return @@ -2816,9 +2832,12 @@ _podman_images_prune() { _podman_container_prune() { local options_with_args=" + --filter " local boolean_options=" + -f + --force -h --help " diff --git a/docs/source/markdown/podman-container-prune.1.md b/docs/source/markdown/podman-container-prune.1.md index d8a4b7f4e..856843a80 100644 --- a/docs/source/markdown/podman-container-prune.1.md +++ b/docs/source/markdown/podman-container-prune.1.md @@ -20,6 +20,8 @@ Print usage statement Remove all stopped containers from local storage ``` $ sudo podman container prune +WARNING! This will remove all stopped containers. +Are you sure you want to continue? [y/N] y 878392adf2e6c5c9bb1fc19b69d37d2e98c8abf9d539c0bce4b15b46bbcce471 37664467fbe3618bf9479c34393ac29c02696675addf1750f9e346581636cde7 ed0c6468b8e1cb641b4621d1fe30cb477e1fefc5c0bceb66feaf2f7cb50e5962 @@ -28,6 +30,26 @@ fff1c5b6c3631746055ec40598ce8ecaa4b82aef122f9e3a85b03b55c0d06c23 602d343cd47e7cb3dfc808282a9900a3e4555747787ec6723bb68cedab8384d5 ``` +Remove all stopped containers from local storage without confirmation. +``` +$ sudo podman container prune -f +878392adf2e6c5c9bb1fc19b69d37d2e98c8abf9d539c0bce4b15b46bbcce471 +37664467fbe3618bf9479c34393ac29c02696675addf1750f9e346581636cde7 +ed0c6468b8e1cb641b4621d1fe30cb477e1fefc5c0bceb66feaf2f7cb50e5962 +6ac6c8f0067b7a4682e6b8e18902665b57d1a0e07e885d9abcd382232a543ccd +fff1c5b6c3631746055ec40598ce8ecaa4b82aef122f9e3a85b03b55c0d06c23 +602d343cd47e7cb3dfc808282a9900a3e4555747787ec6723bb68cedab8384d5 + +``` + +Remove all stopped containers from local storage created within last 10 minutes +``` +$ sudo podman container prune --filter until="10m" +WARNING! This will remove all stopped containers. +Are you sure you want to continue? [y/N] y +3d366295e33d8cc612c4d873199bacadd55088d90d17dcafaa9a2d317ad50b4e +``` + ## SEE ALSO podman(1), podman-ps diff --git a/docs/source/markdown/podman-system-reset.1.md b/docs/source/markdown/podman-system-reset.1.md new file mode 100644 index 000000000..432f275f4 --- /dev/null +++ b/docs/source/markdown/podman-system-reset.1.md @@ -0,0 +1,25 @@ +% podman-system-reset(1) + +## NAME +podman\-system\-reset - Reset storage back to initial state + +## SYNOPSIS +**podman system reset** + +## DESCRIPTION +**podman system reset** removes all pods, containers, images and volumes. + +## OPTIONS +**--force**, **-f** + +Do not prompt for confirmation + +**--help**, **-h** + +Print usage statement + +## SEE ALSO +`podman(1)`, `podman-system(1)` + +## HISTORY +November 2019, Originally compiled by Dan Walsh (dwalsh at redhat dot com) diff --git a/docs/source/markdown/podman-system.1.md b/docs/source/markdown/podman-system.1.md index bbd541066..1af97290d 100644 --- a/docs/source/markdown/podman-system.1.md +++ b/docs/source/markdown/podman-system.1.md @@ -15,9 +15,10 @@ The system command allows you to manage the podman systems | ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- | | df | [podman-system-df(1)](podman-system-df.1.md) | Show podman disk usage. | | info | [podman-system-info(1)](podman-info.1.md) | Displays Podman related system information. | -| prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused container, image and volume data | -| renumber | [podman-system-renumber(1)](podman-system-renumber.1.md)| Migrate lock numbers to handle a change in maximum number of locks. | | migrate | [podman-system-migrate(1)](podman-system-migrate.1.md)| Migrate existing containers to a new podman version. | +| prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused container, image and volume data. | +| renumber | [podman-system-renumber(1)](podman-system-renumber.1.md)| Migrate lock numbers to handle a change in maximum number of locks. | +| reset | [podman-system-reset(1)](podman-system-reset.1.md) | Reset storage back to initial state. | ## SEE ALSO podman(1) diff --git a/docs/source/markdown/podman-version.1.md b/docs/source/markdown/podman-version.1.md index 4499f6338..de22c4800 100644 --- a/docs/source/markdown/podman-version.1.md +++ b/docs/source/markdown/podman-version.1.md @@ -34,8 +34,8 @@ OS/Arch: linux/amd64 Filtering out only the version: ``` -$ podman version --format '{{.Version}}' -0.11.2 +$ podman version --format '{{.Client.Version}}' +1.6.3 ``` ## SEE ALSO diff --git a/install.md b/install.md index 39b639176..bd3732083 100644 --- a/install.md +++ b/install.md @@ -68,7 +68,7 @@ The latest builds are available in a PPA. Take note of the [Build and Run Depend ```bash sudo apt-get update -qq -sudo apt-get install -qq -y software-properties-common uidmap +sudo apt-get install -qq -y software-properties-common uidmap slirp4netns sudo add-apt-repository -y ppa:projectatomic/ppa sudo apt-get update -qq sudo apt-get -qq -y install podman diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go index 09a9be606..6ccda71bd 100644 --- a/libpod/boltdb_state_linux.go +++ b/libpod/boltdb_state_linux.go @@ -3,6 +3,8 @@ package libpod import ( + "github.com/containers/libpod/libpod/define" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -25,8 +27,12 @@ func replaceNetNS(netNSPath string, ctr *Container, newState *ContainerState) er if err == nil { newState.NetNS = ns } else { + if ctr.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) { + return errors.Wrapf(err, "error joning network namespace of container %s", ctr.ID()) + } + logrus.Errorf("error joining network namespace for container %s: %v", ctr.ID(), err) - ctr.valid = false + ctr.state.NetNS = nil } } } else { diff --git a/libpod/container_api.go b/libpod/container_api.go index b8cfe02f6..153a1d628 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -404,6 +404,11 @@ func (c *Container) Mount() (string, error) { return "", err } } + + if c.state.State == define.ContainerStateRemoving { + return "", errors.Wrapf(define.ErrCtrStateInvalid, "cannot mount container %s as it is being removed", c.ID()) + } + defer c.newContainerEvent(events.Mount) return c.mount() } @@ -488,7 +493,12 @@ func (c *Container) Export(path string) error { return err } } - defer c.newContainerEvent(events.Export) + + if c.state.State == define.ContainerStateRemoving { + return errors.Wrapf(define.ErrCtrStateInvalid, "cannot mount container %s as it is being removed", c.ID()) + } + + defer c.newContainerEvent(events.Mount) return c.export(path) } @@ -674,6 +684,10 @@ func (c *Container) Refresh(ctx context.Context) error { } } + if c.state.State == define.ContainerStateRemoving { + return errors.Wrapf(define.ErrCtrStateInvalid, "cannot refresh containers that are being removed") + } + wasCreated := false if c.state.State == define.ContainerStateCreated { wasCreated = true @@ -819,7 +833,6 @@ func (c *Container) Checkpoint(ctx context.Context, options ContainerCheckpointO return err } } - defer c.newContainerEvent(events.Checkpoint) return c.checkpoint(ctx, options) } diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 4ff1913b5..1e8a8a580 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -719,7 +719,8 @@ func (c *Container) isStopped() (bool, error) { if err != nil { return true, err } - return c.state.State != define.ContainerStateRunning && c.state.State != define.ContainerStatePaused, nil + + return !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused), nil } // save container state to the database @@ -1057,6 +1058,8 @@ func (c *Container) initAndStart(ctx context.Context) (err error) { // If we are ContainerStateUnknown, throw an error if c.state.State == define.ContainerStateUnknown { return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is in an unknown state", c.ID()) + } else if c.state.State == define.ContainerStateRemoving { + return errors.Wrapf(define.ErrCtrStateInvalid, "cannot start container %s as it is being removed", c.ID()) } // If we are running, do nothing diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index f051f40e9..586de0776 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -21,6 +21,7 @@ import ( "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/buildah/pkg/secrets" "github.com/containers/libpod/libpod/define" + "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/pkg/annotations" "github.com/containers/libpod/pkg/apparmor" "github.com/containers/libpod/pkg/cgroups" @@ -699,6 +700,8 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO return err } + defer c.newContainerEvent(events.Checkpoint) + if options.TargetFile != "" { if err = c.exportCheckpoint(options.TargetFile, options.IgnoreRootfs); err != nil { return err @@ -770,7 +773,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti return err } - if (c.state.State != define.ContainerStateConfigured) && (c.state.State != define.ContainerStateExited) { + if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateExited) { return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is running or paused, cannot restore", c.ID()) } diff --git a/libpod/define/containerstate.go b/libpod/define/containerstate.go index ab2527b3e..e7d258e21 100644 --- a/libpod/define/containerstate.go +++ b/libpod/define/containerstate.go @@ -25,6 +25,9 @@ const ( // ContainerStateExited indicates the the container has stopped and been // cleaned up ContainerStateExited ContainerStatus = iota + // ContainerStateRemoving indicates the container is in the process of + // being removed. + ContainerStateRemoving ContainerStatus = iota ) // ContainerStatus returns a string representation for users @@ -45,6 +48,8 @@ func (t ContainerStatus) String() string { return "paused" case ContainerStateExited: return "exited" + case ContainerStateRemoving: + return "removing" } return "bad state" } @@ -67,6 +72,8 @@ func StringToContainerStatus(status string) (ContainerStatus, error) { return ContainerStatePaused, nil case ContainerStateExited.String(): return ContainerStateExited, nil + case ContainerStateRemoving.String(): + return ContainerStateRemoving, nil default: return ContainerStateUnknown, errors.Wrapf(ErrInvalidArg, "unknown container state: %s", status) } diff --git a/libpod/oci_util.go b/libpod/oci_util.go index 3345220ac..53567d2d0 100644 --- a/libpod/oci_util.go +++ b/libpod/oci_util.go @@ -82,18 +82,16 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) { } func getOCIRuntimeError(runtimeMsg string) error { - r := strings.ToLower(runtimeMsg) - includeFullOutput := logrus.GetLevel() == logrus.DebugLevel - if match := regexp.MustCompile(".*permission denied.*|.*operation not permitted.*").FindString(r); match != "" { + if match := regexp.MustCompile("(?i).*permission denied.*|.*operation not permitted.*").FindString(runtimeMsg); match != "" { errStr := match if includeFullOutput { errStr = runtimeMsg } return errors.Wrapf(define.ErrOCIRuntimePermissionDenied, "%s", strings.Trim(errStr, "\n")) } - if match := regexp.MustCompile(".*executable file not found in.*|.*no such file or directory.*").FindString(r); match != "" { + if match := regexp.MustCompile("(?i).*executable file not found in.*|.*no such file or directory.*").FindString(runtimeMsg); match != "" { errStr := match if includeFullOutput { errStr = runtimeMsg diff --git a/libpod/options.go b/libpod/options.go index f7f14eb26..a9b775dc3 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -768,16 +768,8 @@ func WithIPCNSFrom(nsCtr *Container) CtrCreateOption { return define.ErrCtrFinalized } - if !nsCtr.valid { - return define.ErrCtrRemoved - } - - if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(define.ErrInvalidArg, "must specify another container") - } - - if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + if err := checkDependencyContainer(nsCtr, ctr); err != nil { + return err } ctr.config.IPCNsCtr = nsCtr.ID() @@ -796,16 +788,8 @@ func WithMountNSFrom(nsCtr *Container) CtrCreateOption { return define.ErrCtrFinalized } - if !nsCtr.valid { - return define.ErrCtrRemoved - } - - if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(define.ErrInvalidArg, "must specify another container") - } - - if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + if err := checkDependencyContainer(nsCtr, ctr); err != nil { + return err } ctr.config.MountNsCtr = nsCtr.ID() @@ -824,22 +808,14 @@ func WithNetNSFrom(nsCtr *Container) CtrCreateOption { return define.ErrCtrFinalized } - if !nsCtr.valid { - return define.ErrCtrRemoved - } - - if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(define.ErrInvalidArg, "must specify another container") + if err := checkDependencyContainer(nsCtr, ctr); err != nil { + return err } if ctr.config.CreateNetNS { return errors.Wrapf(define.ErrInvalidArg, "cannot join another container's net ns as we are making a new net ns") } - if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) - } - ctr.config.NetNsCtr = nsCtr.ID() return nil @@ -856,16 +832,8 @@ func WithPIDNSFrom(nsCtr *Container) CtrCreateOption { return define.ErrCtrFinalized } - if !nsCtr.valid { - return define.ErrCtrRemoved - } - - if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(define.ErrInvalidArg, "must specify another container") - } - - if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + if err := checkDependencyContainer(nsCtr, ctr); err != nil { + return err } if ctr.config.NoCgroups { @@ -888,16 +856,8 @@ func WithUserNSFrom(nsCtr *Container) CtrCreateOption { return define.ErrCtrFinalized } - if !nsCtr.valid { - return define.ErrCtrRemoved - } - - if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(define.ErrInvalidArg, "must specify another container") - } - - if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + if err := checkDependencyContainer(nsCtr, ctr); err != nil { + return err } ctr.config.UserNsCtr = nsCtr.ID() @@ -917,16 +877,8 @@ func WithUTSNSFrom(nsCtr *Container) CtrCreateOption { return define.ErrCtrFinalized } - if !nsCtr.valid { - return define.ErrCtrRemoved - } - - if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(define.ErrInvalidArg, "must specify another container") - } - - if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + if err := checkDependencyContainer(nsCtr, ctr); err != nil { + return err } ctr.config.UTSNsCtr = nsCtr.ID() @@ -945,16 +897,8 @@ func WithCgroupNSFrom(nsCtr *Container) CtrCreateOption { return define.ErrCtrFinalized } - if !nsCtr.valid { - return define.ErrCtrRemoved - } - - if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(define.ErrInvalidArg, "must specify another container") - } - - if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + if err := checkDependencyContainer(nsCtr, ctr); err != nil { + return err } ctr.config.CgroupNsCtr = nsCtr.ID() diff --git a/libpod/reset.go b/libpod/reset.go new file mode 100644 index 000000000..a35b476a4 --- /dev/null +++ b/libpod/reset.go @@ -0,0 +1,107 @@ +package libpod + +import ( + "context" + "os" + "path/filepath" + + "github.com/containers/libpod/libpod/define" + "github.com/containers/libpod/pkg/rootless" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// Reset removes all storage +func (r *Runtime) Reset(ctx context.Context) error { + + pods, err := r.GetAllPods() + if err != nil { + return err + } + for _, p := range pods { + if err := r.RemovePod(ctx, p, true, true); err != nil { + if errors.Cause(err) == define.ErrNoSuchPod { + continue + } + logrus.Errorf("Error removing Pod %s: %v", p.ID(), err) + } + } + + ctrs, err := r.GetAllContainers() + if err != nil { + return err + } + + for _, c := range ctrs { + if err := r.RemoveContainer(ctx, c, true, true); err != nil { + if err := r.RemoveStorageContainer(c.ID(), true); err != nil { + if errors.Cause(err) == define.ErrNoSuchCtr { + continue + } + logrus.Errorf("Error removing container %s: %v", c.ID(), err) + } + } + } + + if err := stopPauseProcess(); err != nil { + logrus.Errorf("Error stopping pause process: %v", err) + } + + ir := r.ImageRuntime() + images, err := ir.GetImages() + if err != nil { + return err + } + + for _, i := range images { + if err := i.Remove(ctx, true); err != nil { + if errors.Cause(err) == define.ErrNoSuchImage { + continue + } + logrus.Errorf("Error removing image %s: %v", i.ID(), err) + } + } + volumes, err := r.state.AllVolumes() + if err != nil { + return err + } + for _, v := range volumes { + if err := r.RemoveVolume(ctx, v, true); err != nil { + if errors.Cause(err) == define.ErrNoSuchVolume { + continue + } + logrus.Errorf("Error removing volume %s: %v", v.config.Name, err) + } + } + + _, prevError := r.store.Shutdown(true) + if err := os.RemoveAll(r.store.GraphRoot()); err != nil { + if prevError != nil { + logrus.Error(prevError) + } + prevError = err + } + if err := os.RemoveAll(r.store.RunRoot()); err != nil { + if prevError != nil { + logrus.Error(prevError) + } + prevError = err + } + if err := os.RemoveAll(r.config.TmpDir); err != nil { + if prevError != nil { + logrus.Error(prevError) + } + prevError = err + } + if rootless.IsRootless() { + configPath := filepath.Join(os.Getenv("HOME"), ".config/containers") + if err := os.RemoveAll(configPath); err != nil { + if prevError != nil { + logrus.Error(prevError) + } + prevError = err + } + } + + return prevError +} diff --git a/libpod/runtime.go b/libpod/runtime.go index 42e6782e9..3873079ce 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -625,7 +625,8 @@ func (r *Runtime) refresh(alivePath string) error { } // Next refresh the state of all containers to recreate dirs and - // namespaces, and all the pods to recreate cgroups + // namespaces, and all the pods to recreate cgroups. + // Containers, pods, and volumes must also reacquire their locks. ctrs, err := r.state.AllContainers() if err != nil { return errors.Wrapf(err, "error retrieving all containers from state") @@ -634,10 +635,14 @@ func (r *Runtime) refresh(alivePath string) error { if err != nil { return errors.Wrapf(err, "error retrieving all pods from state") } - // No locks are taken during pod and container refresh. - // Furthermore, the pod and container refresh() functions are not + vols, err := r.state.AllVolumes() + if err != nil { + return errors.Wrapf(err, "error retrieving all volumes from state") + } + // No locks are taken during pod, volume, and container refresh. + // Furthermore, the pod/volume/container refresh() functions are not // allowed to take locks themselves. - // We cannot assume that any pod or container has a valid lock until + // We cannot assume that any pod/volume/container has a valid lock until // after this function has returned. // The runtime alive lock should suffice to provide mutual exclusion // until this has run. @@ -651,6 +656,11 @@ func (r *Runtime) refresh(alivePath string) error { logrus.Errorf("Error refreshing pod %s: %v", pod.ID(), err) } } + for _, vol := range vols { + if err := vol.refresh(); err != nil { + logrus.Errorf("Error refreshing volume %s: %v", vol.Name(), err) + } + } // Create a file indicating the runtime is alive and ready file, err := os.OpenFile(alivePath, os.O_RDONLY|os.O_CREATE, 0644) diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 7069d3494..ae401013c 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -489,32 +489,19 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, } } - var cleanupErr error - // Remove the container from the state - if c.config.Pod != "" { - // If we're removing the pod, the container will be evicted - // from the state elsewhere - if !removePod { - if err := r.state.RemoveContainerFromPod(pod, c); err != nil { - cleanupErr = err - } - } - } else { - if err := r.state.RemoveContainer(c); err != nil { - cleanupErr = err - } + // Set ContainerStateRemoving and remove exec sessions + c.state.State = define.ContainerStateRemoving + c.state.ExecSessions = nil + + if err := c.save(); err != nil { + return errors.Wrapf(err, "unable to set container %s removing state in database", c.ID()) } - // Set container as invalid so it can no longer be used - c.valid = false + var cleanupErr error // Clean up network namespace, cgroups, mounts if err := c.cleanup(ctx); err != nil { - if cleanupErr == nil { - cleanupErr = errors.Wrapf(err, "error cleaning up container %s", c.ID()) - } else { - logrus.Errorf("cleanup network, cgroups, mounts: %v", err) - } + cleanupErr = errors.Wrapf(err, "error cleaning up container %s", c.ID()) } // Stop the container's storage @@ -540,6 +527,29 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, } } + // Remove the container from the state + if c.config.Pod != "" { + // If we're removing the pod, the container will be evicted + // from the state elsewhere + if !removePod { + if err := r.state.RemoveContainerFromPod(pod, c); err != nil { + if cleanupErr == nil { + cleanupErr = err + } else { + logrus.Errorf("Error removing container %s from database: %v", c.ID(), err) + } + } + } + } else { + if err := r.state.RemoveContainer(c); err != nil { + if cleanupErr == nil { + cleanupErr = err + } else { + logrus.Errorf("Error removing container %s from database: %v", c.ID(), err) + } + } + } + // Deallocate the container's lock if err := c.lock.Free(); err != nil { if cleanupErr == nil { @@ -549,6 +559,9 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, } } + // Set container as invalid so it can no longer be used + c.valid = false + c.newContainerEvent(events.Remove) if !removeVolume { diff --git a/libpod/runtime_migrate_unsupported.go b/libpod/runtime_migrate_unsupported.go index 1a9e46fdc..e362cca63 100644 --- a/libpod/runtime_migrate_unsupported.go +++ b/libpod/runtime_migrate_unsupported.go @@ -9,3 +9,7 @@ import ( func (r *Runtime) migrate(ctx context.Context) error { return nil } + +func stopPauseProcess() error { + return nil +} diff --git a/libpod/util.go b/libpod/util.go index bae2f4eb8..30e5cd4c3 100644 --- a/libpod/util.go +++ b/libpod/util.go @@ -206,3 +206,28 @@ func DefaultSeccompPath() (string, error) { } return config.SeccompDefaultPath, nil } + +// CheckDependencyContainer verifies the given container can be used as a +// dependency of another container. +// Both the dependency to check and the container that will be using the +// dependency must be passed in. +// It is assumed that ctr is locked, and depCtr is unlocked. +func checkDependencyContainer(depCtr, ctr *Container) error { + state, err := depCtr.State() + if err != nil { + return errors.Wrapf(err, "error accessing dependency container %s state", depCtr.ID()) + } + if state == define.ContainerStateRemoving { + return errors.Wrapf(define.ErrCtrStateInvalid, "cannot use container %s as a dependency as it is being removed", depCtr.ID()) + } + + if depCtr.ID() == ctr.ID() { + return errors.Wrapf(define.ErrInvalidArg, "must specify another container") + } + + if ctr.config.Pod != "" && depCtr.PodID() != ctr.config.Pod { + return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, depCtr.ID()) + } + + return nil +} diff --git a/libpod/volume_internal.go b/libpod/volume_internal.go index 42b935e7c..e89b3484d 100644 --- a/libpod/volume_internal.go +++ b/libpod/volume_internal.go @@ -5,6 +5,7 @@ import ( "path/filepath" "github.com/containers/libpod/libpod/define" + "github.com/pkg/errors" ) // Creates a new volume @@ -46,3 +47,14 @@ func (v *Volume) update() error { func (v *Volume) save() error { return v.runtime.state.SaveVolume(v) } + +// Refresh volume state after a restart. +func (v *Volume) refresh() error { + lock, err := v.runtime.lockManager.AllocateAndRetrieveLock(v.config.LockID) + if err != nil { + return errors.Wrapf(err, "error acquiring lock %d for volume %s", v.config.LockID, v.Name()) + } + v.lock = lock + + return nil +} diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index bc9554193..0c73977c7 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -461,7 +461,8 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode if c.IsSet("rm") { if err := r.Runtime.RemoveContainer(ctx, ctr, false, true); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { + 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) @@ -1009,16 +1010,30 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal } // Prune removes stopped containers -func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool) ([]string, map[string]error, error) { +func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool, filters []string) ([]string, map[string]error, error) { var ( - ok = []string{} - failures = map[string]error{} - err error + ok = []string{} + failures = map[string]error{} + err error + filterFunc []libpod.ContainerFilter ) logrus.Debugf("Setting maximum rm workers to %d", maxWorkers) - filter := func(c *libpod.Container) bool { + 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) @@ -1032,7 +1047,9 @@ func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool) ([ } return false } - delContainers, err := r.Runtime.GetContainers(filter) + filterFunc = append(filterFunc, containerStateFilter) + + delContainers, err := r.Runtime.GetContainers(filterFunc...) if err != nil { return ok, failures, err } diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index e34b8ffd9..36db4af68 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -922,7 +922,7 @@ func (r *LocalRuntime) Top(cli *cliconfig.TopValues) ([]string, error) { } // Prune removes stopped containers -func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool) ([]string, map[string]error, error) { +func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool, filter []string) ([]string, map[string]error, error) { var ( ok = []string{} diff --git a/pkg/adapter/reset.go b/pkg/adapter/reset.go new file mode 100644 index 000000000..0decc3d15 --- /dev/null +++ b/pkg/adapter/reset.go @@ -0,0 +1,13 @@ +// +build !remoteclient + +package adapter + +import ( + "context" +) + +// Reset the container storage back to initial states. +// Removes all Pods, Containers, Images and Volumes. +func (r *LocalRuntime) Reset() error { + return r.Runtime.Reset(context.TODO()) +} diff --git a/pkg/adapter/reset_remote.go b/pkg/adapter/reset_remote.go new file mode 100644 index 000000000..663fab639 --- /dev/null +++ b/pkg/adapter/reset_remote.go @@ -0,0 +1,12 @@ +// +build remoteclient + +package adapter + +import ( + "github.com/containers/libpod/cmd/podman/varlink" +) + +// Info returns information for the host system and its components +func (r RemoteRuntime) Reset() error { + return iopodman.Reset().Call(r.Conn) +} diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go index f6057f5fc..b81ff11ba 100644 --- a/pkg/varlinkapi/system.go +++ b/pkg/varlinkapi/system.go @@ -3,12 +3,15 @@ package varlinkapi import ( + "context" "fmt" - "github.com/containers/libpod/libpod/define" + "os" goruntime "runtime" "time" "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod/define" + "github.com/sirupsen/logrus" ) // GetVersion ... @@ -105,3 +108,20 @@ func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error { podmanInfo.Insecure_registries = insecureRegistries return call.ReplyGetInfo(podmanInfo) } + +// GetVersion ... +func (i *LibpodAPI) Reset(call iopodman.VarlinkCall) error { + if err := i.Runtime.Reset(context.TODO()); err != nil { + logrus.Errorf("Reset Failed: %v", err) + if err := call.ReplyErrorOccurred(err.Error()); err != nil { + logrus.Errorf("Failed to send ReplyErrorOccurred: %v", err) + } + os.Exit(define.ExecErrorCodeGeneric) + } + if err := call.ReplyReset(); err != nil { + logrus.Errorf("Failed to send ReplyReset: %v", err) + os.Exit(define.ExecErrorCodeGeneric) + } + os.Exit(0) + return nil +} diff --git a/rootless.md b/rootless.md index 4fb3c7deb..69de6db21 100644 --- a/rootless.md +++ b/rootless.md @@ -42,3 +42,5 @@ can easily fail * Pause and Unpause (Works with cgroup V2 support) * Issues with higher UIDs can cause builds to fail * If a build is attempting to use a UID that is not mapped into the user namespace mapping for a container, then builds will not be able to put the UID in an image. +* Making device nodes within a container fails, even when running --privileged. + * Kernel does not allow non root user processes (processes without CAP_MKNOD) to create device nodes. If container needs to create device nodes, it must be run as root. diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 5239f4d8e..43f08bf03 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -135,3 +135,7 @@ func removeCache() { func (p *PodmanTestIntegration) SeedImages() error { return nil } + +// We don't support running Varlink when local +func (p *PodmanTestIntegration) StartVarlink() { +} diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go index 16522785b..c9b01ad4a 100644 --- a/test/e2e/prune_test.go +++ b/test/e2e/prune_test.go @@ -52,7 +52,7 @@ var _ = Describe("Podman prune", func() { stop.WaitWithDefaultTimeout() Expect(stop.ExitCode()).To(Equal(0)) - prune := podmanTest.Podman([]string{"container", "prune"}) + prune := podmanTest.Podman([]string{"container", "prune", "-f"}) prune.WaitWithDefaultTimeout() Expect(prune.ExitCode()).To(Equal(0)) diff --git a/test/e2e/system_reset_test.go b/test/e2e/system_reset_test.go new file mode 100644 index 000000000..e5ce69739 --- /dev/null +++ b/test/e2e/system_reset_test.go @@ -0,0 +1,83 @@ +package integration + +import ( + "fmt" + "os" + + . "github.com/containers/libpod/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("podman system reset", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + podmanTest.SeedImages() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds()) + GinkgoWriter.Write([]byte(timedResult)) + }) + + It("podman system reset", func() { + // system reset will not remove additional store images, so need to grab length + + session := podmanTest.Podman([]string{"rmi", "--force", "--all"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"images", "-n"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + l := len(session.OutputToStringArray()) + + session = podmanTest.Podman([]string{"pull", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"volume", "create", "data"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"create", "-v", "data:/data", ALPINE, "echo", "hello"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"system", "reset", "-f"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + // If remote then the varlink service should have exited + // On local tests this is a noop + podmanTest.StartVarlink() + + session = podmanTest.Podman([]string{"images", "-n"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(l)) + + session = podmanTest.Podman([]string{"volume", "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(0)) + + session = podmanTest.Podman([]string{"container", "ls", "-q"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(0)) + }) +}) diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go index 0db2e2cf2..c2af613aa 100644 --- a/test/e2e/version_test.go +++ b/test/e2e/version_test.go @@ -33,7 +33,6 @@ var _ = Describe("Podman version", func() { }) It("podman version", func() { - SkipIfRemote() session := podmanTest.Podman([]string{"version"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -43,7 +42,6 @@ var _ = Describe("Podman version", func() { }) It("podman -v", func() { - SkipIfRemote() session := podmanTest.Podman([]string{"-v"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -52,7 +50,6 @@ var _ = Describe("Podman version", func() { }) It("podman --version", func() { - SkipIfRemote() session := podmanTest.Podman([]string{"--version"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -61,7 +58,6 @@ var _ = Describe("Podman version", func() { }) It("podman version --format json", func() { - SkipIfRemote() session := podmanTest.Podman([]string{"version", "--format", "json"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -69,7 +65,6 @@ var _ = Describe("Podman version", func() { }) It("podman version --format json", func() { - SkipIfRemote() session := podmanTest.Podman([]string{"version", "--format", "{{ json .}}"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -77,8 +72,15 @@ var _ = Describe("Podman version", func() { }) It("podman version --format GO template", func() { - SkipIfRemote() - session := podmanTest.Podman([]string{"version", "--format", "{{ .Version }}"}) + session := podmanTest.Podman([]string{"version", "--format", "{{ .Client.Version }}"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"version", "--format", "{{ .Server.Version }}"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"version", "--format", "{{ .Version }}"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) |