diff options
62 files changed, 593 insertions, 206 deletions
@@ -42,6 +42,10 @@ ISODATE ?= $(shell date --iso-8601) #Update to LIBSECCOMP_COMMIT should reflect in Dockerfile too. LIBSECCOMP_COMMIT := release-2.3 +# Rarely if ever should integration tests take more than 50min, +# caller may override in special circumstances if needed. +GINKGOTIMEOUT ?= -timeout=50m + # If GOPATH not specified, use one in the local directory ifeq ($(GOPATH),) export GOPATH := $(CURDIR)/_output @@ -68,28 +72,36 @@ all: binaries docs default: help +define PRINT_HELP_PYSCRIPT +import re, sys + +print("Usage: make <target>") +cmds = {} +for line in sys.stdin: + match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) + if match: + target, help = match.groups() + cmds.update({target: help}) +for cmd in sorted(cmds): + print(" * '%s' - %s" % (cmd, cmds[cmd])) +endef +export PRINT_HELP_PYSCRIPT + help: - @echo "Usage: make <target>" - @echo - @echo " * 'install' - Install binaries to system locations" - @echo " * 'binaries' - Build podman" - @echo " * 'integration' - Execute integration tests" - @echo " * 'clean' - Clean artifacts" - @echo " * 'lint' - Execute the source code linter" - @echo " * 'gofmt' - Verify the source code gofmt" + @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) .gopathok: ifeq ("$(wildcard $(GOPKGDIR))","") mkdir -p "$(GOPKGBASEDIR)" - ln -s "$(CURDIR)" "$(GOPKGBASEDIR)" + ln -sf "$(CURDIR)" "$(GOPKGBASEDIR)" endif touch $@ -lint: .gopathok varlink_generate +lint: .gopathok varlink_generate ## Execute the source code linter @echo "checking lint" @./.tool/lint -gofmt: +gofmt: ## Verify the source code gofmt find . -name '*.go' ! -path './vendor/*' -exec gofmt -s -w {} \+ git diff --exit-code @@ -105,16 +117,16 @@ test/checkseccomp/checkseccomp: .gopathok $(wildcard test/checkseccomp/*.go) test/goecho/goecho: .gopathok $(wildcard test/goecho/*.go) $(GO) build -ldflags '$(LDFLAGS)' -o $@ $(PROJECT)/test/goecho -podman: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) +podman: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman $(GO) build -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o bin/$@ $(PROJECT)/cmd/podman -podman-remote: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) +podman-remote: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman on remote environment $(GO) build -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS) remoteclient" -o bin/$@ $(PROJECT)/cmd/podman -podman-remote-darwin: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) +podman-remote-darwin: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman on remote OSX environment GOOS=darwin $(GO) build -ldflags '$(LDFLAGS_PODMAN)' -tags "remoteclient containers_image_openpgp exclude_graphdriver_devicemapper" -o bin/$@ $(PROJECT)/cmd/podman -local-cross: $(CROSS_BUILD_TARGETS) +local-cross: $(CROSS_BUILD_TARGETS) ## Cross local compilation bin/podman.cross.%: .gopathok TARGET="$*"; \ @@ -122,7 +134,7 @@ bin/podman.cross.%: .gopathok GOARCH="$${TARGET##*.}" \ $(GO) build -ldflags '$(LDFLAGS_PODMAN)' -tags '$(BUILDTAGS_CROSS)' -o "$@" $(PROJECT)/cmd/podman -clean: +clean: ## Clean artifacts rm -rf \ .gopathok \ _output \ @@ -142,16 +154,16 @@ clean: find . -name \*~ -delete find . -name \#\* -delete -libpodimage: +libpodimage: ## Build the libpod image ${CONTAINER_RUNTIME} build -t ${LIBPOD_IMAGE} . dbuild: libpodimage ${CONTAINER_RUNTIME} run --name=${LIBPOD_INSTANCE} --privileged -v ${PWD}:/go/src/${PROJECT} --rm ${LIBPOD_IMAGE} make all -test: libpodimage +test: libpodimage ## Run tests on built image ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e OCI_RUNTIME -e CGROUP_MANAGER=cgroupfs -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make clean all localunit install.catatonit localintegration -integration: libpodimage +integration: libpodimage ## Execute integration tests ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e OCI_RUNTIME -e CGROUP_MANAGER=cgroupfs -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make clean all install.catatonit localintegration integration.fedora: @@ -160,10 +172,10 @@ integration.fedora: integration.centos: DIST=CentOS sh .papr_prepare.sh -shell: libpodimage +shell: libpodimage ## Run the built image and attach a shell ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e CGROUP_MANAGER=cgroupfs -e TESTFLAGS -e OCI_RUNTIME -e TRAVIS -it --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} sh -testunit: libpodimage +testunit: libpodimage ## Run unittest on the built image ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e CGROUP_MANAGER=cgroupfs -e OCI_RUNTIME -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make localunit localunit: test/goecho/goecho varlink_generate @@ -171,29 +183,29 @@ localunit: test/goecho/goecho varlink_generate $(MAKE) -C contrib/cirrus/packer test ginkgo: - ginkgo -v -tags "$(BUILDTAGS)" -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/. + ginkgo -v -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/. ginkgo-remote: - ginkgo -v -tags "$(BUILDTAGS) remoteclient" -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/. + ginkgo -v -tags "$(BUILDTAGS) remoteclient" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/. localintegration: varlink_generate test-binaries ginkgo ginkgo-remote -localsystem: .install.ginkgo .install.gomega +localsystem: .install.ginkgo ginkgo -v -noColor test/system/ -system.test-binary: .install.ginkgo .install.gomega +system.test-binary: .install.ginkgo $(GO) test -c ./test/system -perftest: +perftest: ## Build perf tests $ cd contrib/perftest;go build -run-perftest: perftest +run-perftest: perftest ## Build and run perf tests $ contrib/perftest/perftest vagrant-check: BOX=$(BOX) sh ./vagrant.sh -binaries: varlink_generate podman podman-remote +binaries: varlink_generate podman podman-remote ## Build podman install.catatonit: ./hack/install_catatonit.sh @@ -206,12 +218,12 @@ MANPAGES ?= $(MANPAGES_MD:%.md=%) $(MANPAGES): %: %.md .gopathok @sed -e 's/\((podman.*\.md)\)//' -e 's/\[\(podman.*\)\]/\1/' $< | $(GOMD2MAN) -in /dev/stdin -out $@ -docs: $(MANPAGES) +docs: $(MANPAGES) ## Generate documentation docker-docs: docs (cd docs; ./dckrman.sh *.1) -changelog: +changelog: ## Generate changelog @echo "Creating changelog from $(CHANGELOG_BASE) to $(CHANGELOG_TARGET)" $(eval TMPFILE := $(shell mktemp)) $(shell cat changelog.txt > $(TMPFILE)) @@ -221,7 +233,7 @@ changelog: $(shell cat $(TMPFILE) >> changelog.txt) $(shell rm $(TMPFILE)) -install: .gopathok install.bin install.man install.cni install.systemd +install: .gopathok install.bin install.man install.cni install.systemd ## Install binaries to system locations install.bin: install ${SELINUXOPT} -d -m 755 $(BINDIR) @@ -274,7 +286,7 @@ uninstall: .PHONY: install.tools -install.tools: .install.gitvalidation .install.gometalinter .install.md2man .install.ginkgo +install.tools: .install.gitvalidation .install.gometalinter .install.md2man .install.ginkgo ## Install needed tools .install.vndr: .gopathok $(GO) get github.com/LK4D4/vndr @@ -20,6 +20,8 @@ At a high level, the scope of libpod and podman is the following: * Resource isolation of containers and pods. * Integration with CRI-O to share containers and backend code. +This project tests all builds against each supported version of Fedora, the latest released version of Red Hat Enterprise Linux, and the latest Ubuntu Long Term Support release. The community has also reported success with other Linux flavors. + ## Roadmap 1. Allow the Podman CLI to use a Varlink backend to connect to remote Podman instances diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go index dc0563a94..bcfee6891 100644 --- a/cmd/podman/attach.go +++ b/cmd/podman/attach.go @@ -21,7 +21,7 @@ var ( }, cli.BoolTFlag{ Name: "sig-proxy", - Usage: "proxy received signals to the process (default true)", + Usage: "Proxy received signals to the process (default true)", }, LatestFlag, } diff --git a/cmd/podman/build.go b/cmd/podman/build.go index 02a125aab..0cd1bfbe3 100644 --- a/cmd/podman/build.go +++ b/cmd/podman/build.go @@ -25,7 +25,7 @@ var ( }, cli.BoolTFlag{ Name: "layers", - Usage: "cache intermediate layers during build. Use BUILDAH_LAYERS environment variable to override. ", + Usage: "Cache intermediate layers during build. Use BUILDAH_LAYERS environment variable to override. ", }, } buildDescription = "Builds an OCI or Docker image using instructions from one\n" + diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go index 824c97662..5c3363147 100644 --- a/cmd/podman/checkpoint.go +++ b/cmd/podman/checkpoint.go @@ -21,19 +21,19 @@ var ( checkpointFlags = []cli.Flag{ cli.BoolFlag{ Name: "keep, k", - Usage: "keep all temporary checkpoint files", + Usage: "Keep all temporary checkpoint files", }, cli.BoolFlag{ Name: "leave-running, R", - Usage: "leave the container running after writing checkpoint to disk", + Usage: "Leave the container running after writing checkpoint to disk", }, cli.BoolFlag{ Name: "tcp-established", - Usage: "checkpoint a container with established TCP connections", + Usage: "Checkpoint a container with established TCP connections", }, cli.BoolFlag{ Name: "all, a", - Usage: "checkpoint all running containers", + Usage: "Checkpoint all running containers", }, LatestFlag, } diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index d8fdd556f..57126da4a 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -53,6 +53,10 @@ func getImageSubCommands() []cli.Command { } } +func getSystemSubCommands() []cli.Command { + return []cli.Command{infoCommand} +} + func getContainerSubCommands() []cli.Command { return []cli.Command{ attachCommand, @@ -91,58 +95,58 @@ func getMainAppFlags() []cli.Flag { return []cli.Flag{ cli.StringFlag{ Name: "cgroup-manager", - Usage: "cgroup manager to use (cgroupfs or systemd, default systemd)", + Usage: "Cgroup manager to use (cgroupfs or systemd, default systemd)", }, cli.StringFlag{ Name: "cni-config-dir", - Usage: "path of the configuration directory for CNI networks", + Usage: "Path of the configuration directory for CNI networks", }, cli.StringFlag{ Name: "conmon", - Usage: "path of the conmon binary", + Usage: "Path of the conmon binary", }, cli.StringFlag{ Name: "default-mounts-file", - Usage: "path to default mounts file", + Usage: "Path to default mounts file", Hidden: true, }, cli.StringSliceFlag{ Name: "hooks-dir", - Usage: "set the OCI hooks directory path (may be set multiple times)", + Usage: "Set the OCI hooks directory path (may be set multiple times)", }, cli.IntFlag{ Name: "max-workers", - Usage: "the maximum number of workers for parallel operations", + Usage: "The maximum number of workers for parallel operations", Hidden: true, }, cli.StringFlag{ Name: "namespace", - Usage: "set the libpod namespace, used to create separate views of the containers and pods on the system", + Usage: "Set the libpod namespace, used to create separate views of the containers and pods on the system", Value: "", }, cli.StringFlag{ Name: "root", - Usage: "path to the root directory in which data, including images, is stored", + Usage: "Path to the root directory in which data, including images, is stored", }, cli.StringFlag{ Name: "runroot", - Usage: "path to the 'run directory' where all state information is stored", + Usage: "Path to the 'run directory' where all state information is stored", }, cli.StringFlag{ Name: "runtime", - Usage: "path to the OCI-compatible binary used to run containers, default is /usr/bin/runc", + Usage: "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc", }, cli.StringFlag{ Name: "storage-driver, s", - Usage: "select which storage driver is used to manage storage of images and containers (default is overlay)", + Usage: "Select which storage driver is used to manage storage of images and containers (default is overlay)", }, cli.StringSliceFlag{ Name: "storage-opt", - Usage: "used to pass an option to the storage driver", + Usage: "Used to pass an option to the storage driver", }, cli.BoolFlag{ Name: "syslog", - Usage: "output logging information to syslog as well as the console", + Usage: "Output logging information to syslog as well as the console", }, } } diff --git a/cmd/podman/commands_remoteclient.go b/cmd/podman/commands_remoteclient.go index 6701e14a1..0adbd7b4c 100644 --- a/cmd/podman/commands_remoteclient.go +++ b/cmd/podman/commands_remoteclient.go @@ -16,6 +16,10 @@ func getContainerSubCommands() []cli.Command { return []cli.Command{} } +func getSystemSubCommands() []cli.Command { + return []cli.Command{} +} + func getMainAppFlags() []cli.Flag { return []cli.Flag{} } diff --git a/cmd/podman/common.go b/cmd/podman/common.go index d934c8699..82d60d62e 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -22,11 +22,11 @@ var ( stores = make(map[storage.Store]struct{}) LatestFlag = cli.BoolFlag{ Name: "latest, l", - Usage: "act on the latest container podman is aware of", + Usage: "Act on the latest container podman is aware of", } LatestPodFlag = cli.BoolFlag{ Name: "latest, l", - Usage: "act on the latest pod podman is aware of", + Usage: "Act on the latest pod podman is aware of", } WorkDirFlag = cli.StringFlag{ Name: "workdir, w", @@ -213,7 +213,7 @@ var createFlags = []cli.Flag{ }, cli.StringFlag{ Name: "conmon-pidfile", - Usage: "path to the file that will receive the PID of conmon", + Usage: "Path to the file that will receive the PID of conmon", }, cli.Uint64Flag{ Name: "cpu-period", diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go index 92604e82f..09141e9a3 100644 --- a/cmd/podman/containers_prune.go +++ b/cmd/podman/containers_prune.go @@ -1,9 +1,11 @@ package main import ( - "github.com/containers/libpod/cmd/podman/libpodruntime" + "context" + "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -25,20 +27,11 @@ var ( } ) -func pruneContainersCmd(c *cli.Context) error { - var ( - deleteFuncs []shared.ParallelWorkerInput - ) - - ctx := getContext() - runtime, err := libpodruntime.GetRuntime(c) - if err != nil { - return errors.Wrapf(err, "could not get runtime") - } - defer runtime.Shutdown(false) +func pruneContainers(runtime *adapter.LocalRuntime, ctx context.Context, maxWorkers int, force bool) error { + var deleteFuncs []shared.ParallelWorkerInput filter := func(c *libpod.Container) bool { - state, _ := c.State() + state, err := c.State() if state == libpod.ContainerStateStopped || (state == libpod.ContainerStateExited && err == nil && c.PodID() == "") { return true } @@ -54,7 +47,7 @@ func pruneContainersCmd(c *cli.Context) error { for _, container := range delContainers { con := container f := func() error { - return runtime.RemoveContainer(ctx, con, c.Bool("force")) + return runtime.RemoveContainer(ctx, con, force) } deleteFuncs = append(deleteFuncs, shared.ParallelWorkerInput{ @@ -62,13 +55,23 @@ func pruneContainersCmd(c *cli.Context) error { ParallelFunc: f, }) } + // Run the parallel funcs + deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs) + return printParallelOutput(deleteErrors, errCount) +} + +func pruneContainersCmd(c *cli.Context) error { + runtime, err := adapter.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + maxWorkers := shared.Parallelize("rm") if c.GlobalIsSet("max-workers") { maxWorkers = c.GlobalInt("max-workers") } logrus.Debugf("Setting maximum workers to %d", maxWorkers) - // Run the parallel funcs - deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs) - return printParallelOutput(deleteErrors, errCount) + return pruneContainers(runtime, getContext(), maxWorkers, c.Bool("force")) } diff --git a/cmd/podman/docker/types.go b/cmd/podman/docker/types.go index 90349a31c..eda618e40 100644 --- a/cmd/podman/docker/types.go +++ b/cmd/podman/docker/types.go @@ -69,8 +69,9 @@ type HealthConfig struct { Test []string `json:",omitempty"` // Zero means to inherit. Durations are expressed as integer nanoseconds. - Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. - Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. + Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. + Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. + StartPeriod time.Duration `json:",omitempty"` // Time to wait after the container starts before running the first check. // Retries is the number of consecutive failures needed to consider a container as unhealthy. // Zero means inherit. diff --git a/cmd/podman/generate.go b/cmd/podman/generate.go index 765d0ee70..20a4a61ab 100644 --- a/cmd/podman/generate.go +++ b/cmd/podman/generate.go @@ -9,10 +9,10 @@ var ( containerKubeCommand, } - generateDescription = "generate structured data based for a containers and pods" + generateDescription = "Generate structured data based for a containers and pods" kubeCommand = cli.Command{ Name: "generate", - Usage: "generated structured data", + Usage: "Generate structured data", Description: generateDescription, ArgsUsage: "", Subcommands: generateSubCommands, diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go index f63bd431b..fc667fb5b 100644 --- a/cmd/podman/generate_kube.go +++ b/cmd/podman/generate_kube.go @@ -17,7 +17,7 @@ var ( containerKubeFlags = []cli.Flag{ cli.BoolFlag{ Name: "service, s", - Usage: "generate YAML for kubernetes service object", + Usage: "Generate YAML for kubernetes service object", }, } containerKubeDescription = "Generate Kubernetes Pod YAML" diff --git a/cmd/podman/images.go b/cmd/podman/images.go index d4f405975..9fdf0a780 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -90,11 +90,11 @@ var ( }, cli.BoolFlag{ Name: "digests", - Usage: "show digests", + Usage: "Show digests", }, cli.StringSliceFlag{ Name: "filter, f", - Usage: "filter output based on conditions provided (default [])", + Usage: "Filter output based on conditions provided (default [])", }, cli.StringFlag{ Name: "format", @@ -102,20 +102,20 @@ var ( }, cli.BoolFlag{ Name: "noheading, n", - Usage: "do not print column headings", + Usage: "Do not print column headings", }, cli.BoolFlag{ Name: "no-trunc, notruncate", - Usage: "do not truncate output", + Usage: "Do not truncate output", }, cli.BoolFlag{ Name: "quiet, q", - Usage: "display only image IDs", + Usage: "Display only image IDs", }, cli.StringFlag{ Name: "sort", Usage: "Sort by created, id, repository, size, or tag", - Value: "created", + Value: "Created", }, } @@ -133,7 +133,7 @@ var ( lsImagesCommand = cli.Command{ Name: "list", Aliases: []string{"ls"}, - Usage: "list images in local storage", + Usage: "List images in local storage", Description: imagesDescription, Flags: imagesFlags, Action: imagesCmd, diff --git a/cmd/podman/images_prune.go b/cmd/podman/images_prune.go index aef387732..844984bb9 100644 --- a/cmd/podman/images_prune.go +++ b/cmd/podman/images_prune.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/containers/libpod/libpod/adapter" "github.com/pkg/errors" "github.com/urfave/cli" @@ -16,7 +17,7 @@ var ( pruneImageFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "remove all unused images, not just dangling ones", + Usage: "Remove all unused images, not just dangling ones", }, } pruneImagesCommand = cli.Command{ diff --git a/cmd/podman/info.go b/cmd/podman/info.go index f5f91b603..19078cea5 100644 --- a/cmd/podman/info.go +++ b/cmd/podman/info.go @@ -26,7 +26,7 @@ var ( infoFlags = []cli.Flag{ cli.BoolFlag{ Name: "debug, D", - Usage: "display additional debug information", + Usage: "Display additional debug information", }, cli.StringFlag{ Name: "format, f", diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 1ca8882eb..8c08b2bfb 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -97,6 +97,7 @@ func main() { inspectCommand, pullCommand, rmiCommand, + systemCommand, tagCommand, versionCommand, } @@ -187,21 +188,21 @@ func main() { app.Flags = []cli.Flag{ cli.StringFlag{ Name: "config, c", - Usage: "path of a libpod config file detailing container server configuration options", + Usage: "Path of a libpod config file detailing container server configuration options", Hidden: true, }, cli.StringFlag{ Name: "cpu-profile", - Usage: "path for the cpu profiling results", + Usage: "Path for the cpu profiling results", }, cli.StringFlag{ Name: "log-level", - Usage: "log messages above specified level: debug, info, warn, error (default), fatal or panic", + Usage: "Log messages above specified level: debug, info, warn, error (default), fatal or panic", Value: "error", }, cli.StringFlag{ Name: "tmpdir", - Usage: "path to the tmp directory", + Usage: "Path to the tmp directory", }, } diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go index 86a6b2ad1..f71d47434 100644 --- a/cmd/podman/mount.go +++ b/cmd/podman/mount.go @@ -33,7 +33,7 @@ var ( }, cli.BoolFlag{ Name: "notruncate", - Usage: "do not truncate output", + Usage: "Do not truncate output", }, LatestFlag, } diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go index 9da6abf4b..2e7182871 100644 --- a/cmd/podman/pause.go +++ b/cmd/podman/pause.go @@ -15,7 +15,7 @@ var ( pauseFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "pause all running containers", + Usage: "Pause all running containers", }, } pauseDescription = ` diff --git a/cmd/podman/play.go b/cmd/podman/play.go index adbab3480..4e09b2689 100644 --- a/cmd/podman/play.go +++ b/cmd/podman/play.go @@ -12,7 +12,7 @@ var ( playDescription = "Play a pod and its containers from a structured file." playCommand = cli.Command{ Name: "play", - Usage: "play a container or pod", + Usage: "Play a container or pod", Description: playDescription, ArgsUsage: "", Subcommands: playSubCommands, diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go index 4753dd0a6..2d97e0e95 100644 --- a/cmd/podman/play_kube.go +++ b/cmd/podman/play_kube.go @@ -32,11 +32,11 @@ var ( }, cli.StringFlag{ Name: "cert-dir", - Usage: "`pathname` of a directory containing TLS certificates and keys", + Usage: "`Pathname` of a directory containing TLS certificates and keys", }, cli.StringFlag{ Name: "creds", - Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", + Usage: "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", }, cli.BoolFlag{ Name: "quiet, q", @@ -44,11 +44,11 @@ var ( }, cli.StringFlag{ Name: "signature-policy", - Usage: "`pathname` of signature policy file (not usually used)", + Usage: "`Pathname` of signature policy file (not usually used)", }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, } playKubeDescription = "Play a Pod and its containers based on a Kubrernetes YAML" @@ -58,7 +58,7 @@ var ( Description: playKubeDescription, Action: playKubeYAMLCmd, Flags: sortFlags(playKubeFlags), - ArgsUsage: "kubernetes YAML file", + ArgsUsage: "Kubernetes YAML file", UseShortOptionHandling: true, OnUsageError: usageErrorHandler, } diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go index 77178b14d..c7bbf31cd 100644 --- a/cmd/podman/pod_inspect.go +++ b/cmd/podman/pod_inspect.go @@ -14,10 +14,10 @@ var ( podInspectFlags = []cli.Flag{ LatestPodFlag, } - podInspectDescription = "display the configuration for a pod by name or id" + podInspectDescription = "Display the configuration for a pod by name or id" podInspectCommand = cli.Command{ Name: "inspect", - Usage: "displays a pod configuration", + Usage: "Displays a pod configuration", Description: podInspectDescription, Flags: sortFlags(podInspectFlags), Action: podInspectCmd, diff --git a/cmd/podman/pod_pause.go b/cmd/podman/pod_pause.go index e8de0debc..f29a0b8d1 100644 --- a/cmd/podman/pod_pause.go +++ b/cmd/podman/pod_pause.go @@ -13,7 +13,7 @@ var ( podPauseFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "pause all running pods", + Usage: "Pause all running pods", }, LatestPodFlag, } diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go index e956b2f70..d9800cbf7 100644 --- a/cmd/podman/pod_restart.go +++ b/cmd/podman/pod_restart.go @@ -13,7 +13,7 @@ var ( podRestartFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "restart all pods", + Usage: "Restart all pods", }, LatestPodFlag, } diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go index f0a7926c9..2178340a4 100644 --- a/cmd/podman/pod_start.go +++ b/cmd/podman/pod_start.go @@ -13,7 +13,7 @@ var ( podStartFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "start all running pods", + Usage: "Start all running pods", }, LatestPodFlag, } diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go index 2e29445b4..0f0e215e6 100644 --- a/cmd/podman/pod_stats.go +++ b/cmd/podman/pod_stats.go @@ -19,22 +19,22 @@ var ( podStatsFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "show stats for all pods. Only running pods are shown by default.", + Usage: "Show stats for all pods. Only running pods are shown by default.", }, cli.BoolFlag{ Name: "no-stream", - Usage: "disable streaming stats and only pull the first result, default setting is false", + Usage: "Disable streaming stats and only pull the first result, default setting is false", }, cli.BoolFlag{ Name: "no-reset", - Usage: "disable resetting the screen between intervals", + Usage: "Disable resetting the screen between intervals", }, cli.StringFlag{ Name: "format", - Usage: "pretty-print container statistics to JSON or using a Go template", + Usage: "Pretty-print container statistics to JSON or using a Go template", }, LatestPodFlag, } - podStatsDescription = "display a live stream of resource usage statistics for the containers in or more pods" + podStatsDescription = "Display a live stream of resource usage statistics for the containers in or more pods" podStatsCommand = cli.Command{ Name: "stats", Usage: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for containers in one or more pods", diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go index d49ba8a00..148b4d518 100644 --- a/cmd/podman/pod_stop.go +++ b/cmd/podman/pod_stop.go @@ -12,7 +12,7 @@ var ( podStopFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "stop all running pods", + Usage: "Stop all running pods", }, LatestPodFlag, cli.UintFlag{ diff --git a/cmd/podman/pod_unpause.go b/cmd/podman/pod_unpause.go index 5256f680c..ed1a00cf8 100644 --- a/cmd/podman/pod_unpause.go +++ b/cmd/podman/pod_unpause.go @@ -13,7 +13,7 @@ var ( podUnpauseFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "unpause all paused pods", + Usage: "Unpause all paused pods", }, LatestPodFlag, } diff --git a/cmd/podman/port.go b/cmd/podman/port.go index 3355e751b..6875c648a 100644 --- a/cmd/podman/port.go +++ b/cmd/podman/port.go @@ -15,7 +15,7 @@ var ( portFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "display port information for all containers", + Usage: "Display port information for all containers", }, LatestFlag, } diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index f70e5cded..2349265d0 100644 --- a/cmd/podman/pull.go +++ b/cmd/podman/pull.go @@ -41,7 +41,7 @@ var ( }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, } diff --git a/cmd/podman/push.go b/cmd/podman/push.go index 82589f3f1..361a25e35 100644 --- a/cmd/podman/push.go +++ b/cmd/podman/push.go @@ -21,40 +21,40 @@ var ( pushFlags = []cli.Flag{ cli.StringFlag{ Name: "signature-policy", - Usage: "`pathname` of signature policy file (not usually used)", + Usage: "`Pathname` of signature policy file (not usually used)", Hidden: true, }, cli.StringFlag{ Name: "creds", - Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", + Usage: "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", }, cli.StringFlag{ Name: "cert-dir", - Usage: "`pathname` of a directory containing TLS certificates and keys", + Usage: "`Pathname` of a directory containing TLS certificates and keys", }, cli.BoolFlag{ Name: "compress", - Usage: "compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)", + Usage: "Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)", }, cli.StringFlag{ Name: "format, f", - Usage: "manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir:' transport (default is manifest type of source)", + Usage: "Manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir:' transport (default is manifest type of source)", }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, cli.BoolFlag{ Name: "remove-signatures", - Usage: "discard any pre-existing signatures in the image", + Usage: "Discard any pre-existing signatures in the image", }, cli.StringFlag{ Name: "sign-by", - Usage: "add a signature at the destination using the specified key", + Usage: "Add a signature at the destination using the specified key", }, cli.BoolFlag{ Name: "quiet, q", - Usage: "don't output progress information when pushing images", + Usage: "Don't output progress information when pushing images", }, cli.StringFlag{ Name: "authfile", diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go index c6fe1025a..2e52ce5e4 100644 --- a/cmd/podman/restart.go +++ b/cmd/podman/restart.go @@ -17,11 +17,11 @@ var ( restartFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "restart all non-running containers", + Usage: "Restart all non-running containers", }, cli.BoolFlag{ Name: "running", - Usage: "restart only running containers when --all is used", + Usage: "Restart only running containers when --all is used", }, cli.UintFlag{ Name: "timeout, time, t", diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go index bc2a71ba0..664475e22 100644 --- a/cmd/podman/restore.go +++ b/cmd/podman/restore.go @@ -21,18 +21,18 @@ var ( restoreFlags = []cli.Flag{ cli.BoolFlag{ Name: "keep, k", - Usage: "keep all temporary checkpoint files", + Usage: "Keep all temporary checkpoint files", }, // restore --all would make more sense if there would be // dedicated state for container which are checkpointed. // TODO: add ContainerStateCheckpointed cli.BoolFlag{ Name: "tcp-established", - Usage: "checkpoint a container with established TCP connections", + Usage: "Checkpoint a container with established TCP connections", }, cli.BoolFlag{ Name: "all, a", - Usage: "restore all checkpointed containers", + Usage: "Restore all checkpointed containers", }, LatestFlag, } diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go index c904f2f92..39757272e 100644 --- a/cmd/podman/rmi.go +++ b/cmd/podman/rmi.go @@ -15,11 +15,11 @@ var ( rmiFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "remove all images", + Usage: "Remove all images", }, cli.BoolFlag{ Name: "force, f", - Usage: "force removal of the image", + Usage: "Force removal of the image", }, } rmiCommand = cli.Command{ @@ -34,7 +34,7 @@ var ( } rmImageCommand = cli.Command{ Name: "rm", - Usage: "removes one or more images from local storage", + Usage: "Removes one or more images from local storage", Description: rmiDescription, Action: rmiCmd, ArgsUsage: "IMAGE-NAME-OR-ID [...]", diff --git a/cmd/podman/run.go b/cmd/podman/run.go index 20cb85347..3ef546940 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -20,7 +20,7 @@ var runDescription = "Runs a command in a new container from the given image" var runFlags []cli.Flag = append(createFlags, cli.BoolTFlag{ Name: "sig-proxy", - Usage: "proxy received signals to the process (default true)", + Usage: "Proxy received signals to the process (default true)", }) var runCommand = cli.Command{ @@ -131,6 +131,7 @@ func runCmd(c *cli.Context) error { ctrExitCode, err := readExitFile(runtime.GetConfig().TmpDir, ctr.ID()) if err != nil { logrus.Errorf("Cannot get exit code: %v", err) + exitCode = 127 } else { exitCode = ctrExitCode } diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go index b16a93fd9..38905b5ca 100644 --- a/cmd/podman/runlabel.go +++ b/cmd/podman/runlabel.go @@ -24,15 +24,15 @@ var ( }, cli.BoolFlag{ Name: "display", - Usage: "preview the command that the label would run", + Usage: "Preview the command that the label would run", }, cli.StringFlag{ Name: "cert-dir", - Usage: "`pathname` of a directory containing TLS certificates and keys", + Usage: "`Pathname` of a directory containing TLS certificates and keys", }, cli.StringFlag{ Name: "creds", - Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", + Usage: "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", }, cli.StringFlag{ Name: "name", @@ -59,15 +59,15 @@ var ( }, cli.BoolFlag{ Name: "pull, p", - Usage: "pull the image if it does not exist locally prior to executing the label contents", + Usage: "Pull the image if it does not exist locally prior to executing the label contents", }, cli.StringFlag{ Name: "signature-policy", - Usage: "`pathname` of signature policy file (not usually used)", + Usage: "`Pathname` of signature policy file (not usually used)", }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, } diff --git a/cmd/podman/save.go b/cmd/podman/save.go index 139f3918a..325140b76 100644 --- a/cmd/podman/save.go +++ b/cmd/podman/save.go @@ -29,7 +29,7 @@ var ( saveFlags = []cli.Flag{ cli.BoolFlag{ Name: "compress", - Usage: "compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)", + Usage: "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)", }, cli.StringFlag{ Name: "output, o", diff --git a/cmd/podman/search.go b/cmd/podman/search.go index 442ebb57f..81469a0f8 100644 --- a/cmd/podman/search.go +++ b/cmd/podman/search.go @@ -30,23 +30,23 @@ var ( }, cli.StringSliceFlag{ Name: "filter, f", - Usage: "filter output based on conditions provided (default [])", + Usage: "Filter output based on conditions provided (default [])", }, cli.StringFlag{ Name: "format", - Usage: "change the output format to a Go template", + Usage: "Change the output format to a Go template", }, cli.IntFlag{ Name: "limit", - Usage: "limit the number of results", + Usage: "Limit the number of results", }, cli.BoolFlag{ Name: "no-trunc", - Usage: "do not truncate the output", + Usage: "Do not truncate the output", }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, } searchDescription = ` diff --git a/cmd/podman/start.go b/cmd/podman/start.go index df34deec2..f6e1d9882 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -29,7 +29,7 @@ var ( }, cli.BoolTFlag{ Name: "sig-proxy", - Usage: "proxy received signals to the process (default true if attaching, false otherwise)", + Usage: "Proxy received signals to the process (default true if attaching, false otherwise)", }, LatestFlag, } diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go index f6beac1a8..769354b23 100644 --- a/cmd/podman/stats.go +++ b/cmd/podman/stats.go @@ -31,23 +31,23 @@ var ( statsFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "show all containers. Only running containers are shown by default. The default is false", + Usage: "Show all containers. Only running containers are shown by default. The default is false", }, cli.BoolFlag{ Name: "no-stream", - Usage: "disable streaming stats and only pull the first result, default setting is false", + Usage: "Disable streaming stats and only pull the first result, default setting is false", }, cli.StringFlag{ Name: "format", - Usage: "pretty-print container statistics to JSON or using a Go template", + Usage: "Pretty-print container statistics to JSON or using a Go template", }, cli.BoolFlag{ Name: "no-reset", - Usage: "disable resetting the screen between intervals", + Usage: "Disable resetting the screen between intervals", }, LatestFlag, } - statsDescription = "display a live stream of one or more containers' resource usage statistics" + statsDescription = "Display a live stream of one or more containers' resource usage statistics" statsCommand = cli.Command{ Name: "stats", Usage: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for one or more containers", diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go index ade51705e..204515c70 100644 --- a/cmd/podman/stop.go +++ b/cmd/podman/stop.go @@ -21,7 +21,7 @@ var ( }, cli.BoolFlag{ Name: "all, a", - Usage: "stop all running containers", + Usage: "Stop all running containers", }, LatestFlag, } stopDescription = ` diff --git a/cmd/podman/system.go b/cmd/podman/system.go new file mode 100644 index 000000000..9596252ad --- /dev/null +++ b/cmd/podman/system.go @@ -0,0 +1,29 @@ +package main + +import ( + "sort" + + "github.com/urfave/cli" +) + +var ( + systemSubCommands = []cli.Command{ + pruneSystemCommand, + } + systemDescription = "Manage podman" + systemCommand = cli.Command{ + Name: "system", + Usage: "Manage podman", + Description: systemDescription, + ArgsUsage: "", + Subcommands: getSystemSubCommandsSorted(), + UseShortOptionHandling: true, + OnUsageError: usageErrorHandler, + } +) + +func getSystemSubCommandsSorted() []cli.Command { + systemSubCommands = append(systemSubCommands, getSystemSubCommands()...) + sort.Sort(commandSortedAlpha{systemSubCommands}) + return systemSubCommands +} diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go new file mode 100644 index 000000000..64d291560 --- /dev/null +++ b/cmd/podman/system_prune.go @@ -0,0 +1,107 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/containers/libpod/cmd/podman/shared" + "github.com/containers/libpod/libpod/adapter" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" +) + +var ( + pruneSystemDescription = ` + podman system prune + + Remove unused data +` + pruneSystemFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "Remove all unused data", + }, + cli.BoolFlag{ + Name: "force, f", + Usage: "Do not prompt for confirmation", + }, + cli.BoolFlag{ + Name: "volumes", + Usage: "Prune volumes", + }, + } + pruneSystemCommand = cli.Command{ + Name: "prune", + Usage: "Remove unused data", + Description: pruneSystemDescription, + Action: pruneSystemCmd, + OnUsageError: usageErrorHandler, + Flags: pruneSystemFlags, + } +) + +func pruneSystemCmd(c *cli.Context) error { + + // Prompt for confirmation if --force is not set + if !c.Bool("force") { + reader := bufio.NewReader(os.Stdin) + volumeString := "" + if c.Bool("volumes") { + volumeString = ` + - all volumes not used by at least one container` + } + fmt.Printf(` +WARNING! This will remove: + - all stopped containers%s + - all dangling images + - all build cache +Are you sure you want to continue? [y/N] `, volumeString) + 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(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + + ctx := getContext() + fmt.Println("Deleted Containers") + lasterr := pruneContainers(runtime, ctx, shared.Parallelize("rm"), false) + if c.Bool("volumes") { + fmt.Println("Deleted Volumes") + err := volumePrune(runtime, getContext()) + if err != nil { + if lasterr != nil { + logrus.Errorf("%q", lasterr) + } + lasterr = err + } + } + + // Call prune; if any cids are returned, print them and then + // return err in case an error also came up + pruneCids, err := runtime.PruneImages(c.Bool("all")) + if len(pruneCids) > 0 { + fmt.Println("Deleted Images") + for _, cid := range pruneCids { + fmt.Println(cid) + } + } + if err != nil { + if lasterr != nil { + logrus.Errorf("%q", lasterr) + } + lasterr = err + } + return lasterr +} diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go index 42f169228..ab6925e65 100644 --- a/cmd/podman/umount.go +++ b/cmd/podman/umount.go @@ -15,11 +15,11 @@ var ( umountFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "umount all of the currently mounted containers", + Usage: "Umount all of the currently mounted containers", }, cli.BoolFlag{ Name: "force, f", - Usage: "force the complete umount all of the currently mounted containers", + Usage: "Force the complete umount all of the currently mounted containers", }, LatestFlag, } diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go index d77e056f8..91b5fda33 100644 --- a/cmd/podman/unpause.go +++ b/cmd/podman/unpause.go @@ -15,7 +15,7 @@ var ( unpauseFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "unpause all paused containers", + Usage: "Unpause all paused containers", }, } unpauseDescription = ` diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go index a7c195041..38ce77415 100644 --- a/cmd/podman/varlink.go +++ b/cmd/podman/varlink.go @@ -24,7 +24,7 @@ var ( varlinkFlags = []cli.Flag{ cli.IntFlag{ Name: "timeout, t", - Usage: "time until the varlink session expires in milliseconds. Use 0 to disable the timeout.", + Usage: "Time until the varlink session expires in milliseconds. Use 0 to disable the timeout.", Value: 1000, }, } diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go index 652c50f42..41d95f9c7 100644 --- a/cmd/podman/volume_prune.go +++ b/cmd/podman/volume_prune.go @@ -2,12 +2,13 @@ package main import ( "bufio" + "context" "fmt" "os" "strings" - "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -37,21 +38,40 @@ var volumePruneCommand = cli.Command{ UseShortOptionHandling: true, } -func volumePruneCmd(c *cli.Context) error { +func volumePrune(runtime *adapter.LocalRuntime, ctx context.Context) error { var lastError error + volumes, err := runtime.GetAllVolumes() + if err != nil { + return err + } + + for _, vol := range volumes { + err = runtime.RemoveVolume(ctx, vol, false, true) + if err == nil { + fmt.Println(vol.Name()) + } else if err != libpod.ErrVolumeBeingUsed { + if lastError != nil { + logrus.Errorf("%q", lastError) + } + lastError = errors.Wrapf(err, "failed to remove volume %q", vol.Name()) + } + } + return lastError +} + +func volumePruneCmd(c *cli.Context) error { + if err := validateFlags(c, volumePruneFlags); err != nil { return err } - runtime, err := libpodruntime.GetRuntime(c) + runtime, err := adapter.GetRuntime(c) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } defer runtime.Shutdown(false) - ctx := getContext() - // Prompt for confirmation if --force is not set if !c.Bool("force") { reader := bufio.NewReader(os.Stdin) @@ -66,21 +86,5 @@ func volumePruneCmd(c *cli.Context) error { } } - volumes, err := runtime.GetAllVolumes() - if err != nil { - return err - } - - for _, vol := range volumes { - err = runtime.RemoveVolume(ctx, vol, false, true) - if err == nil { - fmt.Println(vol.Name()) - } else if err != libpod.ErrVolumeBeingUsed { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "failed to remove volume %q", vol.Name()) - } - } - return lastError + return volumePrune(runtime, getContext()) } diff --git a/commands.md b/commands.md index 00be4f1bd..c7d03d5ad 100644 --- a/commands.md +++ b/commands.md @@ -66,6 +66,7 @@ | [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|[![...](/docs/play.png)](https://asciinema.org/a/vfUPbAA5tsNWhsfB9p25T6xdr)| | [podman-stop(1)](/docs/podman-stop.1.md) | Stops one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/KNRF9xVXeaeNTNjBQVogvZBcp)| +| [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 |[![...](/docs/play.png)](https://asciinema.org/a/5WCCi1LXwSuRbvaO9cBUYf3fk)| | [podman-umount(1)](/docs/podman-umount.1.md) | Unmount a working container's root filesystem |[![...](/docs/play.png)](https://asciinema.org/a/MZPTWD5CVs3dMREkBxQBY9C5z)| diff --git a/completions/bash/podman b/completions/bash/podman index e0de4586c..9df87aef4 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -979,6 +979,51 @@ _podman_container() { esac } +_podman_system_info() { + _podman_info +} + +_podman_system_prune() { + local options_with_args=" + " + + local boolean_options=" + -a + --all + -f + --force + -h + --help + --volumes + " + case "$cur" in + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + esac +} + +_podman_system() { + local boolean_options=" + --help + -h + " + subcommands=" + info + prune + " + __podman_subcommands "$subcommands" && return + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac +} + _podman_commit() { local options_with_args=" --author @@ -2482,6 +2527,11 @@ _podman_container_prune() { -h --help " + case "$cur" in + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + esac } _podman_container_exists() { diff --git a/docs/links/podman-system-info.1 b/docs/links/podman-system-info.1 new file mode 100644 index 000000000..809a71b8b --- /dev/null +++ b/docs/links/podman-system-info.1 @@ -0,0 +1 @@ +.so man1/podman-info.1 diff --git a/docs/podman-info.1.md b/docs/podman-info.1.md index d3a0658c9..a6579ec1f 100644 --- a/docs/podman-info.1.md +++ b/docs/podman-info.1.md @@ -1,9 +1,9 @@ -% podman-version(1) +% podman-info(1) ## NAME +podman\-system\-info - Display system information podman\-info - Display system information - ## SYNOPSIS **podman info** [*options*] diff --git a/docs/podman-system-prune.1.md b/docs/podman-system-prune.1.md new file mode 100644 index 000000000..1cdafb774 --- /dev/null +++ b/docs/podman-system-prune.1.md @@ -0,0 +1,37 @@ +% podman-system-prune(1) podman + +## NAME +podman\-system\-prune - Remove all unused container, image and volume data + +## SYNOPSIS +**podman system prune** +[**-all**|**--a**] +[**-force**|**--f**] +[**-help**|**--h**] +[**-volumes**|**--v**] + +## DESCRIPTION +**podman system prune** removes all unused containers, (both dangling and unreferenced) from local storage and optionally, volumes. + +With the `all` option, you can delete all unused images. Unused images are dangling images as well as any image that does not have any containers based on it. + +By default, volumes are not removed to prevent important data from being deleted if there is currently no container using the volume. Use the --volumes flag when running the command to prune volumes as well. + +## OPTIONS +**--all, -a** + +Remove all unused images not just dangling ones. + +**--force, -f** + +Do not prompt for confirmation + +**--volumes** + +Prune volumes not used by at least one container + +## SEE ALSO +podman(1), podman-image-prune(1), podman-container-prune(1), podman-volume-prune(1) + +# HISTORY +February 2019, Originally compiled by Dan Walsh (dwalsh at redhat dot com) diff --git a/docs/podman-system.1.md b/docs/podman-system.1.md new file mode 100644 index 000000000..1b4bccdb9 --- /dev/null +++ b/docs/podman-system.1.md @@ -0,0 +1,20 @@ +% podman-system(1) + +## NAME +podman\-system - Manage podman + +## SYNOPSIS +**podman system** *subcommand* + +## DESCRIPTION +The system command allows you to manage the podman systems + +## COMMANDS + +| Command | Man Page | Description | +| ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- | +| 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 data | + +## SEE ALSO +podman diff --git a/docs/podman.1.md b/docs/podman.1.md index 6200a07f0..51ef00383 100644 --- a/docs/podman.1.md +++ b/docs/podman.1.md @@ -162,6 +162,7 @@ the exit codes follow the `chroot` standard, see below: | [podman-start(1)](podman-start.1.md) | Starts one or more containers. | | [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. | | [podman-stop(1)](podman-stop.1.md) | Stop one or more running containers. | +| [podman-system(1)](podman-system.1.md) | Manage podman. | | [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. | | [podman-top(1)](podman-top.1.md) | Display the running processes of a container. | | [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. | diff --git a/libpod/adapter/runtime_remote.go b/libpod/adapter/runtime_remote.go index 07c786184..c73e98c95 100644 --- a/libpod/adapter/runtime_remote.go +++ b/libpod/adapter/runtime_remote.go @@ -407,3 +407,28 @@ func (r *LocalRuntime) Import(ctx context.Context, source, reference string, cha } return iopodman.ImportImage().Call(r.Conn, strings.TrimRight(tempFile, ":"), reference, history, changes, true) } + +// GetAllVolumes retrieves all the volumes +func (r *LocalRuntime) GetAllVolumes() ([]*libpod.Volume, error) { + return nil, libpod.ErrNotImplemented +} + +// RemoveVolume removes a volumes +func (r *LocalRuntime) RemoveVolume(ctx context.Context, v *libpod.Volume, force, prune bool) error { + return libpod.ErrNotImplemented +} + +// GetContainers retrieves all containers from the state +// Filters can be provided which will determine what containers are included in +// the output. Multiple filters are handled by ANDing their output, so only +// containers matching all filters are returned +func (r *LocalRuntime) GetContainers(filters ...libpod.ContainerFilter) ([]*libpod.Container, error) { + return nil, libpod.ErrNotImplemented +} + +// RemoveContainer removes the given container +// If force is specified, the container will be stopped first +// Otherwise, RemoveContainer will return an error if the container is running +func (r *LocalRuntime) RemoveContainer(ctx context.Context, c *libpod.Container, force bool) error { + return libpod.ErrNotImplemented +} diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 39c1501da..b0dcc853e 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -392,7 +392,9 @@ func resetState(state *ContainerState) error { state.PID = 0 state.Mountpoint = "" state.Mounted = false - state.State = ContainerStateConfigured + if state.State != ContainerStateExited { + state.State = ContainerStateConfigured + } state.ExecSessions = make(map[string]*ExecSession) state.NetworkStatus = nil state.BindMounts = make(map[string]string) diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index 46105af4a..76b8963ff 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -9,6 +9,7 @@ import ( "github.com/containers/storage/pkg/mount" "github.com/docker/docker/daemon/caps" "github.com/docker/go-units" + "github.com/opencontainers/runc/libcontainer/user" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" "github.com/pkg/errors" @@ -45,6 +46,18 @@ func supercedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.M return configMount } +func getAvailableGids() (int64, error) { + idMap, err := user.ParseIDMapFile("/proc/self/gid_map") + if err != nil { + return 0, err + } + count := int64(0) + for _, r := range idMap { + count += r.Count + } + return count, nil +} + // CreateConfigToOCISpec parses information needed to create a container into an OCI runtime spec func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint cgroupPerm := "ro" @@ -91,14 +104,21 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint g.AddMount(sysMnt) } if isRootless { - g.RemoveMount("/dev/pts") - devPts := spec.Mount{ - Destination: "/dev/pts", - Type: "devpts", - Source: "devpts", - Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"}, + nGids, err := getAvailableGids() + if err != nil { + return nil, err + } + if nGids < 5 { + // If we have no GID mappings, the gid=5 default option would fail, so drop it. + g.RemoveMount("/dev/pts") + devPts := spec.Mount{ + Destination: "/dev/pts", + Type: "devpts", + Source: "devpts", + Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"}, + } + g.AddMount(devPts) } - g.AddMount(devPts) } if inUserNS && config.IpcMode.IsHost() { g.RemoveMount("/dev/mqueue") diff --git a/pkg/util/utils.go b/pkg/util/utils.go index e0b94b011..52f431881 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -301,36 +301,36 @@ func getTomlStorage(storeOptions *storage.StoreOptions) *tomlConfig { // for the volume API // It also returns the path where all named volumes will be created using the volume API func GetDefaultStoreOptions() (storage.StoreOptions, string, error) { + var ( + defaultRootlessRunRoot string + defaultRootlessGraphRoot string + err error + ) storageOpts := storage.DefaultStoreOptions volumePath := "/var/lib/containers/storage" + if rootless.IsRootless() { - var err error storageOpts, err = GetRootlessStorageOpts() if err != nil { return storageOpts, volumePath, err } + volumePath, err = GetRootlessVolumeInfo() if err != nil { return storageOpts, volumePath, err } + } - storageConf := StorageConfigFile() - if _, err := os.Stat(storageConf); err == nil { - defaultRootlessRunRoot := storageOpts.RunRoot - defaultRootlessGraphRoot := storageOpts.GraphRoot - storageOpts = storage.StoreOptions{} - storage.ReloadConfigurationFile(storageConf, &storageOpts) + storageConf := StorageConfigFile() + if _, err = os.Stat(storageConf); err == nil { + defaultRootlessRunRoot = storageOpts.RunRoot + defaultRootlessGraphRoot = storageOpts.GraphRoot + storageOpts = storage.StoreOptions{} + storage.ReloadConfigurationFile(storageConf, &storageOpts) + } - // If the file did not specify a graphroot or runroot, - // set sane defaults so we don't try and use root-owned - // directories - if storageOpts.RunRoot == "" { - storageOpts.RunRoot = defaultRootlessRunRoot - } - if storageOpts.GraphRoot == "" { - storageOpts.GraphRoot = defaultRootlessGraphRoot - } - } else if os.IsNotExist(err) { + if rootless.IsRootless() { + if os.IsNotExist(err) { os.MkdirAll(filepath.Dir(storageConf), 0755) file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) if err != nil { @@ -343,6 +343,16 @@ func GetDefaultStoreOptions() (storage.StoreOptions, string, error) { if err := enc.Encode(tomlConfiguration); err != nil { os.Remove(storageConf) } + } else if err == nil { + // If the file did not specify a graphroot or runroot, + // set sane defaults so we don't try and use root-owned + // directories + if storageOpts.RunRoot == "" { + storageOpts.RunRoot = defaultRootlessRunRoot + } + if storageOpts.GraphRoot == "" { + storageOpts.GraphRoot = defaultRootlessGraphRoot + } } } return storageOpts, volumePath, nil diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go index 637c04e0a..a50c27dda 100644 --- a/test/e2e/info_test.go +++ b/test/e2e/info_test.go @@ -39,4 +39,10 @@ var _ = Describe("Podman Info", func() { Expect(session.ExitCode()).To(Equal(0)) }) + It("podman system info json output", func() { + session := podmanTest.Podman([]string{"system", "info", "--format=json"}) + session.Wait() + Expect(session.ExitCode()).To(Equal(0)) + + }) }) diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go index 81fb82b20..74cdc126f 100644 --- a/test/e2e/prune_test.go +++ b/test/e2e/prune_test.go @@ -88,4 +88,17 @@ var _ = Describe("Podman rm", func() { Expect(len(images.OutputToStringArray())).To(Equal(0)) }) + It("podman system image prune unused images", func() { + SkipIfRemote() + podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true") + prune := podmanTest.Podman([]string{"system", "prune", "-a", "--force"}) + prune.WaitWithDefaultTimeout() + Expect(prune.ExitCode()).To(Equal(0)) + + images := podmanTest.Podman([]string{"images", "-a"}) + images.WaitWithDefaultTimeout() + // all images are unused, so they all should be deleted! + Expect(len(images.OutputToStringArray())).To(Equal(0)) + }) + }) diff --git a/test/e2e/run_signal_test.go b/test/e2e/run_signal_test.go index 9be8e7810..51c14602e 100644 --- a/test/e2e/run_signal_test.go +++ b/test/e2e/run_signal_test.go @@ -55,7 +55,7 @@ var _ = Describe("Podman run with --sig-proxy", func() { _, pid := podmanTest.PodmanPID([]string{"run", "-it", "-v", fmt.Sprintf("%s:/h:Z", udsDir), fedoraMinimal, "bash", "-c", sigCatch}) - uds, _ := os.OpenFile(udsPath, os.O_RDONLY, 0600) + uds, _ := os.OpenFile(udsPath, os.O_RDONLY|syscall.O_NONBLOCK, 0600) defer uds.Close() // Wait for the script in the container to alert us that it is READY @@ -73,7 +73,7 @@ var _ = Describe("Podman run with --sig-proxy", func() { } time.Sleep(1 * time.Second) if counter == 15 { - os.Exit(1) + Fail("Timed out waiting for READY from container") } counter++ } @@ -99,7 +99,7 @@ var _ = Describe("Podman run with --sig-proxy", func() { } time.Sleep(1 * time.Second) if counter == 15 { - os.Exit(1) + Fail("timed out waiting for FOO from container") } counter++ } diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go index 008acc2a2..802f3fc4a 100644 --- a/test/e2e/volume_prune_test.go +++ b/test/e2e/volume_prune_test.go @@ -63,4 +63,34 @@ var _ = Describe("Podman volume prune", func() { podmanTest.Cleanup() }) + + It("podman system prune --volume", func() { + session := podmanTest.Podman([]string{"volume", "create"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"volume", "create"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"create", "-v", "myvol:/myvol", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"volume", "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(4)) + + session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"volume", "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(2)) + + podmanTest.Cleanup() + }) }) diff --git a/transfer.md b/transfer.md index c0d309575..af7904e5f 100644 --- a/transfer.md +++ b/transfer.md @@ -76,7 +76,10 @@ There are other equivalents for these tools | `docker volume ls` | [`podman volume ls`](./docs/podman-volume-ls.1.md) | | `docker volume prune` | [`podman volume prune`](./docs/podman-volume-prune.1.md) | | `docker volume rm` | [`podman volume rm`](./docs/podman-volume-rm.1.md) | -| `docker wait` | [`podman wait`](./docs/podman-wait.1.md) | +| `docker system` | [`podman system`](./docs/podman-system.1.md) | +| `docker system prune` | [`podman system prune`](./docs/podman-system-prune.1.md) | +| `docker system info` | [`podman system info`](./docs/podman-system-info.1.md) | +| `docker wait` | [`podman wait`](./docs/podman-wait.1.md) | **** Use mount to take advantage of the entire linux tool chain rather then just cp. Read [`here`](./docs/podman-cp.1.md) for more information. @@ -95,7 +98,6 @@ Those Docker commands currently do not have equivalents in `podman`: | `docker service` || | `docker stack` || | `docker swarm` | podman does not support swarm. We support Kubernetes for orchestration using [CRI-O](https://github.com/kubernetes-sigs/cri-o).| -| `docker system` || | `docker volume` | podman currently supports file volumes. Future enhancement planned to support Docker Volumes Plugins ## Missing commands in Docker |