summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml66
-rw-r--r--.gitignore1
-rw-r--r--Makefile33
-rw-r--r--cmd/podman/attach.go2
-rw-r--r--cmd/podman/build.go17
-rw-r--r--cmd/podman/checkpoint.go2
-rw-r--r--cmd/podman/cleanup.go2
-rw-r--r--cmd/podman/commit.go2
-rw-r--r--cmd/podman/common.go26
-rw-r--r--cmd/podman/containers_prune.go2
-rw-r--r--cmd/podman/cp.go8
-rw-r--r--cmd/podman/create.go2
-rw-r--r--cmd/podman/diff.go9
-rw-r--r--cmd/podman/events.go4
-rw-r--r--cmd/podman/exec.go2
-rw-r--r--cmd/podman/exists.go6
-rw-r--r--cmd/podman/export.go2
-rw-r--r--cmd/podman/generate_kube.go2
-rw-r--r--cmd/podman/generate_systemd.go2
-rw-r--r--cmd/podman/healthcheck_run.go1
-rw-r--r--cmd/podman/history.go2
-rw-r--r--cmd/podman/images.go2
-rw-r--r--cmd/podman/images_prune.go2
-rw-r--r--cmd/podman/import.go2
-rw-r--r--cmd/podman/info.go6
-rw-r--r--cmd/podman/init.go2
-rw-r--r--cmd/podman/inspect.go6
-rw-r--r--cmd/podman/kill.go2
-rw-r--r--cmd/podman/load.go4
-rw-r--r--cmd/podman/login.go3
-rw-r--r--cmd/podman/logout.go3
-rw-r--r--cmd/podman/logs.go5
-rw-r--r--cmd/podman/main.go5
-rw-r--r--cmd/podman/main_local.go18
-rw-r--r--cmd/podman/mount.go2
-rw-r--r--cmd/podman/pause.go2
-rw-r--r--cmd/podman/play_kube.go8
-rw-r--r--cmd/podman/pod_create.go8
-rw-r--r--cmd/podman/pod_inspect.go2
-rw-r--r--cmd/podman/pod_kill.go2
-rw-r--r--cmd/podman/pod_pause.go2
-rw-r--r--cmd/podman/pod_ps.go10
-rw-r--r--cmd/podman/pod_restart.go2
-rw-r--r--cmd/podman/pod_rm.go2
-rw-r--r--cmd/podman/pod_start.go2
-rw-r--r--cmd/podman/pod_stats.go23
-rw-r--r--cmd/podman/pod_stop.go2
-rw-r--r--cmd/podman/pod_top.go12
-rw-r--r--cmd/podman/pod_unpause.go2
-rw-r--r--cmd/podman/pods_prune.go5
-rw-r--r--cmd/podman/port.go5
-rw-r--r--cmd/podman/ps.go109
-rw-r--r--cmd/podman/pull.go7
-rw-r--r--cmd/podman/push.go7
-rw-r--r--cmd/podman/refresh.go2
-rw-r--r--cmd/podman/restart.go2
-rw-r--r--cmd/podman/restore.go2
-rw-r--r--cmd/podman/rm.go2
-rw-r--r--cmd/podman/rmi.go2
-rw-r--r--cmd/podman/run.go3
-rw-r--r--cmd/podman/runlabel.go18
-rw-r--r--cmd/podman/save.go2
-rw-r--r--cmd/podman/search.go11
-rw-r--r--cmd/podman/shared/create.go10
-rw-r--r--cmd/podman/shared/funcs.go15
-rw-r--r--cmd/podman/sign.go2
-rw-r--r--cmd/podman/start.go2
-rw-r--r--cmd/podman/stats.go6
-rw-r--r--cmd/podman/stop.go2
-rw-r--r--cmd/podman/system_df.go31
-rw-r--r--cmd/podman/system_prune.go26
-rw-r--r--cmd/podman/tag.go2
-rw-r--r--cmd/podman/top.go11
-rw-r--r--cmd/podman/tree.go2
-rw-r--r--cmd/podman/trust_set_show.go11
-rw-r--r--cmd/podman/umount.go2
-rw-r--r--cmd/podman/unpause.go2
-rw-r--r--cmd/podman/utils.go32
-rw-r--r--cmd/podman/varlink.go2
-rw-r--r--cmd/podman/version.go12
-rw-r--r--cmd/podman/volume_create.go2
-rw-r--r--cmd/podman/volume_inspect.go2
-rw-r--r--cmd/podman/volume_ls.go2
-rw-r--r--cmd/podman/volume_prune.go2
-rw-r--r--cmd/podman/volume_rm.go2
-rw-r--r--cmd/podman/wait.go2
-rw-r--r--contrib/cirrus/README.md36
-rwxr-xr-xcontrib/cirrus/build_vm_images.sh13
-rwxr-xr-xcontrib/cirrus/cache_release_archive.sh140
-rwxr-xr-xcontrib/cirrus/integration_test.sh73
-rw-r--r--contrib/cirrus/lib.sh187
-rw-r--r--contrib/cirrus/packer/fedora_setup.sh24
-rw-r--r--contrib/cirrus/packer/libpod_images.yml18
-rw-r--r--contrib/cirrus/packer/ubuntu_setup.sh47
-rwxr-xr-xcontrib/cirrus/rootless_test.sh2
-rwxr-xr-xcontrib/cirrus/setup_environment.sh22
l---------contrib/cirrus/uncache_release_archives.sh1
-rwxr-xr-xcontrib/cirrus/unit_test.sh17
-rw-r--r--docs/podman-create.1.md2
-rw-r--r--docs/podman-generate-systemd.1.md4
-rw-r--r--docs/podman-run.1.md2
-rw-r--r--docs/podman-stats.1.md2
-rw-r--r--libpod/boltdb_state.go66
-rw-r--r--libpod/boltdb_state_internal.go18
-rw-r--r--libpod/common_test.go16
-rw-r--r--libpod/container.go3
-rw-r--r--libpod/container_attach_linux.go11
-rw-r--r--libpod/container_inspect.go16
-rw-r--r--libpod/container_internal.go38
-rw-r--r--libpod/container_internal_linux.go67
-rw-r--r--libpod/healthcheck_linux.go49
-rw-r--r--libpod/image/image.go30
-rw-r--r--libpod/image/pull.go6
-rw-r--r--libpod/image/search.go4
-rw-r--r--libpod/kube.go23
-rw-r--r--libpod/networking_linux.go17
-rw-r--r--libpod/oci.go20
-rw-r--r--libpod/oci_linux.go25
-rw-r--r--libpod/options.go2
-rw-r--r--libpod/runtime.go17
-rw-r--r--libpod/runtime_ctr.go21
-rw-r--r--libpod/runtime_migrate.go4
-rw-r--r--libpod/stats.go4
-rw-r--r--libpod/util.go20
-rw-r--r--pkg/adapter/containers.go21
-rw-r--r--pkg/adapter/runtime_remote.go8
-rw-r--r--pkg/adapter/sigproxy_linux.go4
-rw-r--r--pkg/adapter/terminal_linux.go4
-rw-r--r--pkg/cgroups/blkio.go4
-rw-r--r--pkg/cgroups/cgroups.go93
-rw-r--r--pkg/cgroups/cpu.go19
-rw-r--r--pkg/cgroups/cpuset.go22
-rw-r--r--pkg/cgroups/memory.go5
-rw-r--r--pkg/cgroups/pids.go6
-rw-r--r--pkg/channelwriter/channelwriter.go34
-rw-r--r--pkg/errorhandling/errorhandling.go23
-rw-r--r--pkg/firewall/firewalld.go5
-rw-r--r--pkg/firewall/iptables.go9
-rw-r--r--pkg/hooks/exec/exec.go5
-rw-r--r--pkg/logs/logs.go7
-rw-r--r--pkg/netns/netns_linux.go4
-rw-r--r--pkg/rootless/rootless_linux.go54
-rw-r--r--pkg/spec/spec.go8
-rw-r--r--pkg/systemdgen/systemdgen.go28
-rw-r--r--pkg/systemdgen/systemdgen_test.go18
-rw-r--r--pkg/util/utils.go16
-rw-r--r--pkg/util/utils_supported.go9
-rw-r--r--pkg/varlinkapi/images.go108
-rw-r--r--pkg/varlinkapi/util.go40
-rw-r--r--rootless.md8
-rw-r--r--test/README.md23
-rw-r--r--test/e2e/checkpoint_test.go96
-rw-r--r--test/e2e/common_test.go13
-rw-r--r--test/e2e/pod_rm_test.go17
-rw-r--r--test/e2e/push_test.go4
-rw-r--r--test/e2e/rmi_test.go4
-rw-r--r--test/e2e/run_signal_test.go8
-rw-r--r--test/e2e/stats_test.go2
-rw-r--r--test/e2e/tree_test.go6
-rw-r--r--test/system/070-build.bats3
-rw-r--r--test/system/250-generate-systemd.bats46
-rw-r--r--test/system/README.md9
-rw-r--r--test/system/helpers.bash11
-rwxr-xr-xtest/test_podman_baseline.sh22
-rw-r--r--utils/utils.go5
-rw-r--r--vendor/modules.txt6
166 files changed, 1623 insertions, 974 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index a019f4072..da28bb597 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -29,9 +29,9 @@ env:
####
#### Cache-image names to test with
###
- FEDORA_CACHE_IMAGE_NAME: "fedora-30-libpod-5699414987898880"
- PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-5699414987898880"
- UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-5699414987898880"
+ FEDORA_CACHE_IMAGE_NAME: "fedora-30-libpod-5081463649730560"
+ PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-5081463649730560"
+ UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-5081463649730560"
####
#### Variables for composing new cache-images (used in PR testing) from
@@ -215,7 +215,8 @@ build_each_commit_task:
on_failure:
failed_master_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_master_failure.sh'
-build_without_cgo:
+
+build_without_cgo_task:
depends_on:
- "gating"
@@ -310,6 +311,9 @@ testing_task:
unit_test_script: '$SCRIPT_BASE/unit_test.sh |& ${TIMESTAMP}'
integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}'
+ cache_release_archive_script: >-
+ [[ "$TEST_REMOTE_CLIENT" == "false" ]] || \
+ $SCRIPT_BASE/cache_release_archive.sh |& ${TIMESTAMP}
on_failure:
failed_master_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_master_failure.sh'
@@ -379,6 +383,29 @@ special_testing_in_podman_task:
<<: *standardlogs
+special_testing_cross_task:
+
+ depends_on:
+ - "gating"
+ - "varlink_api"
+ - "vendor"
+
+ only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*'
+
+ env:
+ matrix:
+ SPECIALMODE: 'windows' # See docs
+ SPECIALMODE: 'darwin'
+
+ timeout_in: 20m
+
+ setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
+ cache_release_archive_script: '$SCRIPT_BASE/cache_release_archive.sh |& ${TIMESTAMP}'
+
+ on_failure:
+ failed_master_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_master_failure.sh'
+
+
# Test building of new cache-images for future PR testing, in this PR.
test_build_cache_images_task:
@@ -449,24 +476,25 @@ verify_test_built_images_task:
always:
<<: *standardlogs
-
-# Post message to IRC if everything passed
+# Post message to IRC if everything passed PR testing
success_task:
only_if: $CIRRUS_BRANCH != 'master'
- depends_on: # ignores any dependent task conditions
+ # ignores any dependent task conditions, include everything except 'release'
+ depends_on: &alltasks
- "gating"
- "vendor"
- "varlink_api"
- "build_each_commit"
+ - "build_without_cgo"
- "meta"
- "testing"
- "special_testing_rootless"
- "special_testing_in_podman"
+ - "special_testing_cross"
- "test_build_cache_images"
- "verify_test_built_images"
- - "build_without_cgo"
env:
CIRRUS_WORKING_DIR: "/usr/src/libpod"
@@ -479,3 +507,25 @@ success_task:
memory: 1
success_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/success.sh |& ${TIMESTAMP}'
+
+
+release_task:
+
+ # TODO: Uncomment both to not affect pass/fail status of entire job?
+ # allow_failures: $CI == "true"
+ # skip_notifications: $CI == "true"
+
+ depends_on: *alltasks
+
+ gce_instance:
+ image_name: "${IMAGE_BUILDER_CACHE_IMAGE_NAME}"
+
+ timeout_in: 30m
+
+ env:
+ CIRRUS_CLONE_DEPTH: 1 # source is not used, only Makefile
+ GCPJSON: ENCRYPTED[789d8f7e9a5972ce350fd8e60f1032ccbf4a35c3938b604774b711aad280e12c21faf10e25af1e0ba33597ffb9e39e46]
+ GCPNAME: ENCRYPTED[417d50488a4bd197bcc925ba6574de5823b97e68db1a17e3a5fde4bcf26576987345e75f8d9ea1c15a156b4612c072a1]
+ GCPROJECT: ENCRYPTED[7c80e728e046b1c76147afd156a32c1c57d4a1ac1eab93b7e68e718c61ca8564fc61fef815952b8ae0a64e7034b8fe4f]
+
+ uncache_release_archives_script: '$SCRIPT_BASE/uncache_release_archives.sh |& ${TIMESTAMP}'
diff --git a/.gitignore b/.gitignore
index 020621558..b26674172 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ __pycache__
/cmd/podman/varlink/iopodman.go
.gopathok
test/e2e/e2e.coverprofile
+/podman*zip
diff --git a/Makefile b/Makefile
index 1f98fe8e3..140b2e149 100644
--- a/Makefile
+++ b/Makefile
@@ -69,11 +69,16 @@ LDFLAGS_PODMAN ?= $(LDFLAGS) \
-X $(LIBPOD).etcDir=$(ETCDIR)
#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=90m
+RELEASE_VERSION ?= $(shell git fetch --tags && git describe HEAD 2> /dev/null)
+RELEASE_DIST ?= $(shell ( source /etc/os-release; echo $$ID ))
+RELEASE_DIST_VER ?= $(shell ( source /etc/os-release; echo $$VERSION_ID | cut -d '.' -f 1))
+RELEASE_ARCH ?= $(shell go env GOARCH 2> /dev/null)
+RELEASE_BASENAME := $(shell basename $(PROJECT))
+
# If GOPATH not specified, use one in the local directory
ifeq ($(GOPATH),)
export GOPATH := $(CURDIR)/_output
@@ -148,10 +153,10 @@ podman-remote: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman on
$(GO) build -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS) remoteclient" -o bin/$@ $(PROJECT)/cmd/podman
podman-remote-darwin: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman on remote OSX environment
- GOOS=darwin $(GO) build -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "remoteclient containers_image_openpgp exclude_graphdriver_devicemapper" -o bin/$@ $(PROJECT)/cmd/podman
+ CGO_ENABLED=0 GOOS=darwin $(GO) build -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "remoteclient containers_image_openpgp exclude_graphdriver_devicemapper" -o bin/$@ $(PROJECT)/cmd/podman
podman-remote-windows: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman for a remote windows environment
- GOOS=windows $(GO) build -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "remoteclient containers_image_openpgp exclude_graphdriver_devicemapper" -o bin/$@.exe $(PROJECT)/cmd/podman
+ CGO_ENABLED=0 GOOS=windows $(GO) build -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "remoteclient containers_image_openpgp exclude_graphdriver_devicemapper" -o bin/$@.exe $(PROJECT)/cmd/podman
local-cross: $(CROSS_BUILD_TARGETS) ## Cross local compilation
@@ -165,6 +170,7 @@ clean: ## Clean artifacts
rm -rf \
.gopathok \
_output \
+ podman*.zip \
bin \
build \
test/checkseccomp/checkseccomp \
@@ -231,6 +237,8 @@ localintegration: varlink_generate test-binaries ginkgo
remoteintegration: varlink_generate test-binaries ginkgo-remote
localsystem:
+ # Wipe existing config, database, and cache: start with clean slate.
+ $(RM) -rf ${HOME}/.local/share/containers ${HOME}/.config/containers
if timeout -v 1 true; then PODMAN=./bin/podman bats test/system/; else echo "Skipping localsystem: 'timeout -v' unavailable'"; fi
remotesystem:
@@ -250,6 +258,23 @@ vagrant-check:
binaries: varlink_generate podman podman-remote ## Build podman
+# Zip archives are supported on all platforms + allows embedding metadata
+podman.zip: binaries docs
+ $(eval TMPDIR := $(shell mktemp -d -p '' $@_XXXX))
+ test -n "$(TMPDIR)"
+ $(MAKE) install "DESTDIR=$(TMPDIR)" "PREFIX=$(TMPDIR)/usr"
+ # Encoded RELEASE_INFO format depended upon by CI tooling
+ # X-RELEASE-INFO format depended upon by CI tooling
+ cd "$(TMPDIR)" && echo \
+ "X-RELEASE-INFO: $(RELEASE_BASENAME) $(RELEASE_VERSION) $(RELEASE_DIST) $(RELEASE_DIST_VER) $(RELEASE_ARCH)" | \
+ zip --recurse-paths --archive-comment "$(CURDIR)/$@" "./"
+ -rm -rf "$(TMPDIR)"
+
+podman-remote-%.zip: podman-remote-%
+ # Don't label darwin/windows cros-compiles with local distribution & version
+ echo "X-RELEASE-INFO: podman-remote $(RELEASE_VERSION) $* cc $(RELEASE_ARCH)" | \
+ zip --archive-comment "$(CURDIR)/$@" ./bin/$<*
+
install.catatonit:
./hack/install_catatonit.sh
@@ -384,7 +409,7 @@ install.libseccomp.sudo:
cmd/podman/varlink/iopodman.go: cmd/podman/varlink/io.podman.varlink
- $(GO) generate ./cmd/podman/varlink/...
+ GO111MODULE=off $(GO) generate ./cmd/podman/varlink/...
API.md: cmd/podman/varlink/io.podman.varlink
$(GO) generate ./docs/...
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go
index 48a25a3e2..b78633ed6 100644
--- a/cmd/podman/attach.go
+++ b/cmd/podman/attach.go
@@ -51,6 +51,6 @@ func attachCmd(c *cliconfig.AttachValues) error {
if err != nil {
return errors.Wrapf(err, "error creating runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
return runtime.Attach(getContext(), c)
}
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index 5e2b1aa82..bd7269390 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -57,14 +57,20 @@ func init() {
budFlags := buildahcli.GetBudFlags(&budFlagsValues)
flag := budFlags.Lookup("pull")
- flag.Value.Set("true")
+ if err := flag.Value.Set("true"); err != nil {
+ logrus.Error("unable to set pull flag to true")
+ }
flag.DefValue = "true"
layerFlags := buildahcli.GetLayerFlags(&layerValues)
flag = layerFlags.Lookup("layers")
- flag.Value.Set(useLayers())
+ if err := flag.Value.Set(useLayers()); err != nil {
+ logrus.Error("unable to set uselayers")
+ }
flag.DefValue = useLayers()
flag = layerFlags.Lookup("force-rm")
- flag.Value.Set("true")
+ if err := flag.Value.Set("true"); err != nil {
+ logrus.Error("unable to set force-rm flag to true")
+ }
flag.DefValue = "true"
fromAndBugFlags := buildahcli.GetFromAndBudFlags(&fromAndBudValues, &userNSValues, &namespaceValues)
@@ -72,7 +78,7 @@ func init() {
flags.AddFlagSet(&budFlags)
flags.AddFlagSet(&layerFlags)
flags.AddFlagSet(&fromAndBugFlags)
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
func getDockerfiles(files []string) []string {
@@ -177,7 +183,6 @@ func buildCmd(c *cliconfig.BuildValues) error {
}
contextDir = absDir
}
- cliArgs = Tail(cliArgs)
} else {
// No context directory or URL was specified. Try to use the
// home of the first locally-available Dockerfile.
@@ -218,7 +223,7 @@ func buildCmd(c *cliconfig.BuildValues) error {
}
// end from buildah
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
var stdout, stderr, reporter *os.File
stdout = os.Stdout
diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go
index bfb5b49d4..6755bb073 100644
--- a/cmd/podman/checkpoint.go
+++ b/cmd/podman/checkpoint.go
@@ -59,6 +59,6 @@ func checkpointCmd(c *cliconfig.CheckpointValues) error {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
return runtime.Checkpoint(c)
}
diff --git a/cmd/podman/cleanup.go b/cmd/podman/cleanup.go
index 9544b75b0..c00654162 100644
--- a/cmd/podman/cleanup.go
+++ b/cmd/podman/cleanup.go
@@ -52,7 +52,7 @@ func cleanupCmd(c *cliconfig.CleanupValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.CleanupContainers(getContext(), c)
if err != nil {
diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go
index c49645a1d..e98b71514 100644
--- a/cmd/podman/commit.go
+++ b/cmd/podman/commit.go
@@ -53,7 +53,7 @@ func commitCmd(c *cliconfig.CommitValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) != 2 {
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index 3cc645f95..50f3d9a7b 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -4,14 +4,13 @@ import (
"context"
"fmt"
"os"
- "path/filepath"
"strings"
"github.com/containers/buildah"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/rootless"
- "github.com/containers/storage"
"github.com/fatih/camelcase"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
@@ -19,8 +18,7 @@ import (
)
var (
- stores = make(map[storage.Store]struct{})
- json = jsoniter.ConfigCompatibleWithStandardLibrary
+ json = jsoniter.ConfigCompatibleWithStandardLibrary
)
const (
@@ -112,7 +110,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
"Attach to STDIN, STDOUT or STDERR (default [])",
)
createFlags.String(
- "authfile", getAuthFile(""),
+ "authfile", shared.GetAuthFile(""),
"Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override",
)
createFlags.String(
@@ -502,24 +500,6 @@ func getFormat(c *cliconfig.PodmanCommand) (string, error) {
return "", errors.Errorf("unrecognized image type %q", format)
}
-func getAuthFile(authfile string) string {
- if authfile != "" {
- return authfile
- }
- if remote {
- return ""
- }
- authfile = os.Getenv("REGISTRY_AUTH_FILE")
- if authfile != "" {
- return authfile
- }
- runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
- if runtimeDir != "" {
- return filepath.Join(runtimeDir, "containers/auth.json")
- }
- return ""
-}
-
// scrubServer removes 'http://' or 'https://' from the front of the
// server/registry string if either is there. This will be mostly used
// for user input from 'podman login' and 'podman logout'.
diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go
index 97481fb35..b8a84a0e3 100644
--- a/cmd/podman/containers_prune.go
+++ b/cmd/podman/containers_prune.go
@@ -43,7 +43,7 @@ func pruneContainersCmd(c *cliconfig.PruneContainersValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
maxWorkers := shared.DefaultPoolSize("prune")
if c.GlobalIsSet("max-workers") {
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index f6ac5f8f7..7c28edd26 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -68,7 +68,7 @@ func cpCmd(c *cliconfig.CpValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
return copyBetweenHostAndContainer(runtime, args[0], args[1], c.Extract, c.Pause)
}
@@ -95,7 +95,11 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
if err != nil {
return err
}
- defer ctr.Unmount(false)
+ defer func() {
+ if err := ctr.Unmount(false); err != nil {
+ logrus.Errorf("unable to umount container '%s': %q", ctr.ID(), err)
+ }
+ }()
// We can't pause rootless containers.
if pause && rootless.IsRootless() {
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 2351f5860..93141a800 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -57,7 +57,7 @@ func createCmd(c *cliconfig.CreateValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
cid, err := runtime.CreateContainer(getContext(), c)
if err != nil {
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 032c0f2c0..2b0c1d398 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -61,8 +61,7 @@ func init() {
flags.BoolVar(&diffCommand.Archive, "archive", true, "Save the diff as a tar archive")
flags.StringVar(&diffCommand.Format, "format", "", "Change the output format")
flags.BoolVarP(&diffCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
-
- flags.MarkHidden("archive")
+ markFlagHidden(flags, "archive")
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -93,7 +92,7 @@ func diffCmd(c *cliconfig.DiffValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
var to string
if c.Latest {
@@ -137,7 +136,5 @@ func diffCmd(c *cliconfig.DiffValues) error {
} else {
out = stdoutStruct{output: diffOutput}
}
- formats.Writer(out).Out()
-
- return nil
+ return formats.Writer(out).Out()
}
diff --git a/cmd/podman/events.go b/cmd/podman/events.go
index 88c1010e3..18126e626 100644
--- a/cmd/podman/events.go
+++ b/cmd/podman/events.go
@@ -36,7 +36,7 @@ func init() {
flags.BoolVar(&eventsCommand.Stream, "stream", true, "stream new events; for testing only")
flags.StringVar(&eventsCommand.Since, "since", "", "show all events created since timestamp")
flags.StringVar(&eventsCommand.Until, "until", "", "show all events until timestamp")
- flags.MarkHidden("stream")
+ markFlagHidden(flags, "stream")
}
func eventsCmd(c *cliconfig.EventValues) error {
@@ -44,7 +44,7 @@ func eventsCmd(c *cliconfig.EventValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
return runtime.Events(c)
}
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index bf8de69fc..799ed9f38 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -64,7 +64,7 @@ func execCmd(c *cliconfig.ExecValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
err = runtime.Exec(c, cmd)
if errors.Cause(err) == define.ErrCtrStateInvalid {
diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go
index 1e052e25f..f8b1f8e59 100644
--- a/cmd/podman/exists.go
+++ b/cmd/podman/exists.go
@@ -90,7 +90,7 @@ func imageExistsCmd(c *cliconfig.ImageExistsValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if _, err := runtime.NewImageFromLocal(args[0]); err != nil {
//TODO we need to ask about having varlink defined errors exposed
//so we can reuse them
@@ -111,7 +111,7 @@ func containerExistsCmd(c *cliconfig.ContainerExistsValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if _, err := runtime.LookupContainer(args[0]); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr || err.Error() == "io.podman.ContainerNotFound" {
os.Exit(1)
@@ -130,7 +130,7 @@ func podExistsCmd(c *cliconfig.PodExistsValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if _, err := runtime.LookupPod(args[0]); err != nil {
if errors.Cause(err) == define.ErrNoSuchPod || err.Error() == "io.podman.PodNotFound" {
diff --git a/cmd/podman/export.go b/cmd/podman/export.go
index f2336167b..27948004c 100644
--- a/cmd/podman/export.go
+++ b/cmd/podman/export.go
@@ -45,7 +45,7 @@ func exportCmd(c *cliconfig.ExportValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) == 0 {
diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go
index 3969e3132..6f04d6517 100644
--- a/cmd/podman/generate_kube.go
+++ b/cmd/podman/generate_kube.go
@@ -62,7 +62,7 @@ func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
podYAML, serviceYAML, err := runtime.GenerateKube(c)
if err != nil {
diff --git a/cmd/podman/generate_systemd.go b/cmd/podman/generate_systemd.go
index b4779e512..8be097c83 100644
--- a/cmd/podman/generate_systemd.go
+++ b/cmd/podman/generate_systemd.go
@@ -50,7 +50,7 @@ func generateSystemdCmd(c *cliconfig.GenerateSystemdValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
// User input stop timeout must be 0 or greater
if c.Flag("timeout").Changed && c.StopTimeout < 0 {
diff --git a/cmd/podman/healthcheck_run.go b/cmd/podman/healthcheck_run.go
index aaeed93c6..66ca4580a 100644
--- a/cmd/podman/healthcheck_run.go
+++ b/cmd/podman/healthcheck_run.go
@@ -42,6 +42,7 @@ func healthCheckCmd(c *cliconfig.HealthCheckValues) error {
if err != nil {
return errors.Wrap(err, "could not get runtime")
}
+ defer runtime.DeferredShutdown(false)
status, err := runtime.HealthCheck(c)
fmt.Println(status)
return err
diff --git a/cmd/podman/history.go b/cmd/podman/history.go
index 0998a023c..fea2219bc 100644
--- a/cmd/podman/history.go
+++ b/cmd/podman/history.go
@@ -71,7 +71,7 @@ func historyCmd(c *cliconfig.HistoryValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
format := genHistoryFormat(c.Format, c.Quiet)
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 33cf11ab7..f842573d9 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -138,7 +138,7 @@ func imagesCmd(c *cliconfig.ImagesValues) error {
if err != nil {
return errors.Wrapf(err, "Could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if len(c.InputArgs) == 1 {
image = c.InputArgs[0]
}
diff --git a/cmd/podman/images_prune.go b/cmd/podman/images_prune.go
index 1ac5bc65d..5745edd6b 100644
--- a/cmd/podman/images_prune.go
+++ b/cmd/podman/images_prune.go
@@ -41,7 +41,7 @@ func pruneImagesCmd(c *cliconfig.PruneImagesValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
// Call prune; if any cids are returned, print them and then
// return err in case an error also came up
diff --git a/cmd/podman/import.go b/cmd/podman/import.go
index 167d9f2c9..70ea167cb 100644
--- a/cmd/podman/import.go
+++ b/cmd/podman/import.go
@@ -49,7 +49,7 @@ func importCmd(c *cliconfig.ImportValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
var (
source string
diff --git a/cmd/podman/info.go b/cmd/podman/info.go
index e24fe3c77..ed60970b6 100644
--- a/cmd/podman/info.go
+++ b/cmd/podman/info.go
@@ -55,7 +55,7 @@ func infoCmd(c *cliconfig.InfoValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
infoArr, err := runtime.Info()
if err != nil {
@@ -97,9 +97,7 @@ func infoCmd(c *cliconfig.InfoValues) error {
out = formats.StdoutTemplate{Output: info, Template: infoOutputFormat}
}
- formats.Writer(out).Out()
-
- return nil
+ return formats.Writer(out).Out()
}
// top-level "debug" info
diff --git a/cmd/podman/init.go b/cmd/podman/init.go
index 68c80631d..3f97824fc 100644
--- a/cmd/podman/init.go
+++ b/cmd/podman/init.go
@@ -54,7 +54,7 @@ func initCmd(c *cliconfig.InitValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.InitContainers(ctx, c)
if err != nil {
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 24edfcb68..df597c868 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -88,7 +88,7 @@ func inspectCmd(c *cliconfig.InspectValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if !util.StringInSlice(inspectType, []string{inspectTypeContainer, inspectTypeImage, inspectAll}) {
return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll)
@@ -193,8 +193,8 @@ func iterateInput(ctx context.Context, size bool, args []string, runtime *adapte
inspectError = errors.Wrapf(err, "error getting libpod container inspect data %s", ctr.ID())
break
}
- artifact, inspectError := getArtifact(ctr)
- if inspectError != nil {
+ artifact, err := getArtifact(ctr)
+ if err != nil {
inspectError = err
break
}
diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go
index edf69ff2e..d5056d86d 100644
--- a/cmd/podman/kill.go
+++ b/cmd/podman/kill.go
@@ -63,7 +63,7 @@ func killCmd(c *cliconfig.KillValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.KillContainers(getContext(), c, killSignal)
if err != nil {
diff --git a/cmd/podman/load.go b/cmd/podman/load.go
index 0c41eb792..ed6a4e5fa 100644
--- a/cmd/podman/load.go
+++ b/cmd/podman/load.go
@@ -43,7 +43,7 @@ func init() {
// Disabled flags for the remote client
if !remote {
flags.StringVar(&loadCommand.SignaturePolicy, "signature-policy", "", "Pathname of signature policy file (not usually used)")
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
}
@@ -65,7 +65,7 @@ func loadCmd(c *cliconfig.LoadValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if len(c.Input) > 0 {
if err := parse.ValidateFileName(c.Input); err != nil {
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index 3a78adadc..36262fd4d 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/image/pkg/docker/config"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/docker/docker-credential-helpers/credentials"
"github.com/pkg/errors"
@@ -52,7 +53,7 @@ func init() {
flags.BoolVar(&loginCommand.StdinPassword, "password-stdin", false, "Take the password from stdin")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&loginCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&loginCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&loginCommand.CertDir, "cert-dir", "", "Pathname of a directory containing TLS certificates and keys used to connect to the registry")
flags.BoolVar(&loginCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go
index 5df838bba..66dc82363 100644
--- a/cmd/podman/logout.go
+++ b/cmd/podman/logout.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/image/docker"
"github.com/containers/image/pkg/docker/config"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -39,7 +40,7 @@ func init() {
logoutCommand.SetUsageTemplate(UsageTemplate())
flags := logoutCommand.Flags()
flags.BoolVarP(&logoutCommand.All, "all", "a", false, "Remove the cached credentials for all registries in the auth file")
- flags.StringVar(&logoutCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&logoutCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
markFlagHiddenForRemoteClient("authfile", flags)
}
diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go
index 25248db21..32605389e 100644
--- a/cmd/podman/logs.go
+++ b/cmd/podman/logs.go
@@ -54,8 +54,7 @@ func init() {
flags.StringVar(&logsCommand.Since, "since", "", "Show logs since TIMESTAMP")
flags.Uint64Var(&logsCommand.Tail, "tail", 0, "Output the specified number of LINES at the end of the logs. Defaults to 0, which prints all lines")
flags.BoolVarP(&logsCommand.Timestamps, "timestamps", "t", false, "Output the timestamps in the log")
- flags.MarkHidden("details")
-
+ markFlagHidden(flags, "details")
flags.SetInterspersed(false)
markFlagHiddenForRemoteClient("latest", flags)
@@ -68,7 +67,7 @@ func logsCmd(c *cliconfig.LogsValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
sinceTime := time.Time{}
if c.Flag("since").Changed {
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 248d63753..a8478bda6 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -2,11 +2,12 @@ package main
import (
"context"
- "github.com/containers/libpod/libpod"
"io"
"os"
+ "path"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/libpod"
_ "github.com/containers/libpod/pkg/hooks/0.1.0"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/version"
@@ -68,7 +69,7 @@ var mainCommands = []*cobra.Command{
}
var rootCmd = &cobra.Command{
- Use: "podman",
+ Use: path.Base(os.Args[0]),
Long: "manage pods and images",
RunE: commandRunE(),
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go
index d5f70a28f..e4f521bc4 100644
--- a/cmd/podman/main_local.go
+++ b/cmd/podman/main_local.go
@@ -45,14 +45,18 @@ func init() {
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.NetworkCmdPath, "network-cmd-path", "", "Path to the command for configuring the network")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CniConfigDir, "cni-config-dir", "", "Path of the configuration directory for CNI networks")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.DefaultMountsFile, "default-mounts-file", "", "Path to default mounts file")
- rootCmd.PersistentFlags().MarkHidden("defaults-mount-file")
+ if err := rootCmd.PersistentFlags().MarkHidden("default-mounts-file"); err != nil {
+ logrus.Error("unable to mark default-mounts-file flag as hidden")
+ }
// Override default --help information of `--help` global flag
var dummyHelp bool
rootCmd.PersistentFlags().BoolVar(&dummyHelp, "help", false, "Help for podman")
rootCmd.PersistentFlags().StringSliceVar(&MainGlobalOpts.HooksDir, "hooks-dir", []string{}, "Set the OCI hooks directory path (may be set multiple times)")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error, fatal or panic")
rootCmd.PersistentFlags().IntVar(&MainGlobalOpts.MaxWorks, "max-workers", 0, "The maximum number of workers for parallel operations")
- rootCmd.PersistentFlags().MarkHidden("max-workers")
+ if err := rootCmd.PersistentFlags().MarkHidden("max-workers"); err != nil {
+ logrus.Error("unable to mark max-workers flag as hidden")
+ }
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Namespace, "namespace", "", "Set the libpod namespace, used to create separate views of the containers and pods on the system")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Root, "root", "", "Path to the root directory in which data, including images, is stored")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored")
@@ -118,10 +122,10 @@ func setupRootless(cmd *cobra.Command, args []string) error {
return nil
}
podmanCmd := cliconfig.PodmanCommand{
- cmd,
- args,
- MainGlobalOpts,
- remoteclient,
+ Command: cmd,
+ InputArgs: args,
+ GlobalFlags: MainGlobalOpts,
+ Remote: remoteclient,
}
pausePidPath, err := util.GetRootlessPauseProcessPidPath()
@@ -148,7 +152,7 @@ func setupRootless(cmd *cobra.Command, args []string) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ctrs, err := runtime.GetRunningContainers()
if err != nil {
diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go
index 662fb0a28..b14827592 100644
--- a/cmd/podman/mount.go
+++ b/cmd/podman/mount.go
@@ -65,7 +65,7 @@ func mountCmd(c *cliconfig.MountValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if os.Geteuid() != 0 {
rtc, err := runtime.GetConfig()
diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go
index ee5fd352d..3a8f4edb5 100644
--- a/cmd/podman/pause.go
+++ b/cmd/podman/pause.go
@@ -46,7 +46,7 @@ func pauseCmd(c *cliconfig.PauseValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) < 1 && !c.All {
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index 8a611dffa..9a5cc3ec1 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -2,8 +2,8 @@ package main
import (
"fmt"
-
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -40,11 +40,11 @@ func init() {
flags.BoolVarP(&playKubeCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&playKubeCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&playKubeCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&playKubeCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
flags.StringVar(&playKubeCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
}
@@ -62,7 +62,7 @@ func playKubeCmd(c *cliconfig.KubePlayValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
_, err = runtime.PlayKubeYAML(ctx, c, args[0])
return err
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index 0abf84756..b6154b4db 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -56,7 +57,6 @@ func init() {
flags.StringVar(&podCreateCommand.Share, "share", shared.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
}
-
func podCreateCmd(c *cliconfig.PodCreateValues) error {
var (
err error
@@ -67,7 +67,7 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if len(c.Publish) > 0 {
if !c.Infra {
@@ -86,8 +86,8 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error {
if err != nil {
return errors.Errorf("error opening pod-id-file %s", c.PodIDFile)
}
- defer podIdFile.Close()
- defer podIdFile.Sync()
+ defer errorhandling.CloseQuiet(podIdFile)
+ defer errorhandling.SyncQuiet(podIdFile)
}
labels, err := shared.GetAllLabels(c.LabelFile, c.Labels)
diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go
index a22624078..03b5a8cc4 100644
--- a/cmd/podman/pod_inspect.go
+++ b/cmd/podman/pod_inspect.go
@@ -53,7 +53,7 @@ func podInspectCmd(c *cliconfig.PodInspectValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if c.Latest {
pod, err = runtime.GetLatestPod()
diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go
index 6be79363a..9bda77471 100644
--- a/cmd/podman/pod_kill.go
+++ b/cmd/podman/pod_kill.go
@@ -53,7 +53,7 @@ func podKillCmd(c *cliconfig.PodKillValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
killSignal := uint(syscall.SIGTERM)
diff --git a/cmd/podman/pod_pause.go b/cmd/podman/pod_pause.go
index e8574bfdc..75d179f52 100644
--- a/cmd/podman/pod_pause.go
+++ b/cmd/podman/pod_pause.go
@@ -49,7 +49,7 @@ func podPauseCmd(c *cliconfig.PodPauseValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
pauseIDs, conErrors, pauseErrors := runtime.PausePods(c)
diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go
index fbea5124e..a525857de 100644
--- a/cmd/podman/pod_ps.go
+++ b/cmd/podman/pod_ps.go
@@ -20,7 +20,7 @@ import (
)
const (
- STOPPED = "Stopped"
+ STOPPED = "Stopped" //nolint
RUNNING = "Running"
PAUSED = "Paused"
EXITED = "Exited"
@@ -36,9 +36,9 @@ var (
)
type podPsCtrInfo struct {
- Name string `"json:name,omitempty"`
- Id string `"json:id,omitempty"`
- Status string `"json:status,omitempty"`
+ Name string `json:"name,omitempty"`
+ Id string `json:"id,omitempty"`
+ Status string `json:"status,omitempty"`
}
type podPsOptions struct {
@@ -161,7 +161,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
opts := podPsOptions{
NoTrunc: c.NoTrunc,
diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go
index a1f4c8359..0b009e6c7 100644
--- a/cmd/podman/pod_restart.go
+++ b/cmd/podman/pod_restart.go
@@ -51,7 +51,7 @@ func podRestartCmd(c *cliconfig.PodRestartValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
restartIDs, conErrors, restartErrors := runtime.RestartPods(getContext(), c)
diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go
index 218ed8154..82d0eb977 100644
--- a/cmd/podman/pod_rm.go
+++ b/cmd/podman/pod_rm.go
@@ -51,7 +51,7 @@ func podRmCmd(c *cliconfig.PodRmValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
podRmIds, podRmErrors := runtime.RemovePods(getContext(), c)
for _, p := range podRmIds {
diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go
index 5c9225428..64c951b43 100644
--- a/cmd/podman/pod_start.go
+++ b/cmd/podman/pod_start.go
@@ -49,7 +49,7 @@ func podStartCmd(c *cliconfig.PodStartValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
podStartIDs, podStartErrors := runtime.StartPods(getContext(), c)
for _, p := range podStartIDs {
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index 97aa52f5d..7984f08ee 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -74,16 +74,13 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error {
if ctr > 1 {
return errors.Errorf("--all, --latest and containers cannot be used together")
- } else if ctr == 0 {
- // If user didn't specify, imply --all
- all = true
}
runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
times := -1
if c.NoStream {
@@ -173,7 +170,9 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error {
tm.Flush()
}
if strings.ToLower(format) == formats.JSONString {
- outputJson(newStats)
+ if err := outputJson(newStats); err != nil {
+ return err
+ }
} else {
results := podContainerStatsToPodStatOut(newStats)
@@ -300,17 +299,3 @@ func outputJson(stats []*adapter.PodContainerStats) error {
fmt.Println(string(b))
return nil
}
-
-func getPodsByList(podList []string, r *libpod.Runtime) ([]*libpod.Pod, error) {
- var (
- pods []*libpod.Pod
- )
- for _, p := range podList {
- pod, err := r.LookupPod(p)
- if err != nil {
- return nil, err
- }
- pods = append(pods, pod)
- }
- return pods, nil
-}
diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go
index b4b1718d9..edda99550 100644
--- a/cmd/podman/pod_stop.go
+++ b/cmd/podman/pod_stop.go
@@ -51,7 +51,7 @@ func podStopCmd(c *cliconfig.PodStopValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
podStopIds, podStopErrors := runtime.StopPods(getContext(), c)
for _, p := range podStopIds {
diff --git a/cmd/podman/pod_top.go b/cmd/podman/pod_top.go
index 72137b5a7..fcd9c4f3c 100644
--- a/cmd/podman/pod_top.go
+++ b/cmd/podman/pod_top.go
@@ -44,8 +44,7 @@ func init() {
flags := podTopCommand.Flags()
flags.BoolVarP(&podTopCommand.Latest, "latest,", "l", false, "Act on the latest pod podman is aware of")
flags.BoolVar(&podTopCommand.ListDescriptors, "list-descriptors", false, "")
- flags.MarkHidden("list-descriptors")
-
+ markFlagHidden(flags, "list-descriptors")
}
func podTopCmd(c *cliconfig.PodTopValues) error {
@@ -71,7 +70,7 @@ func podTopCmd(c *cliconfig.PodTopValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if c.Latest {
descriptors = args
@@ -85,8 +84,9 @@ func podTopCmd(c *cliconfig.PodTopValues) error {
return err
}
for _, proc := range psOutput {
- fmt.Fprintln(w, proc)
+ if _, err := fmt.Fprintln(w, proc); err != nil {
+ return err
+ }
}
- w.Flush()
- return nil
+ return w.Flush()
}
diff --git a/cmd/podman/pod_unpause.go b/cmd/podman/pod_unpause.go
index c5b7e6a18..91c3bfdf8 100644
--- a/cmd/podman/pod_unpause.go
+++ b/cmd/podman/pod_unpause.go
@@ -50,7 +50,7 @@ func podUnpauseCmd(c *cliconfig.PodUnpauseValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
unpauseIDs, conErrors, unpauseErrors := runtime.UnpausePods(c)
diff --git a/cmd/podman/pods_prune.go b/cmd/podman/pods_prune.go
index bdd75f9de..d40e37bdb 100644
--- a/cmd/podman/pods_prune.go
+++ b/cmd/podman/pods_prune.go
@@ -40,8 +40,11 @@ func podPruneCmd(c *cliconfig.PodPruneValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.PrunePods(getContext(), c)
+ if err != nil {
+ return err
+ }
return printCmdResults(ok, failures)
}
diff --git a/cmd/podman/port.go b/cmd/podman/port.go
index 1bd2d623e..5753c8e56 100644
--- a/cmd/podman/port.go
+++ b/cmd/podman/port.go
@@ -95,9 +95,12 @@ func portCmd(c *cliconfig.PortValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
containers, err := runtime.Port(c)
+ if err != nil {
+ return err
+ }
for _, con := range containers {
portmappings, err := con.PortMappings()
if err != nil {
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 75e07d325..26cc55e5f 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -15,87 +15,32 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/pkg/adapter"
- "github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/spf13/cobra"
- "k8s.io/apimachinery/pkg/fields"
)
const (
- mountTruncLength = 12
- hid = "CONTAINER ID"
- himage = "IMAGE"
- hcommand = "COMMAND"
- hcreated = "CREATED"
- hstatus = "STATUS"
- hports = "PORTS"
- hnames = "NAMES"
- hsize = "SIZE"
- hinfra = "IS INFRA"
- hpod = "POD"
- nspid = "PID"
- nscgroup = "CGROUPNS"
- nsipc = "IPC"
- nsmnt = "MNT"
- nsnet = "NET"
- nspidns = "PIDNS"
- nsuserns = "USERNS"
- nsuts = "UTS"
+ hid = "CONTAINER ID"
+ himage = "IMAGE"
+ hcommand = "COMMAND"
+ hcreated = "CREATED"
+ hstatus = "STATUS"
+ hports = "PORTS"
+ hnames = "NAMES"
+ hsize = "SIZE"
+ hinfra = "IS INFRA" //nolint
+ hpod = "POD"
+ nspid = "PID"
+ nscgroup = "CGROUPNS"
+ nsipc = "IPC"
+ nsmnt = "MNT"
+ nsnet = "NET"
+ nspidns = "PIDNS"
+ nsuserns = "USERNS"
+ nsuts = "UTS"
)
-type psTemplateParams struct {
- ID string
- Image string
- Command string
- CreatedAtTime time.Time
- Created string
- Status string
- Ports string
- Size string
- Names string
- Labels string
- Mounts string
- PID int
- CGROUPNS string
- IPC string
- MNT string
- NET string
- PIDNS string
- USERNS string
- UTS string
- Pod string
- IsInfra bool
-}
-
-// psJSONParams is used as a base structure for the psParams
-// If template output is requested, psJSONParams will be converted to
-// psTemplateParams.
-// psJSONParams will be populated by data from libpod.Container,
-// the members of the struct are the sama data types as their sources.
-type psJSONParams struct {
- ID string `json:"id"`
- Image string `json:"image"`
- ImageID string `json:"image_id"`
- Command []string `json:"command"`
- ExitCode int32 `json:"exitCode"`
- Exited bool `json:"exited"`
- CreatedAt time.Time `json:"createdAt"`
- StartedAt time.Time `json:"startedAt"`
- ExitedAt time.Time `json:"exitedAt"`
- Status string `json:"status"`
- PID int `json:"PID"`
- Ports []ocicni.PortMapping `json:"ports"`
- Size *shared.ContainerSize `json:"size,omitempty"`
- Names string `json:"names"`
- Labels fields.Set `json:"labels"`
- Mounts []string `json:"mounts"`
- ContainerRunning bool `json:"ctrRunning"`
- Namespaces *shared.Namespace `json:"namespace,omitempty"`
- Pod string `json:"pod,omitempty"`
- IsInfra bool `json:"infra"`
-}
-
// Type declaration and functions for sorting the PS output
type psSorted []shared.PsContainerOutput
@@ -223,7 +168,7 @@ func psCmd(c *cliconfig.PsValues) error {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if !watch {
if err := psDisplay(c, runtime); err != nil {
@@ -273,22 +218,6 @@ func checkFlagsPassed(c *cliconfig.PsValues) error {
return nil
}
-// generate the accurate header based on template given
-func (p *psTemplateParams) headerMap() map[string]string {
- v := reflect.Indirect(reflect.ValueOf(p))
- values := make(map[string]string)
-
- for i := 0; i < v.NumField(); i++ {
- key := v.Type().Field(i).Name
- value := key
- if value == "ID" {
- value = "Container" + value
- }
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}
-
func sortPsOutput(sortBy string, psOutput psSorted) (psSorted, error) {
switch sortBy {
case "id":
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index a05c78928..0eee51e79 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/image/transports/alltransports"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
@@ -55,11 +56,11 @@ func init() {
flags.BoolVarP(&pullCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&pullCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&pullCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&pullCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
flags.StringVar(&pullCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.BoolVar(&pullCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
}
@@ -81,7 +82,7 @@ func pullCmd(c *cliconfig.PullValues) (retError error) {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) == 0 {
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index 497820156..43df8c2de 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/image/manifest"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
@@ -57,12 +58,12 @@ func init() {
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&pushCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&pushCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&pushCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
flags.BoolVar(&pushCommand.Compress, "compress", false, "Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)")
flags.StringVar(&pushCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.BoolVar(&pushCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
- flags.MarkHidden("signature-policy")
+ markFlagHidden(flags, "signature-policy")
}
}
@@ -108,7 +109,7 @@ func pushCmd(c *cliconfig.PushValues) error {
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
var writer io.Writer
if !c.Quiet {
diff --git a/cmd/podman/refresh.go b/cmd/podman/refresh.go
index 9f9cbf908..b21a4ff79 100644
--- a/cmd/podman/refresh.go
+++ b/cmd/podman/refresh.go
@@ -42,7 +42,7 @@ func refreshCmd(c *cliconfig.RefreshValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
allCtrs, err := runtime.GetAllContainers()
if err != nil {
diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go
index 89bda7d6c..494a9ec06 100644
--- a/cmd/podman/restart.go
+++ b/cmd/podman/restart.go
@@ -55,7 +55,7 @@ func restartCmd(c *cliconfig.RestartValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.Restart(getContext(), c)
if err != nil {
diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go
index fcac9855d..c4146eff0 100644
--- a/cmd/podman/restore.go
+++ b/cmd/podman/restore.go
@@ -58,7 +58,7 @@ func restoreCmd(c *cliconfig.RestoreValues, cmd *cobra.Command) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if c.Import == "" && c.Name != "" {
return errors.Errorf("--name can only used with --import")
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index 0f81a0d63..958ca1c60 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -54,7 +54,7 @@ func rmCmd(c *cliconfig.RmValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
// Storage conflicts with --all/--latest/--volumes
if c.Storage {
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index 4c41a3ad5..9229d497e 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -55,7 +55,7 @@ func rmiCmd(c *cliconfig.RmiValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) == 0 && !removeAll {
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index 6f089e5a4..76ab3d944 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -37,7 +37,6 @@ func init() {
flags.Bool("sig-proxy", true, "Proxy received signals to the process")
getCreateFlags(&runCommand.PodmanCommand)
markFlagHiddenForRemoteClient("authfile", flags)
- flags.MarkHidden("signature-policy")
}
func runCmd(c *cliconfig.RunValues) error {
@@ -54,7 +53,7 @@ func runCmd(c *cliconfig.RunValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
exitCode, err = runtime.Run(getContext(), c, exitCode)
return err
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index be5d29139..db6d390d5 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -53,23 +53,23 @@ func init() {
flags.StringVar(&runlabelCommand.Opt1, "opt1", "", "Optional parameter to pass for install")
flags.StringVar(&runlabelCommand.Opt2, "opt2", "", "Optional parameter to pass for install")
flags.StringVar(&runlabelCommand.Opt3, "opt3", "", "Optional parameter to pass for install")
- flags.MarkHidden("opt1")
- flags.MarkHidden("opt2")
- flags.MarkHidden("opt3")
-
+ markFlagHidden(flags, "opt1")
+ markFlagHidden(flags, "opt2")
+ markFlagHidden(flags, "opt3")
flags.BoolP("pull", "p", false, "Pull the image if it does not exist locally prior to executing the label contents")
flags.BoolVarP(&runlabelCommand.Quiet, "quiet", "q", false, "Suppress output information when installing images")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&runlabelCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&runlabelCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&runlabelCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
flags.StringVar(&runlabelCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.BoolVar(&runlabelCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
- flags.MarkDeprecated("pull", "podman will pull if not found in local storage")
- flags.MarkHidden("signature-policy")
+ if err := flags.MarkDeprecated("pull", "podman will pull if not found in local storage"); err != nil {
+ logrus.Error("unable to mark pull flag deprecated")
+ }
+ markFlagHidden(flags, "signature-policy")
}
- markFlagHiddenForRemoteClient("authfile", flags)
}
// installCmd gets the data from the command line and calls installImage
@@ -95,7 +95,7 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) < 2 {
diff --git a/cmd/podman/save.go b/cmd/podman/save.go
index e59c9df5f..237ebde03 100644
--- a/cmd/podman/save.go
+++ b/cmd/podman/save.go
@@ -74,7 +74,7 @@ func saveCmd(c *cliconfig.SaveValues) error {
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if c.Flag("compress").Changed && (c.Format != ociManifestDir && c.Format != v2s2ManifestDir && c.Format == "") {
return errors.Errorf("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'")
diff --git a/cmd/podman/search.go b/cmd/podman/search.go
index ba04002f6..be75b6e37 100644
--- a/cmd/podman/search.go
+++ b/cmd/podman/search.go
@@ -7,16 +7,12 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/image"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
-const (
- descriptionTruncLength = 44
- maxQueries = 25
-)
-
var (
searchCommand cliconfig.SearchValues
searchDescription = `Search registries for a given image. Can search all the default registries or a specific registry.
@@ -49,7 +45,7 @@ func init() {
flags.BoolVar(&searchCommand.NoTrunc, "no-trunc", false, "Do not truncate the output")
// Disabled flags for the remote client
if !remote {
- flags.StringVar(&searchCommand.Authfile, "authfile", getAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&searchCommand.Authfile, "authfile", shared.GetAuthFile(""), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
}
@@ -88,8 +84,7 @@ func searchCmd(c *cliconfig.SearchValues) error {
return nil
}
out := formats.StdoutTemplateArray{Output: searchToGeneric(results), Template: format, Fields: searchHeaderMap()}
- formats.Writer(out).Out()
- return nil
+ return formats.Writer(out).Out()
}
// searchHeaderMap returns the headers of a SearchResult.
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 31ac9a3a1..f401d3cf5 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
+ "github.com/containers/libpod/pkg/errorhandling"
"io"
"os"
"path/filepath"
@@ -63,8 +64,8 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
if err != nil {
return nil, nil, errors.Errorf("error opening cidfile %s", c.String("cidfile"))
}
- defer cidFile.Close()
- defer cidFile.Sync()
+ defer errorhandling.CloseQuiet(cidFile)
+ defer errorhandling.SyncQuiet(cidFile)
}
imageName := ""
@@ -77,11 +78,14 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
writer = os.Stderr
}
- newImage, err := runtime.ImageRuntime().New(ctx, c.InputArgs[0], rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, false, nil)
+ newImage, err := runtime.ImageRuntime().New(ctx, c.InputArgs[0], rtc.SignaturePolicyPath, GetAuthFile(""), writer, nil, image.SigningOptions{}, false, nil)
if err != nil {
return nil, nil, err
}
data, err = newImage.Inspect(ctx)
+ if err != nil {
+ return nil, nil, err
+ }
names := newImage.Names()
if len(names) > 0 {
imageName = names[0]
diff --git a/cmd/podman/shared/funcs.go b/cmd/podman/shared/funcs.go
index c189cceeb..2ceb9cdcb 100644
--- a/cmd/podman/shared/funcs.go
+++ b/cmd/podman/shared/funcs.go
@@ -9,6 +9,21 @@ import (
"github.com/google/shlex"
)
+func GetAuthFile(authfile string) string {
+ if authfile != "" {
+ return authfile
+ }
+ authfile = os.Getenv("REGISTRY_AUTH_FILE")
+ if authfile != "" {
+ return authfile
+ }
+ runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
+ if runtimeDir != "" {
+ return filepath.Join(runtimeDir, "containers/auth.json")
+ }
+ return ""
+}
+
func substituteCommand(cmd string) (string, error) {
var (
newCommand string
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
index 0c25eec62..1333cf441 100644
--- a/cmd/podman/sign.go
+++ b/cmd/podman/sign.go
@@ -60,7 +60,7 @@ func signCmd(c *cliconfig.SignValues) error {
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
signby := c.SignBy
if signby == "" {
diff --git a/cmd/podman/start.go b/cmd/podman/start.go
index 165273114..737a6d9f1 100644
--- a/cmd/podman/start.go
+++ b/cmd/podman/start.go
@@ -69,7 +69,7 @@ func startCmd(c *cliconfig.StartValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
exitCode, err = runtime.Start(getContext(), c, sigProxy)
return err
}
diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go
index d79eebc3d..a1ec20b37 100644
--- a/cmd/podman/stats.go
+++ b/cmd/podman/stats.go
@@ -93,7 +93,7 @@ func statsCmd(c *cliconfig.StatsValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
times := -1
if c.NoStream {
@@ -175,7 +175,9 @@ func statsCmd(c *cliconfig.StatsValues) error {
tm.MoveCursor(1, 1)
tm.Flush()
}
- outputStats(reportStats, format)
+ if err := outputStats(reportStats, format); err != nil {
+ return err
+ }
time.Sleep(time.Second)
}
return nil
diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go
index 5c93904ef..e04d8a12b 100644
--- a/cmd/podman/stop.go
+++ b/cmd/podman/stop.go
@@ -60,7 +60,7 @@ func stopCmd(c *cliconfig.StopValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.StopContainers(getContext(), c)
if err != nil {
diff --git a/cmd/podman/system_df.go b/cmd/podman/system_df.go
index ab67e4f07..85554bf05 100644
--- a/cmd/podman/system_df.go
+++ b/cmd/podman/system_df.go
@@ -106,7 +106,7 @@ func dfSystemCmd(c *cliconfig.SystemDfValues) error {
if err != nil {
return errors.Wrapf(err, "Could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ctx := getContext()
@@ -131,11 +131,10 @@ func dfSystemCmd(c *cliconfig.SystemDfValues) error {
if c.Format != "" {
format = strings.Replace(c.Format, `\t`, "\t", -1)
}
- generateSysDfOutput(systemDfDiskUsages, format)
- return nil
+ return generateSysDfOutput(systemDfDiskUsages, format)
}
-func generateSysDfOutput(systemDfDiskUsages []systemDfDiskUsage, format string) {
+func generateSysDfOutput(systemDfDiskUsages []systemDfDiskUsage, format string) error {
var systemDfHeader = map[string]string{
"Type": "TYPE",
"Total": "TOTAL",
@@ -144,7 +143,7 @@ func generateSysDfOutput(systemDfDiskUsages []systemDfDiskUsage, format string)
"Reclaimable": "RECLAIMABLE",
}
out := formats.StdoutTemplateArray{Output: systemDfDiskUsageToGeneric(systemDfDiskUsages), Template: format, Fields: systemDfHeader}
- formats.Writer(out).Out()
+ return formats.Writer(out).Out()
}
func getDiskUsage(ctx context.Context, runtime *libpod.Runtime, metaData dfMetaData) ([]systemDfDiskUsage, error) {
@@ -554,10 +553,11 @@ func imagesVerboseOutput(ctx context.Context, metaData dfMetaData) error {
if err != nil {
return errors.Wrapf(err, "error getting verbose output of images")
}
- os.Stderr.WriteString("Images space usage:\n\n")
+ if _, err := os.Stderr.WriteString("Images space usage:\n\n"); err != nil {
+ return err
+ }
out := formats.StdoutTemplateArray{Output: systemDfImageVerboseDiskUsageToGeneric(imagesVerboseDiskUsage), Template: imageVerboseFormat, Fields: imageVerboseHeader}
- formats.Writer(out).Out()
- return nil
+ return formats.Writer(out).Out()
}
func containersVerboseOutput(ctx context.Context, metaData dfMetaData) error {
@@ -575,10 +575,12 @@ func containersVerboseOutput(ctx context.Context, metaData dfMetaData) error {
if err != nil {
return errors.Wrapf(err, "error getting verbose output of containers")
}
- os.Stderr.WriteString("\nContainers space usage:\n\n")
+ if _, err := os.Stderr.WriteString("\nContainers space usage:\n\n"); err != nil {
+ return err
+ }
out := formats.StdoutTemplateArray{Output: systemDfContainerVerboseDiskUsageToGeneric(containersVerboseDiskUsage), Template: containerVerboseFormat, Fields: containerVerboseHeader}
- formats.Writer(out).Out()
- return nil
+ return formats.Writer(out).Out()
+
}
func volumesVerboseOutput(ctx context.Context, metaData dfMetaData) error {
@@ -591,10 +593,11 @@ func volumesVerboseOutput(ctx context.Context, metaData dfMetaData) error {
if err != nil {
return errors.Wrapf(err, "error getting verbose output of volumes")
}
- os.Stderr.WriteString("\nLocal Volumes space usage:\n\n")
+ if _, err := os.Stderr.WriteString("\nLocal Volumes space usage:\n\n"); err != nil {
+ return err
+ }
out := formats.StdoutTemplateArray{Output: systemDfVolumeVerboseDiskUsageToGeneric(volumesVerboseDiskUsage), Template: volumeVerboseFormat, Fields: volumeVerboseHeader}
- formats.Writer(out).Out()
- return nil
+ return formats.Writer(out).Out()
}
func verboseOutput(ctx context.Context, metaData dfMetaData) error {
diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go
index d5b218cd8..b499d8dd2 100644
--- a/cmd/podman/system_prune.go
+++ b/cmd/podman/system_prune.go
@@ -76,27 +76,33 @@ Are you sure you want to continue? [y/N] `, volumeString)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
-
- rmWorkers := shared.Parallelize("rm")
- ctx := getContext()
- fmt.Println("Deleted Containers")
- ok, failures, lasterr := runtime.Prune(ctx, rmWorkers, false)
- printCmdResults(ok, failures)
+ defer runtime.DeferredShutdown(false)
+ // We must clean out pods first because if they may have infra containers
fmt.Println("Deleted Pods")
pruneValues := cliconfig.PodPruneValues{
PodmanCommand: c.PodmanCommand,
Force: c.Force,
}
- ok, failures, err = runtime.PrunePods(ctx, &pruneValues)
+ ctx := getContext()
+ ok, failures, lasterr := runtime.PrunePods(ctx, &pruneValues)
+
+ if err := printCmdResults(ok, failures); err != nil {
+ return err
+ }
+
+ rmWorkers := shared.Parallelize("rm")
+ fmt.Println("Deleted Containers")
+ ok, failures, err = runtime.Prune(ctx, rmWorkers, false)
if err != nil {
if lasterr != nil {
- logrus.Errorf("%q", lasterr)
+ logrus.Errorf("%q", err)
}
lasterr = err
}
- printCmdResults(ok, failures)
+ if err := printCmdResults(ok, failures); err != nil {
+ return err
+ }
if c.Bool("volumes") {
fmt.Println("Deleted Volumes")
diff --git a/cmd/podman/tag.go b/cmd/podman/tag.go
index 58f221e26..eb43d695c 100644
--- a/cmd/podman/tag.go
+++ b/cmd/podman/tag.go
@@ -42,7 +42,7 @@ func tagCmd(c *cliconfig.TagValues) error {
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
newImage, err := runtime.NewImageFromLocal(args[0])
if err != nil {
diff --git a/cmd/podman/top.go b/cmd/podman/top.go
index ba6cbe72d..bfba90fc0 100644
--- a/cmd/podman/top.go
+++ b/cmd/podman/top.go
@@ -57,7 +57,7 @@ func init() {
flags := topCommand.Flags()
flags.SetInterspersed(false)
flags.BoolVar(&topCommand.ListDescriptors, "list-descriptors", false, "")
- flags.MarkHidden("list-descriptors")
+ markFlagHidden(flags, "list-descriptors")
flags.BoolVarP(&topCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -83,7 +83,7 @@ func topCmd(c *cliconfig.TopValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
psOutput, err := runtime.Top(c)
if err != nil {
@@ -91,8 +91,9 @@ func topCmd(c *cliconfig.TopValues) error {
}
w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
for _, proc := range psOutput {
- fmt.Fprintln(w, proc)
+ if _, err := fmt.Fprintln(w, proc); err != nil {
+ return err
+ }
}
- w.Flush()
- return nil
+ return w.Flush()
}
diff --git a/cmd/podman/tree.go b/cmd/podman/tree.go
index 48e192990..c13dffd6e 100644
--- a/cmd/podman/tree.go
+++ b/cmd/podman/tree.go
@@ -55,7 +55,7 @@ func treeCmd(c *cliconfig.TreeValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
imageInfo, layerInfoMap, img, err := runtime.Tree(c)
if err != nil {
return err
diff --git a/cmd/podman/trust_set_show.go b/cmd/podman/trust_set_show.go
index b615f6266..d6f0eabd8 100644
--- a/cmd/podman/trust_set_show.go
+++ b/cmd/podman/trust_set_show.go
@@ -7,7 +7,6 @@ import (
"strings"
"github.com/containers/buildah/pkg/formats"
- "github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod/image"
@@ -57,7 +56,7 @@ func init() {
showTrustCommand.SetUsageTemplate(UsageTemplate())
setFlags := setTrustCommand.Flags()
setFlags.StringVar(&setTrustCommand.PolicyPath, "policypath", "", "")
- setFlags.MarkHidden("policypath")
+ markFlagHidden(setFlags, "policypath")
setFlags.StringSliceVarP(&setTrustCommand.PubKeysFile, "pubkeysfile", "f", []string{}, `Path of installed public key(s) to trust for TARGET.
Absolute path to keys is added to policy.json. May
used multiple times to define multiple public keys.
@@ -68,9 +67,9 @@ File(s) must exist before using this command`)
showFlags.BoolVarP(&showTrustCommand.Json, "json", "j", false, "Output as json")
showFlags.StringVar(&showTrustCommand.PolicyPath, "policypath", "", "")
showFlags.BoolVar(&showTrustCommand.Raw, "raw", false, "Output raw policy file")
- showFlags.MarkHidden("policypath")
+ markFlagHidden(showFlags, "policypath")
showFlags.StringVar(&showTrustCommand.RegistryPath, "registrypath", "", "")
- showFlags.MarkHidden("registrypath")
+ markFlagHidden(showFlags, "registrypath")
}
func showTrustCmd(c *cliconfig.ShowTrustValues) error {
@@ -238,10 +237,6 @@ func isValidTrustType(t string) bool {
return false
}
-func getDefaultPolicyPath() string {
- return trust.DefaultPolicyPath(&types.SystemContext{})
-}
-
func getPolicyJSON(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, error) {
registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
if err != nil {
diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go
index ddbd00bd5..c3d81d3a8 100644
--- a/cmd/podman/umount.go
+++ b/cmd/podman/umount.go
@@ -52,7 +52,7 @@ func umountCmd(c *cliconfig.UmountValues) error {
if err != nil {
return errors.Wrapf(err, "error creating runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.UmountRootFilesystems(getContext(), c)
if err != nil {
diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go
index 8126ebfbd..382b64e97 100644
--- a/cmd/podman/unpause.go
+++ b/cmd/podman/unpause.go
@@ -45,7 +45,7 @@ func unpauseCmd(c *cliconfig.UnpauseValues) error {
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
args := c.InputArgs
if len(args) < 1 && !c.All {
diff --git a/cmd/podman/utils.go b/cmd/podman/utils.go
index 986db469e..0790f673a 100644
--- a/cmd/podman/utils.go
+++ b/cmd/podman/utils.go
@@ -3,27 +3,12 @@ package main
import (
"fmt"
"reflect"
+ "runtime/debug"
+ "github.com/sirupsen/logrus"
"github.com/spf13/pflag"
)
-// printParallelOutput takes the map of parallel worker results and outputs them
-// to stdout
-func printParallelOutput(m map[string]error, errCount int) error {
- var lastError error
- for cid, result := range m {
- if result != nil {
- if errCount > 1 {
- fmt.Println(result.Error())
- }
- lastError = result
- continue
- }
- fmt.Println(cid)
- }
- return lastError
-}
-
// print results from CLI command
func printCmdResults(ok []string, failures map[string]error) error {
for _, id := range ok {
@@ -48,6 +33,17 @@ func printCmdResults(ok []string, failures map[string]error) error {
// on the remote-client
func markFlagHiddenForRemoteClient(flagName string, flags *pflag.FlagSet) {
if remoteclient {
- flags.MarkHidden(flagName)
+ if err := flags.MarkHidden(flagName); err != nil {
+ debug.PrintStack()
+ logrus.Errorf("unable to mark %s as hidden in the remote-client", flagName)
+ }
+ }
+}
+
+// markFlagHidden is a helper function to log an error if marking
+// a flag as hidden happens to fail
+func markFlagHidden(flags *pflag.FlagSet, flag string) {
+ if err := flags.MarkHidden(flag); err != nil {
+ logrus.Errorf("unable to mark flag '%s' as hidden: %q", flag, err)
}
}
diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go
index 698a30d84..92315cd6b 100644
--- a/cmd/podman/varlink.go
+++ b/cmd/podman/varlink.go
@@ -83,7 +83,7 @@ func varlinkCmd(c *cliconfig.VarlinkValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
var varlinkInterfaces = []*iopodman.VarlinkInterface{varlinkapi.New(&c.PodmanCommand, runtime)}
// Register varlink service. The metadata can be retrieved with:
diff --git a/cmd/podman/version.go b/cmd/podman/version.go
index a078ba2fe..6a88993c1 100644
--- a/cmd/podman/version.go
+++ b/cmd/podman/version.go
@@ -42,7 +42,7 @@ func init() {
func versionCmd(c *cliconfig.VersionValues) error {
clientVersion, err := define.GetVersion()
if err != nil {
- errors.Wrapf(err, "unable to determine version")
+ return errors.Wrapf(err, "unable to determine version")
}
versionOutputFormat := c.Format
@@ -63,18 +63,22 @@ func versionCmd(c *cliconfig.VersionValues) error {
defer w.Flush()
if remote {
- fmt.Fprintf(w, "Client:\n")
+ if _, err := fmt.Fprintf(w, "Client:\n"); err != nil {
+ return err
+ }
}
formatVersion(w, clientVersion)
if remote {
- fmt.Fprintf(w, "\nService:\n")
+ 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.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
serviceVersion, err := runtime.GetVersion()
if err != nil {
diff --git a/cmd/podman/volume_create.go b/cmd/podman/volume_create.go
index 84f6bba94..0897ab705 100644
--- a/cmd/podman/volume_create.go
+++ b/cmd/podman/volume_create.go
@@ -46,7 +46,7 @@ func volumeCreateCmd(c *cliconfig.VolumeCreateValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
if len(c.InputArgs) > 1 {
return errors.Errorf("too many arguments, create takes at most 1 argument")
diff --git a/cmd/podman/volume_inspect.go b/cmd/podman/volume_inspect.go
index e4b05f96a..1ebc5ce60 100644
--- a/cmd/podman/volume_inspect.go
+++ b/cmd/podman/volume_inspect.go
@@ -47,7 +47,7 @@ func volumeInspectCmd(c *cliconfig.VolumeInspectValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
vols, err := runtime.InspectVolumes(getContext(), c)
if err != nil {
diff --git a/cmd/podman/volume_ls.go b/cmd/podman/volume_ls.go
index 581e595cb..7248caf0c 100644
--- a/cmd/podman/volume_ls.go
+++ b/cmd/podman/volume_ls.go
@@ -76,7 +76,7 @@ func volumeLsCmd(c *cliconfig.VolumeLsValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
opts := volumeLsOptions{
Quiet: c.Quiet,
diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go
index 6dc9e2403..daea5a4d2 100644
--- a/cmd/podman/volume_prune.go
+++ b/cmd/podman/volume_prune.go
@@ -67,7 +67,7 @@ func volumePruneCmd(c *cliconfig.VolumePruneValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
// Prompt for confirmation if --force is not set
if !c.Force {
diff --git a/cmd/podman/volume_rm.go b/cmd/podman/volume_rm.go
index 77137eb7a..0141d06da 100644
--- a/cmd/podman/volume_rm.go
+++ b/cmd/podman/volume_rm.go
@@ -51,7 +51,7 @@ func volumeRmCmd(c *cliconfig.VolumeRmValues) error {
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
deletedVolumeNames, err := runtime.RemoveVolumes(getContext(), c)
if err != nil {
if len(deletedVolumeNames) > 0 {
diff --git a/cmd/podman/wait.go b/cmd/podman/wait.go
index 380e861ed..d6a707bb8 100644
--- a/cmd/podman/wait.go
+++ b/cmd/podman/wait.go
@@ -55,7 +55,7 @@ func waitCmd(c *cliconfig.WaitValues) error {
if err != nil {
return errors.Wrapf(err, "error creating runtime")
}
- defer runtime.Shutdown(false)
+ defer runtime.DeferredShutdown(false)
ok, failures, err := runtime.WaitOnContainers(getContext(), c, interval)
if err != nil {
diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md
index 5ff4f290f..18ef3e7f7 100644
--- a/contrib/cirrus/README.md
+++ b/contrib/cirrus/README.md
@@ -13,7 +13,6 @@ which alter this behavior. Within each task, each script executes in sequence,
so long as any previous script exited successfully. The overall state of each
task (pass or fail) is set based on the exit status of the last script to execute.
-
### ``gating`` Task
***N/B: Steps below are performed by automation***
@@ -64,6 +63,12 @@ task (pass or fail) is set based on the exit status of the last script to execut
but this script normally completes in less than an hour.
+### ``special_testing_cross`` Task
+
+Confirm that cross-compile of podman-remote functions for both `windows`
+and `darwin` targets.
+
+
### ``test_build_cache_images_task`` Task
Modifying the contents of cache-images is tested by making changes to
@@ -142,8 +147,22 @@ the magic ``***CIRRUS: TEST IMAGES***`` string. Keeping it and
`--force` pushing would needlessly cause Cirrus-CI to build
and test images again.
+### `release` Task
+
+Gathers up zip files uploaded by other tasks, from the local Cirrus-CI caching service.
+Depending on the execution context (a PR or a branch), this task uploads the files
+found to storage buckets at:
+
+* [https://storage.cloud.google.com/libpod-pr-releases](https://storage.cloud.google.com/libpod-pr-releases)
+* [https://storage.cloud.google.com/libpod-master-releases](https://storage.cloud.google.com/libpod-master-releases)
-### Base-images
+***Note:*** Repeated builds from the same PR or branch, will clobber previous archives
+ *by design*. This is intended so that the "latest" archive is always
+ available at a consistent URL. The precise details regarding a particular
+ build is encoded within the zip-archive comment.
+
+
+## Base-images
Base-images are VM disk-images specially prepared for executing as GCE VMs.
In particular, they run services on startup similar in purpose/function
@@ -236,3 +255,16 @@ console output. Simply set the ``TTYDEV`` parameter, for example:
$ make libpod_base_images ... TTYDEV=$(tty)
...
```
+
+## `$SPECIALMODE`
+
+Some tasks alter their behavior based on this value. A summary of supported
+values follows:
+
+* `none`: Operate as normal, this is the default value if unspecified.
+* `rootless`: Causes a random, ordinary user account to be created
+ and utilized for testing.
+* `in_podman`: Causes testing to occur within a container executed by
+ podman on the host.
+* `windows`: See **darwin**
+* `darwin`: Signals the ``special_testing_cross`` task to cross-compile the remote client.
diff --git a/contrib/cirrus/build_vm_images.sh b/contrib/cirrus/build_vm_images.sh
index 805aba428..f5d53a92e 100755
--- a/contrib/cirrus/build_vm_images.sh
+++ b/contrib/cirrus/build_vm_images.sh
@@ -3,13 +3,11 @@
set -e
source $(dirname $0)/lib.sh
-ENV_VARS='CNI_COMMIT CONMON_COMMIT PACKER_BUILDS BUILT_IMAGE_SUFFIX UBUNTU_BASE_IMAGE FEDORA_BASE_IMAGE PRIOR_FEDORA_BASE_IMAGE SERVICE_ACCOUNT GCE_SSH_USERNAME GCP_PROJECT_ID PACKER_VER SCRIPT_BASE PACKER_BASE'
+ENV_VARS='PACKER_BUILDS BUILT_IMAGE_SUFFIX UBUNTU_BASE_IMAGE FEDORA_BASE_IMAGE PRIOR_FEDORA_BASE_IMAGE SERVICE_ACCOUNT GCE_SSH_USERNAME GCP_PROJECT_ID PACKER_VER SCRIPT_BASE PACKER_BASE'
req_env_var $ENV_VARS
# Must also be made available through make, into packer process
export $ENV_VARS
-show_env_vars
-
# Everything here is running on the 'image-builder-image' GCE image
# Assume basic dependencies are all met, but there could be a newer version
# of the packer binary
@@ -27,21 +25,12 @@ fi
cd "$GOSRC/$PACKER_BASE"
-# Separate PR-produced images from those produced on master.
-if [[ "${CIRRUS_BRANCH:-}" == "master" ]]
-then
- POST_MERGE_BUCKET_SUFFIX="-master"
-else
- POST_MERGE_BUCKET_SUFFIX=""
-fi
-
make libpod_images \
PACKER_BUILDS=$PACKER_BUILDS \
PACKER_VER=$PACKER_VER \
GOSRC=$GOSRC \
SCRIPT_BASE=$SCRIPT_BASE \
PACKER_BASE=$PACKER_BASE \
- POST_MERGE_BUCKET_SUFFIX=$POST_MERGE_BUCKET_SUFFIX \
BUILT_IMAGE_SUFFIX=$BUILT_IMAGE_SUFFIX
# When successful, upload manifest of produced images using a filename unique
diff --git a/contrib/cirrus/cache_release_archive.sh b/contrib/cirrus/cache_release_archive.sh
new file mode 100755
index 000000000..639bc9801
--- /dev/null
+++ b/contrib/cirrus/cache_release_archive.sh
@@ -0,0 +1,140 @@
+#!/bin/bash
+
+set -eo pipefail
+
+source $(dirname $0)/lib.sh
+
+req_env_var GOSRC
+
+RELEASE_ARCHIVE_NAMES=""
+
+handle_archive() { # Assumed to be called with set +e
+ TASK_NUMBER=$1
+ PR_OR_BRANCH=$2
+ CACHE_URL=$3
+ ARCHIVE_NAME="$(basename $CACHE_URL)"
+ req_env_var TASK_NUMBER PR_OR_BRANCH CACHE_URL ARCHIVE_NAME
+
+ cd /tmp
+ curl -sO "$CACHE_URL" || return $(warn 0 "Couldn't download file, skipping.")
+ [[ -r "/tmp/$ARCHIVE_NAME" ]] || return $(warn 0 "Unreadable archive '/tmp/$ARCHIVE_NAME', skipping.")
+
+ ZIPCOMMENT=$(unzip -qqz "$ARCHIVE_NAME" 2>/dev/null) # noisy bugger
+ if [[ "$?" -ne "0" ]] || [[ -z "$ZIPCOMMENT" ]]
+ then
+ return $(warn 0 "Could not unzip metadata from downloaded '/tmp/$ARCHIVE_NAME', skipping.")
+ fi
+
+ RELEASE_INFO=$(echo "$ZIPCOMMENT" | grep -m 1 'X-RELEASE-INFO:' | sed -r -e 's/X-RELEASE-INFO:\s*(.+)/\1/')
+ if [[ "$?" -ne "0" ]] || [[ -z "$RELEASE_INFO" ]]
+ then
+ return $(warn 0 "Metadata empty or invalid: '$ZIPCOMMENT', skipping.")
+ fi
+
+ # e.g. libpod v1.3.1-166-g60df124e fedora 29 amd64
+ # or libpod v1.3.1-166-g60df124e amd64
+ FIELDS="RELEASE_BASENAME RELEASE_VERSION RELEASE_DIST RELEASE_DIST_VER RELEASE_ARCH"
+ read $FIELDS <<< $RELEASE_INFO
+ for f in $FIELDS
+ do
+ [[ -n "${!f}" ]] || return $(warn 0 "Expecting $f to be non-empty in metadata: '$RELEASE_INFO', skipping.")
+ done
+
+ echo -n "Preparing $RELEASE_BASENAME archive: "
+ # Drop version number to enable "latest" representation
+ # (version available w/in zip-file comment)
+ RELEASE_ARCHIVE_NAME="${RELEASE_BASENAME}-${PR_OR_BRANCH}-${RELEASE_DIST}-${RELEASE_DIST_VER}-${RELEASE_ARCH}.zip"
+ # Allow uploading all gathered files in parallel, later with gsutil.
+ mv -v "$ARCHIVE_NAME" "/$RELEASE_ARCHIVE_NAME"
+ RELEASE_ARCHIVE_NAMES="$RELEASE_ARCHIVE_NAMES $RELEASE_ARCHIVE_NAME"
+}
+
+make_release() {
+ ARCHIVE_NAME="$1"
+ req_env_var ARCHIVE_NAME
+
+ # There's no actual testing of windows/darwin targets yet
+ # but we still want to cross-compile and publish binaries
+ if [[ "$SPECIALMODE" == "windows" ]] || [[ "$SPECIALMODE" == "darwin" ]]
+ then
+ RELFILE="podman-remote-${SPECIALMODE}.zip"
+ elif [[ "$SPECIALMODE" == "none" ]]
+ then
+ RELFILE="podman.zip"
+ else
+ die 55 "$(basename $0) unable to handle \$SPECIALMODE=$SPECIALMODE for $ARCHIVE_NAME"
+ fi
+ echo "Calling make $RELFILE"
+ cd $GOSRC
+ make "$RELFILE"
+ echo "Renaming archive so it can be identified/downloaded for publishing"
+ mv -v "$RELFILE" "$ARCHIVE_NAME"
+ echo "Success!"
+}
+
+[[ "$CI" == "true" ]] || \
+ die 56 "$0 requires a Cirrus-CI cross-task cache to function"
+
+cd $GOSRC
+# Same script re-used for both uploading and downloading to avoid duplication
+if [[ "$(basename $0)" == "cache_release_archive.sh" ]]
+then
+ # ref: https://cirrus-ci.org/guide/writing-tasks/#environment-variables
+ req_env_var CI_NODE_INDEX CIRRUS_BUILD_ID
+ # Use unique names for uncache_release_archives.sh to find/download them all
+ ARCHIVE_NAME="build-${CIRRUS_BUILD_ID}-task-${CI_NODE_INDEX}.zip"
+ make_release "$ARCHIVE_NAME"
+
+ # ref: https://cirrus-ci.org/guide/writing-tasks/#http-cache
+ URL="http://$CIRRUS_HTTP_CACHE_HOST/${ARCHIVE_NAME}"
+ echo "Uploading $ARCHIVE_NAME to Cirrus-CI cache at $URL"
+ curl -s -X POST --data-binary "@$ARCHIVE_NAME" "$URL"
+elif [[ "$(basename $0)" == "uncache_release_archives.sh" ]]
+then
+ req_env_var CIRRUS_BUILD_ID CI_NODE_TOTAL GCPJSON GCPNAME GCPROJECT
+ [[ "${CI_NODE_INDEX}" -eq "$[CI_NODE_TOTAL-1]" ]] || \
+ die 8 "The release task must be executed last to guarantee archive cache is complete"
+
+ if [[ -n "$CIRRUS_PR" ]]
+ then
+ PR_OR_BRANCH="pr$CIRRUS_PR"
+ BUCKET="libpod-pr-releases"
+ elif [[ -n "$CIRRUS_BRANCH" ]]
+ then
+ PR_OR_BRANCH="$CIRRUS_BRANCH"
+ BUCKET="libpod-$CIRRUS_BRANCH-releases"
+ else
+ die 10 "Expecting either \$CIRRUS_PR or \$CIRRUS_BRANCH to be non-empty."
+ fi
+
+ echo "Blindly downloading Cirrus-CI cache files for task (some will fail)."
+ set +e # Don't stop looping until all task's cache is attempted
+ for (( task_number = 0 ; task_number < $CI_NODE_TOTAL ; task_number++ ))
+ do
+ ARCHIVE_NAME="build-${CIRRUS_BUILD_ID}-task-${task_number}.zip"
+ URL="http://$CIRRUS_HTTP_CACHE_HOST/${ARCHIVE_NAME}"
+ echo "Attempting to download cached archive from $URL"
+ handle_archive "$task_number" "$PR_OR_BRANCH" "$URL"
+ echo "----------------------------------------"
+ done
+ set -e
+
+ [[ -n "$RELEASE_ARCHIVE_NAMES" ]] || \
+ die 67 "Error: No release archives found in CI cache, expecting at least one."
+
+ echo "Preparing to upload release archives."
+ gcloud config set project "$GCPROJECT"
+ echo "$GCPJSON" > /tmp/gcp.json
+ gcloud auth activate-service-account --key-file=/tmp/gcp.json
+ rm /tmp/gcp.json
+ # handle_archive() placed all uploadable files under /
+ gsutil -m cp /*.zip "gs://$BUCKET" # Upload in parallel
+ echo "Successfully uploaded archives:"
+ for ARCHIVE_NAME in $RELEASE_ARCHIVE_NAMES
+ do
+ echo " https://storage.cloud.google.com/$BUCKET/$ARCHIVE_NAME"
+ done
+ echo "These will remain available until automatic pruning by bucket policy."
+else
+ die 9 "I don't know what to do when called $0"
+fi
diff --git a/contrib/cirrus/integration_test.sh b/contrib/cirrus/integration_test.sh
index b163834d5..cfaf33b85 100755
--- a/contrib/cirrus/integration_test.sh
+++ b/contrib/cirrus/integration_test.sh
@@ -1,6 +1,7 @@
#!/bin/bash
set -e
+
source $(dirname $0)/lib.sh
req_env_var GOSRC SCRIPT_BASE OS_RELEASE_ID OS_RELEASE_VER CONTAINER_RUNTIME
@@ -15,39 +16,41 @@ fi
cd "$GOSRC"
-if [[ "$SPECIALMODE" == "in_podman" ]]
-then
- ${CONTAINER_RUNTIME} run --rm --privileged --net=host \
- -v $GOSRC:$GOSRC:Z \
- --workdir $GOSRC \
- -e "CGROUP_MANAGER=cgroupfs" \
- -e "STORAGE_OPTIONS=--storage-driver=vfs" \
- -e "CRIO_ROOT=$GOSRC" \
- -e "PODMAN_BINARY=/usr/bin/podman" \
- -e "CONMON_BINARY=/usr/libexec/podman/conmon" \
- -e "DIST=$OS_RELEASE_ID" \
- -e "CONTAINER_RUNTIME=$CONTAINER_RUNTIME" \
- $IN_PODMAN_IMAGE bash $GOSRC/$SCRIPT_BASE/container_test.sh -b -i -t
-elif [[ "$SPECIALMODE" == "rootless" ]]
-then
- req_env_var ROOTLESS_USER
-
- if [[ "$USER" == "$ROOTLESS_USER" ]]
- then
- $GOSRC/$SCRIPT_BASE/rootless_test.sh ${TESTSUITE}
- else
+case "$SPECIALMODE" in
+ in_podman)
+ ${CONTAINER_RUNTIME} run --rm --privileged --net=host \
+ -v $GOSRC:$GOSRC:Z \
+ --workdir $GOSRC \
+ -e "CGROUP_MANAGER=cgroupfs" \
+ -e "STORAGE_OPTIONS=--storage-driver=vfs" \
+ -e "CRIO_ROOT=$GOSRC" \
+ -e "PODMAN_BINARY=/usr/bin/podman" \
+ -e "CONMON_BINARY=/usr/libexec/podman/conmon" \
+ -e "DIST=$OS_RELEASE_ID" \
+ -e "CONTAINER_RUNTIME=$CONTAINER_RUNTIME" \
+ $IN_PODMAN_IMAGE bash $GOSRC/$SCRIPT_BASE/container_test.sh -b -i -t
+ ;;
+ rootless)
+ req_env_var ROOTLESS_USER
ssh $ROOTLESS_USER@localhost \
- -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o CheckHostIP=no \
- $GOSRC/$SCRIPT_BASE/rootless_test.sh ${TESTSUITE}
- fi
-else
- make
- make install PREFIX=/usr ETCDIR=/etc
- make test-binaries
- if [[ "$TEST_REMOTE_CLIENT" == "true" ]]
- then
- make remote${TESTSUITE}
- else
- make local${TESTSUITE}
- fi
-fi
+ -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
+ -o CheckHostIP=no $GOSRC/$SCRIPT_BASE/rootless_test.sh ${TESTSUITE}
+ ;;
+ none)
+ make
+ make install PREFIX=/usr ETCDIR=/etc
+ make test-binaries
+ if [[ "$TEST_REMOTE_CLIENT" == "true" ]]
+ then
+ make remote${TESTSUITE}
+ else
+ make local${TESTSUITE}
+ fi
+ ;;
+ windows) ;& # for podman-remote building only
+ darwin)
+ warn '' "No $SPECIALMODE remote client integration tests configured"
+ ;;
+ *)
+ die 110 "Unsupported \$SPECIAL_MODE: $SPECIALMODE"
+esac
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index 36751fbd7..ea0f9e326 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -18,9 +18,8 @@ if type -P go &> /dev/null
then
# required for go 1.12+
export GOCACHE="${GOCACHE:-$HOME/.cache/go-build}"
- eval "$(go env)"
- # required by make and other tools
- export $(go env | cut -d '=' -f 1)
+ # called processes like `make` and other tools need these vars.
+ eval "export $(go env)"
# Ensure compiled tooling is reachable
export PATH="$PATH:$GOPATH/bin"
@@ -55,16 +54,24 @@ PACKER_VER="1.3.5"
# CSV of cache-image names to build (see $PACKER_BASE/libpod_images.json)
# Base-images rarely change, define them here so they're out of the way.
-PACKER_BUILDS="${PACKER_BUILDS:-ubuntu-18,fedora-30,fedora-29}"
+export PACKER_BUILDS="${PACKER_BUILDS:-ubuntu-18,fedora-30,fedora-29}"
# Google-maintained base-image names
-UBUNTU_BASE_IMAGE="ubuntu-1804-bionic-v20181203a"
+export UBUNTU_BASE_IMAGE="ubuntu-1804-bionic-v20181203a"
# Manually produced base-image names (see $SCRIPT_BASE/README.md)
-FEDORA_BASE_IMAGE="fedora-cloud-base-30-1-2-1559164849"
-PRIOR_FEDORA_BASE_IMAGE="fedora-cloud-base-29-1-2-1559164849"
-BUILT_IMAGE_SUFFIX="${BUILT_IMAGE_SUFFIX:--$CIRRUS_REPO_NAME-${CIRRUS_BUILD_ID}}"
+export FEDORA_BASE_IMAGE="fedora-cloud-base-30-1-2-1559164849"
+export PRIOR_FEDORA_BASE_IMAGE="fedora-cloud-base-29-1-2-1559164849"
+export BUILT_IMAGE_SUFFIX="${BUILT_IMAGE_SUFFIX:--$CIRRUS_REPO_NAME-${CIRRUS_BUILD_ID}}"
# IN_PODMAN container image
IN_PODMAN_IMAGE="quay.io/libpod/in_podman:latest"
+# Avoid getting stuck waiting for user input
+export DEBIAN_FRONTEND="noninteractive"
+SUDOAPTGET="ooe.sh sudo -E apt-get -qq --yes"
+SUDOAPTADD="ooe.sh sudo -E add-apt-repository --yes"
+# Short-cuts for retrying/timeout calls
+LILTO="timeout_attempt_delay_command 24s 5 30s"
+BIGTO="timeout_attempt_delay_command 300s 5 30s"
+
# Safe env. vars. to transfer from root -> $ROOTLESS_USER (go env handled separetly)
ROOTLESS_ENV_RE='(CIRRUS_.+)|(ROOTLESS_.+)|(.+_IMAGE.*)|(.+_BASE)|(.*DIRPATH)|(.*FILEPATH)|(SOURCE.*)|(DEPEND.*)|(.+_DEPS_.+)|(OS_REL.*)|(.+_ENV_RE)|(TRAVIS)|(CI.+)|(TEST_REMOTE.*)'
# Unsafe env. vars for display
@@ -148,9 +155,6 @@ show_env_vars() {
# Supports older BASH versions
printf " ${_env_var_name}=%q\n" "$(printenv $_env_var_name)"
done
- echo ""
- echo "##### $(go version) #####"
- echo ""
}
die() {
@@ -160,6 +164,11 @@ die() {
exit ${1:-1}
}
+warn() {
+ echo ">>>>> ${2:-WARNING (but no message given!) in ${FUNCNAME[1]}()}" > /dev/stderr
+ echo ${1:-1} > /dev/stdout
+}
+
bad_os_id_ver() {
echo "Unknown/Unsupported distro. $OS_RELEASE_ID and/or version $OS_RELEASE_VER for $(basename $0)"
exit 42
@@ -169,6 +178,35 @@ stub() {
echo "STUB: Pretending to do $1"
}
+timeout_attempt_delay_command() {
+ TIMEOUT=$1
+ ATTEMPTS=$2
+ DELAY=$3
+ shift 3
+ STDOUTERR=$(mktemp -p '' $(basename $0)_XXXXX)
+ req_env_var ATTEMPTS DELAY
+ echo "Retrying $ATTEMPTS times with a $DELAY delay, and $TIMEOUT timeout for command: $@"
+ for (( COUNT=1 ; COUNT <= $ATTEMPTS ; COUNT++ ))
+ do
+ echo "##### (attempt #$COUNT)" &>> "$STDOUTERR"
+ if timeout --foreground $TIMEOUT "$@" &>> "$STDOUTERR"
+ then
+ echo "##### (success after #$COUNT attempts)" &>> "$STDOUTERR"
+ break
+ else
+ echo "##### (failed with exit: $?)" &>> "$STDOUTERR"
+ sleep $DELAY
+ fi
+ done
+ cat "$STDOUTERR"
+ rm -f "$STDOUTERR"
+ if (( COUNT > $ATTEMPTS ))
+ then
+ echo "##### (exceeded $ATTEMPTS attempts)"
+ exit 125
+ fi
+}
+
ircmsg() {
req_env_var CIRRUS_TASK_ID IRCID
[[ -n "$*" ]] || die 9 "ircmsg() invoked without message text argument"
@@ -183,7 +221,7 @@ ircmsg() {
}
setup_rootless() {
- req_env_var ROOTLESS_USER GOSRC
+ req_env_var ROOTLESS_USER GOSRC SECRET_ENV_RE ROOTLESS_ENV_RE
# Only do this once
if passwd --status $ROOTLESS_USER
@@ -257,7 +295,7 @@ setup_rootless() {
install_ooe() {
req_env_var SCRIPT_BASE
echo "Installing script to mask stdout/stderr unless non-zero exit."
- sudo install -D -m 755 "/tmp/libpod/$SCRIPT_BASE/ooe.sh" /usr/local/bin/ooe.sh
+ sudo install -D -m 755 "$GOSRC/$SCRIPT_BASE/ooe.sh" /usr/local/bin/ooe.sh
}
# Grab a newer version of git from software collections
@@ -274,110 +312,34 @@ EOF
sudo chmod 755 /usr/bin/git
}
-install_cni_plugins() {
- echo "Installing CNI Plugins from commit $CNI_COMMIT"
- req_env_var GOPATH CNI_COMMIT
- DEST="$GOPATH/src/github.com/containernetworking/plugins"
- rm -rf "$DEST"
- ooe.sh git clone "https://github.com/containernetworking/plugins.git" "$DEST"
- cd "$DEST"
- ooe.sh git checkout -q "$CNI_COMMIT"
- ooe.sh ./build.sh
- sudo mkdir -p /usr/libexec/cni
- sudo cp bin/* /usr/libexec/cni
+install_test_configs(){
+ echo "Installing cni config, policy and registry config"
+ req_env_var GOSRC
+ sudo install -D -m 755 $GOSRC/cni/87-podman-bridge.conflist \
+ /etc/cni/net.d/87-podman-bridge.conflist
+ sudo install -D -m 755 $GOSRC/test/policy.json \
+ /etc/containers/policy.json
+ sudo install -D -m 755 $GOSRC/test/registries.conf \
+ /etc/containers/registries.conf
}
-install_runc_from_git(){
- req_env_var GOPATH OS_RELEASE_ID RUNC_COMMIT
- wd=$(pwd)
- DEST="$GOPATH/src/github.com/opencontainers/runc"
- rm -rf "$DEST"
- ooe.sh git clone https://github.com/opencontainers/runc.git "$DEST"
- cd "$DEST"
- ooe.sh git fetch origin --tags
- ooe.sh git checkout -q "$RUNC_COMMIT"
- if [[ "${OS_RELEASE_ID}" == "ubuntu" ]]
+remove_packaged_podman_files(){
+ show_and_store_warning "Removing packaged podman files to prevent conflicts with source build and testing."
+ req_env_var OS_RELEASE_ID
+ if [[ "$OS_RELEASE_ID" =~ "ubuntu" ]]
then
- ooe.sh make static BUILDTAGS="seccomp apparmor"
+ LISTING_CMD="sudo -E dpkg-query -L podman"
else
- ooe.sh make BUILDTAGS="seccomp selinux"
+ LISTING_CMD='sudo rpm -ql podman'
fi
- sudo install -m 755 runc /usr/bin/runc
- cd $wd
-}
-install_runc(){
- echo "Installing RunC from commit $RUNC_COMMIT"
- echo "Platform is $OS_RELEASE_ID"
- req_env_var GOPATH RUNC_COMMIT OS_RELEASE_ID
- if [[ "$OS_RELEASE_ID" =~ "ubuntu" ]]; then
- echo "Running make install.libseccomp.sudo for ubuntu"
- if ! [[ -d "/tmp/libpod" ]]
- then
- echo "Expecting a copy of libpod repository in /tmp/libpod"
- exit 5
- fi
- mkdir -p "$GOPATH/src/github.com/containers/"
- # Symlinks don't work with Go
- cp -a /tmp/libpod "$GOPATH/src/github.com/containers/"
- cd "$GOPATH/src/github.com/containers/libpod"
- ooe.sh sudo make install.libseccomp.sudo
- fi
- install_runc_from_git
-}
-
-install_buildah() {
- echo "Installing buildah from latest upstream master"
- req_env_var GOPATH
- DEST="$GOPATH/src/github.com/containers/buildah"
- rm -rf "$DEST"
- ooe.sh git clone https://github.com/containers/buildah "$DEST"
- cd "$DEST"
- ooe.sh make
- ooe.sh sudo make install
-}
-
-# Requires $GOPATH and $CONMON_COMMIT to be set
-install_conmon(){
- echo "Installing conmon from commit $CONMON_COMMIT"
- req_env_var GOPATH CONMON_COMMIT
- DEST="$GOPATH/src/github.com/containers/conmon.git"
- rm -rf "$DEST"
- ooe.sh git clone https://github.com/containers/conmon.git "$DEST"
- cd "$DEST"
- ooe.sh git fetch origin --tags
- ooe.sh git checkout -q "$CONMON_COMMIT"
- ooe.sh make
- sudo install -D -m 755 bin/conmon /usr/libexec/podman/conmon
-}
-
-install_criu(){
- echo "Installing CRIU"
- echo "Installing CRIU from commit $CRIU_COMMIT"
- echo "Platform is $OS_RELEASE_ID"
- req_env_var CRIU_COMMIT
-
- if [[ "$OS_RELEASE_ID" =~ "ubuntu" ]]; then
- ooe.sh sudo -E add-apt-repository -y ppa:criu/ppa
- ooe.sh sudo -E apt-get -qq -y update
- ooe.sh sudo -E apt-get -qq -y install criu
- elif [[ "$OS_RELEASE_ID" =~ "fedora" ]]; then
- echo "Using CRIU from distribution"
- else
- DEST="/tmp/criu"
- rm -rf "$DEST"
- ooe.sh git clone https://github.com/checkpoint-restore/criu.git "$DEST"
- cd $DEST
- ooe.sh git fetch origin --tags
- ooe.sh git checkout -q "$CRIU_COMMIT"
- ooe.sh make
- sudo install -D -m 755 criu/criu /usr/sbin/
- fi
-}
-
-install_varlink() {
- echo "Installing varlink from the cheese-factory"
- ooe.sh sudo -H pip3 install varlink
+ # yum/dnf/dpkg may list system directories, only remove files
+ $LISTING_CMD | while read fullpath
+ do
+ # TODO: This can go away when conmon gets it's own package
+ if [[ -d "$fullpath" ]] || [[ $(basename "$fullpath") == "conmon" ]] ; then continue; fi
+ ooe.sh sudo rm -vf "$fullpath"
+ done
}
_finalize(){
@@ -390,7 +352,7 @@ _finalize(){
sudo rm -rf /home/*
sudo rm -rf /tmp/*
sudo rm -rf /tmp/.??*
- sync
+ sudo sync
sudo fstrim -av
}
@@ -413,6 +375,7 @@ rh_finalize(){
ubuntu_finalize(){
set +e # Don't fail at the very end
echo "Resetting to fresh-state for usage as cloud-image."
+ $LILTO $SUDOAPTGET autoremove
sudo rm -rf /var/cache/apt
_finalize
}
diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh
index 4388dc992..eb95db907 100644
--- a/contrib/cirrus/packer/fedora_setup.sh
+++ b/contrib/cirrus/packer/fedora_setup.sh
@@ -8,7 +8,7 @@ set -e
# Load in library (copied by packer, before this script was run)
source /tmp/libpod/$SCRIPT_BASE/lib.sh
-req_env_var SCRIPT_BASE FEDORA_CNI_COMMIT CNI_COMMIT CONMON_COMMIT CRIU_COMMIT
+req_env_var SCRIPT_BASE
install_ooe
@@ -17,11 +17,16 @@ trap "sudo rm -rf $GOPATH" EXIT
ooe.sh sudo dnf update -y
+echo "Installing general build/test dependencies"
ooe.sh sudo dnf install -y \
atomic-registries \
bats \
+ bridge-utils \
btrfs-progs-devel \
bzip2 \
+ container-selinux \
+ containernetworking-plugins \
+ containers-common \
criu \
device-mapper-devel \
emacs-nox \
@@ -32,22 +37,24 @@ ooe.sh sudo dnf install -y \
gnupg \
golang \
golang-github-cpuguy83-go-md2man \
- golang-github-cpuguy83-go-md2man \
gpgme-devel \
- iptables \
iproute \
+ iptables \
jq \
libassuan-devel \
libcap-devel \
libnet \
libnet-devel \
libnl3-devel \
+ libseccomp \
libseccomp-devel \
libselinux-devel \
lsof \
make \
nmap-ncat \
+ ostree \
ostree-devel \
+ podman \
procps-ng \
protobuf \
protobuf-c \
@@ -61,7 +68,7 @@ ooe.sh sudo dnf install -y \
python3-psutil \
python3-pytoml \
runc \
- skopeo-containers \
+ selinux-policy-devel \
slirp4netns \
unzip \
vim \
@@ -69,15 +76,8 @@ ooe.sh sudo dnf install -y \
xz \
zip
-install_varlink
-
-install_conmon
-
-CNI_COMMIT=$FEDORA_CNI_COMMIT
-install_cni_plugins
-
sudo /tmp/libpod/hack/install_catatonit.sh
-rh_finalize # N/B: Halts system!
+rh_finalize
echo "SUCCESS!"
diff --git a/contrib/cirrus/packer/libpod_images.yml b/contrib/cirrus/packer/libpod_images.yml
index c25da25ac..91ed3b474 100644
--- a/contrib/cirrus/packer/libpod_images.yml
+++ b/contrib/cirrus/packer/libpod_images.yml
@@ -7,13 +7,6 @@ variables:
FEDORA_BASE_IMAGE: '{{env `FEDORA_BASE_IMAGE`}}'
PRIOR_FEDORA_BASE_IMAGE: '{{env `PRIOR_FEDORA_BASE_IMAGE`}}'
- # libpod dependencies to build and install into images
- FEDORA_CNI_COMMIT: "{{env `FEDORA_CNI_COMMIT`}}"
- CNI_COMMIT: "{{env `CNI_COMMIT`}}"
- CONMON_COMMIT: "{{env `CONMON_COMMIT`}}"
- CRIU_COMMIT: "{{env `CRIU_COMMIT`}}"
- RUNC_COMMIT: "{{env `RUNC_COMMIT`}}"
-
BUILT_IMAGE_SUFFIX: '{{env `BUILT_IMAGE_SUFFIX`}}'
GOSRC: '{{env `GOSRC`}}'
PACKER_BASE: '{{env `PACKER_BASE`}}'
@@ -25,10 +18,6 @@ variables:
SERVICE_ACCOUNT: '{{env `SERVICE_ACCOUNT`}}'
GOOGLE_APPLICATION_CREDENTIALS: '{{env `GOOGLE_APPLICATION_CREDENTIALS`}}'
- # Used to separate images produced during PR testing from those
- # produced from post-merge testing. Must be empty for PR testing.
- POST_MERGE_BUCKET_SUFFIX: ''
-
# Don't leak sensitive values in error messages / output
sensitive-variables:
- 'GCE_SSH_USERNAME'
@@ -72,12 +61,7 @@ provisioners:
script: '{{user `GOSRC`}}/{{user `PACKER_BASE`}}/{{split build_name "-" 0}}_setup.sh'
environment_vars:
- 'GOSRC=/tmp/libpod'
- - 'CNI_COMMIT={{user `CNI_COMMIT`}}'
- - 'FEDORA_CNI_COMMIT={{user `FEDORA_CNI_COMMIT`}}'
- - 'CONMON_COMMIT={{user `CONMON_COMMIT`}}'
- - 'CRIU_COMMIT={{user `CRIU_COMMIT`}}'
- - 'RUNC_COMMIT={{user `RUNC_COMMIT`}}'
- 'SCRIPT_BASE={{user `SCRIPT_BASE`}}'
post-processors:
- - - type: 'manifest' # writes packer-manifest.json
+ - type: 'manifest' # writes packer-manifest.json
diff --git a/contrib/cirrus/packer/ubuntu_setup.sh b/contrib/cirrus/packer/ubuntu_setup.sh
index f183932c1..6209f2f89 100644
--- a/contrib/cirrus/packer/ubuntu_setup.sh
+++ b/contrib/cirrus/packer/ubuntu_setup.sh
@@ -6,31 +6,28 @@
set -e
# Load in library (copied by packer, before this script was run)
-source /tmp/libpod/$SCRIPT_BASE/lib.sh
+source $GOSRC/$SCRIPT_BASE/lib.sh
-req_env_var SCRIPT_BASE CNI_COMMIT CONMON_COMMIT CRIU_COMMIT
+req_env_var SCRIPT_BASE
install_ooe
export GOPATH="$(mktemp -d)"
trap "sudo rm -rf $GOPATH" EXIT
-# Avoid getting stuck waiting for user input
-export DEBIAN_FRONTEND=noninteractive
+echo "Updating/configuring package repositories."
+$LILTO $SUDOAPTGET update
+$LILTO $SUDOAPTGET install software-properties-common
+$LILTO $SUDOAPTADD ppa:longsleep/golang-backports
+$LILTO $SUDOAPTADD ppa:projectatomic/ppa
+$LILTO $SUDOAPTADD ppa:criu/ppa
-# Try twice as workaround for minor networking problems
-echo "Updating system and installing package dependencies"
-ooe.sh sudo -E apt-get -qq update || sudo -E apt-get -qq update
-ooe.sh sudo -E apt-get -qq upgrade || sudo -E apt-get -qq upgrade
-ooe.sh sudo -E apt-get -qq install software-properties-common
+echo "Upgrading all packages"
+$LILTO $SUDOAPTGET update
+$BIGTO $SUDOAPTGET upgrade
-# Required to have Go 1.11 on Ubuntu 18.0.4
-ooe.sh sudo -E add-apt-repository --yes ppa:longsleep/golang-backports
-ooe.sh sudo -E add-apt-repository --yes ppa:projectatomic/ppa
-ooe.sh sudo -E add-apt-repository --yes ppa:criu/ppa
-ooe.sh sudo -E apt-get -qq update || sudo -E apt-get -qq update
-
-ooe.sh sudo -E apt-get -qq install \
+echo "Installing general testing and system dependencies"
+$BIGTO $SUDOAPTGET install \
apparmor \
autoconf \
automake \
@@ -38,6 +35,8 @@ ooe.sh sudo -E apt-get -qq install \
bison \
btrfs-tools \
build-essential \
+ containernetworking-plugins \
+ containers-common \
cri-o-runc \
criu \
curl \
@@ -73,6 +72,7 @@ ooe.sh sudo -E apt-get -qq install \
lsof \
netcat \
pkg-config \
+ podman \
protobuf-c-compiler \
protobuf-compiler \
python-future \
@@ -83,29 +83,22 @@ ooe.sh sudo -E apt-get -qq install \
python3-psutil \
python3-pytoml \
python3-setuptools \
+ slirp4netns \
+ skopeo \
socat \
unzip \
vim \
xz-utils \
zip
-echo "Fixing Ubuntu kernel not enabling swap accounting by default"
+echo "Forced Ubuntu 18 kernel to enable cgroup swap accounting."
SEDCMD='s/^GRUB_CMDLINE_LINUX="(.*)"/GRUB_CMDLINE_LINUX="\1 cgroup_enable=memory swapaccount=1"/g'
ooe.sh sudo sed -re "$SEDCMD" -i /etc/default/grub.d/*
ooe.sh sudo sed -re "$SEDCMD" -i /etc/default/grub
ooe.sh sudo update-grub
-install_conmon
-
-install_cni_plugins
-
sudo /tmp/libpod/hack/install_catatonit.sh
-
-install_varlink
-
-sudo mkdir -p /etc/containers
-sudo curl https://raw.githubusercontent.com/projectatomic/registries/master/registries.fedora\
- -o /etc/containers/registries.conf
+ooe.sh sudo make -C /tmp/libpod install.libseccomp.sudo
ubuntu_finalize
diff --git a/contrib/cirrus/rootless_test.sh b/contrib/cirrus/rootless_test.sh
index b5744671b..3f45aac84 100755
--- a/contrib/cirrus/rootless_test.sh
+++ b/contrib/cirrus/rootless_test.sh
@@ -5,7 +5,7 @@ set -e
remote=0
# The TEST_REMOTE_CLIENT environment variable decides whether
-# to test varlinke
+# to test varlink
if [[ "$TEST_REMOTE_CLIENT" == "true" ]]; then
remote=1
fi
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index 8fdcf5897..f312e593a 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -6,14 +6,15 @@ source $(dirname $0)/lib.sh
req_env_var USER HOME GOSRC SCRIPT_BASE SETUP_MARKER_FILEPATH
+show_env_vars
+
# Ensure this script only executes successfully once and always logs ending timestamp
[[ ! -e "$SETUP_MARKER_FILEPATH" ]] || exit 0
exithandler() {
RET=$?
- set +e
- show_env_vars
+ echo "."
echo "$(basename $0) exit status: $RET"
- [[ "$RET" -eq "0" ]] && date +%s >> "SETUP_MARKER_FILEPATH"
+ [[ "$RET" -eq "0" ]] && date +%s >> "$SETUP_MARKER_FILEPATH"
}
trap exithandler EXIT
@@ -31,6 +32,7 @@ done
# Anything externally dependent, should be made fixed-in-time by adding to
# contrib/cirrus/packer/*_setup.sh to be incorporated into VM cache-images
# (see docs).
+cd "${GOSRC}/"
case "${OS_REL_VER}" in
ubuntu-18) ;;
fedora-30) ;;
@@ -42,20 +44,10 @@ case "${OS_REL_VER}" in
*) bad_os_id_ver ;;
esac
-cd "${GOSRC}/"
# Reload to incorporate any changes from above
source "$SCRIPT_BASE/lib.sh"
-echo "Installing cni config, policy and registry config"
-req_env_var GOSRC
-sudo install -D -m 755 $GOSRC/cni/87-podman-bridge.conflist \
- /etc/cni/net.d/87-podman-bridge.conflist
-sudo install -D -m 755 $GOSRC/test/policy.json \
- /etc/containers/policy.json
-sudo install -D -m 755 $GOSRC/test/registries.conf \
- /etc/containers/registries.conf
-# cri-o if installed will mess with testing in non-obvious ways
-rm -f /etc/cni/net.d/*cri*
+install_test_configs
make install.tools
@@ -78,6 +70,8 @@ case "$SPECIALMODE" in
dnf install -y podman
$SCRIPT_BASE/setup_container_environment.sh
;;
+ windows) ;& # for podman-remote building only
+ darwin) ;;
*)
die 111 "Unsupported \$SPECIAL_MODE: $SPECIALMODE"
esac
diff --git a/contrib/cirrus/uncache_release_archives.sh b/contrib/cirrus/uncache_release_archives.sh
new file mode 120000
index 000000000..e9fc6edff
--- /dev/null
+++ b/contrib/cirrus/uncache_release_archives.sh
@@ -0,0 +1 @@
+cache_release_archive.sh \ No newline at end of file
diff --git a/contrib/cirrus/unit_test.sh b/contrib/cirrus/unit_test.sh
index 202663fb7..004839f17 100755
--- a/contrib/cirrus/unit_test.sh
+++ b/contrib/cirrus/unit_test.sh
@@ -1,12 +1,25 @@
#!/bin/bash
set -e
+
source $(dirname $0)/lib.sh
req_env_var GOSRC
-set -x
cd "$GOSRC"
make install.tools
make localunit
-make
+
+case "$SPECIALMODE" in
+ in_podman) ;&
+ rootless) ;&
+ none)
+ make
+ ;;
+ windows) ;&
+ darwin)
+ make podman-remote-$SPECIALMODE
+ ;;
+ *)
+ die 109 "Unsupported \$SPECIAL_MODE: $SPECIALMODE"
+esac
diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md
index 2425c817b..a34111a03 100644
--- a/docs/podman-create.1.md
+++ b/docs/podman-create.1.md
@@ -268,7 +268,7 @@ The following example maps uids 0-2000 in the container to the uids 30000-31999
Add additional groups to run as
-**--healthcheck**=*command*
+**--healthcheck-command**=*command*
Set or alter a healthcheck command for a container. The command is a command to be executed inside your
container that determines your container health. The command is required for other healthcheck options
diff --git a/docs/podman-generate-systemd.1.md b/docs/podman-generate-systemd.1.md
index 09752480d..64e68a69a 100644
--- a/docs/podman-generate-systemd.1.md
+++ b/docs/podman-generate-systemd.1.md
@@ -39,7 +39,7 @@ ExecStart=/usr/bin/podman start c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f14
ExecStop=/usr/bin/podman stop -t 10 c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc
KillMode=none
Type=forking
-PIDFile=/var/lib/containers/storage/overlay-containers/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc/userdata/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc.pid
+PIDFile=/var/run/containers/storage/overlay-containers/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc/userdata/conmon.pid
[Install]
WantedBy=multi-user.target
```
@@ -55,7 +55,7 @@ ExecStart=/usr/bin/podman start c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f14
ExecStop=/usr/bin/podman stop -t 1 c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc
KillMode=none
Type=forking
-PIDFile=/var/lib/containers/storage/overlay-containers/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc/userdata/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc.pid
+PIDFile=/var/run/containers/storage/overlay-containers/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc/userdata/conmon.pid
[Install]
WantedBy=multi-user.target
```
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index 84bf4a11b..86cc2125c 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -275,7 +275,7 @@ The example maps gids 0-2000 in the container to the gids 30000-31999 on the hos
Add additional groups to run as
-**--healthcheck**=*command*
+**--healthcheck-command**=*command*
Set or alter a healthcheck command for a container. The command is a command to be executed inside your
container that determines your container health. The command is required for other healthcheck options
diff --git a/docs/podman-stats.1.md b/docs/podman-stats.1.md
index b817662a8..b71d435fa 100644
--- a/docs/podman-stats.1.md
+++ b/docs/podman-stats.1.md
@@ -39,7 +39,7 @@ Valid placeholders for the Go template are listed below:
| **Placeholder** | **Description** |
| --------------- | --------------- |
| .Pod | Pod ID |
-| .CID | Container ID |
+| .ID | Container ID |
| .Name | Container Name |
| .CPU | CPU percentage |
| .MemUsage | Memory usage |
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index 4dda3a7f0..176781f07 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -66,7 +66,7 @@ func NewBoltState(path string, runtime *Runtime) (State, error) {
if err != nil {
return nil, errors.Wrapf(err, "error opening database %s", path)
}
- // Everywhere else, we use s.closeDBCon(db) to ensure the state's DB
+ // Everywhere else, we use s.deferredCloseDBCon(db) to ensure the state's DB
// mutex is also unlocked.
// However, here, the mutex has not been locked, since we just created
// the DB connection, and it hasn't left this function yet - no risk of
@@ -141,7 +141,7 @@ func (s *BoltState) Refresh() error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
idBucket, err := getIDBucket(tx)
@@ -253,7 +253,7 @@ func (s *BoltState) GetDBConfig() (*DBConfig, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
configBucket, err := getRuntimeConfigBucket(tx)
@@ -298,7 +298,7 @@ func (s *BoltState) ValidateDBConfig(runtime *Runtime) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
// Check runtime configuration
if err := checkRuntimeConfig(db, runtime); err != nil {
@@ -342,7 +342,7 @@ func (s *BoltState) Container(id string) (*Container, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
ctrBucket, err := getCtrBucket(tx)
@@ -378,7 +378,7 @@ func (s *BoltState) LookupContainer(idOrName string) (*Container, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
ctrBucket, err := getCtrBucket(tx)
@@ -484,7 +484,7 @@ func (s *BoltState) HasContainer(id string) (bool, error) {
if err != nil {
return false, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
exists := false
@@ -549,7 +549,7 @@ func (s *BoltState) RemoveContainer(ctr *Container) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
return s.removeContainer(ctr, nil, tx)
@@ -580,7 +580,7 @@ func (s *BoltState) UpdateContainer(ctr *Container) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
ctrBucket, err := getCtrBucket(tx)
@@ -651,7 +651,7 @@ func (s *BoltState) SaveContainer(ctr *Container) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
ctrBucket, err := getCtrBucket(tx)
@@ -708,7 +708,7 @@ func (s *BoltState) ContainerInUse(ctr *Container) ([]string, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
ctrBucket, err := getCtrBucket(tx)
@@ -759,7 +759,7 @@ func (s *BoltState) AllContainers() ([]*Container, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
allCtrsBucket, err := getAllCtrsBucket(tx)
@@ -833,7 +833,7 @@ func (s *BoltState) RewriteContainerConfig(ctr *Container, newCfg *ContainerConf
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
ctrBkt, err := getCtrBucket(tx)
@@ -877,7 +877,7 @@ func (s *BoltState) RewritePodConfig(pod *Pod, newCfg *PodConfig) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -920,7 +920,7 @@ func (s *BoltState) Pod(id string) (*Pod, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -955,7 +955,7 @@ func (s *BoltState) LookupPod(idOrName string) (*Pod, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -1062,7 +1062,7 @@ func (s *BoltState) HasPod(id string) (bool, error) {
if err != nil {
return false, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -1118,7 +1118,7 @@ func (s *BoltState) PodHasContainer(pod *Pod, id string) (bool, error) {
if err != nil {
return false, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -1180,7 +1180,7 @@ func (s *BoltState) PodContainersByID(pod *Pod) ([]string, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -1242,7 +1242,7 @@ func (s *BoltState) PodContainers(pod *Pod) ([]*Container, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -1312,7 +1312,7 @@ func (s *BoltState) AddVolume(volume *Volume) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
volBkt, err := getVolBucket(tx)
@@ -1369,7 +1369,7 @@ func (s *BoltState) RemoveVolume(volume *Volume) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
volBkt, err := getVolBucket(tx)
@@ -1451,7 +1451,7 @@ func (s *BoltState) AllVolumes() ([]*Volume, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
allVolsBucket, err := getAllVolsBucket(tx)
@@ -1512,7 +1512,7 @@ func (s *BoltState) Volume(name string) (*Volume, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
volBkt, err := getVolBucket(tx)
@@ -1547,7 +1547,7 @@ func (s *BoltState) HasVolume(name string) (bool, error) {
if err != nil {
return false, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
volBkt, err := getVolBucket(tx)
@@ -1587,7 +1587,7 @@ func (s *BoltState) VolumeInUse(volume *Volume) ([]string, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
volBucket, err := getVolBucket(tx)
@@ -1673,7 +1673,7 @@ func (s *BoltState) AddPod(pod *Pod) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -1782,7 +1782,7 @@ func (s *BoltState) RemovePod(pod *Pod) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -1877,7 +1877,7 @@ func (s *BoltState) RemovePodContainers(pod *Pod) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
podBkt, err := getPodBucket(tx)
@@ -2038,7 +2038,7 @@ func (s *BoltState) RemoveContainerFromPod(pod *Pod, ctr *Container) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
return s.removeContainer(ctr, pod, tx)
@@ -2066,7 +2066,7 @@ func (s *BoltState) UpdatePod(pod *Pod) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
podID := []byte(pod.ID())
@@ -2126,7 +2126,7 @@ func (s *BoltState) SavePod(pod *Pod) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
podID := []byte(pod.ID())
@@ -2168,7 +2168,7 @@ func (s *BoltState) AllPods() ([]*Pod, error) {
if err != nil {
return nil, err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
allPodsBucket, err := getAllPodsBucket(tx)
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index 122bb5935..408ef7224 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -247,6 +247,15 @@ func (s *BoltState) getDBCon() (*bolt.DB, error) {
return db, nil
}
+// deferredCloseDBCon closes the bolt db but instead of returning an
+// error it logs the error. it is meant to be used within the confines
+// of a defer statement only
+func (s *BoltState) deferredCloseDBCon(db *bolt.DB) {
+ if err := s.closeDBCon(db); err != nil {
+ logrus.Errorf("failed to close libpod db: %q", err)
+ }
+}
+
// Close a connection to the database.
// MUST be used in place of `db.Close()` to ensure proper unlocking of the
// state.
@@ -339,7 +348,6 @@ func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
}
func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.Bucket) error {
- valid := true
ctrBkt := ctrsBkt.Bucket(id)
if ctrBkt == nil {
return errors.Wrapf(define.ErrNoSuchCtr, "container %s not found in DB", string(id))
@@ -386,7 +394,7 @@ func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.
}
ctr.runtime = s.runtime
- ctr.valid = valid
+ ctr.valid = true
return nil
}
@@ -480,7 +488,7 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
if err != nil {
return err
}
- defer s.closeDBCon(db)
+ defer s.deferredCloseDBCon(db)
err = db.Update(func(tx *bolt.Tx) error {
idsBucket, err := getIDBucket(tx)
@@ -639,7 +647,7 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
}
// Add ctr to pod
- if pod != nil {
+ if pod != nil && podCtrs != nil {
if err := podCtrs.Put(ctrID, ctrName); err != nil {
return errors.Wrapf(err, "error adding container %s to pod %s", ctr.ID(), pod.ID())
}
@@ -737,7 +745,7 @@ func (s *BoltState) removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error
}
}
- if podDB != nil {
+ if podDB != nil && pod != nil {
// Check if the container is in the pod, remove it if it is
podCtrs := podDB.Bucket(containersBkt)
if podCtrs == nil {
diff --git a/libpod/common_test.go b/libpod/common_test.go
index ae3cb1c87..93ca7bc71 100644
--- a/libpod/common_test.go
+++ b/libpod/common_test.go
@@ -89,13 +89,13 @@ func getTestContainer(id, name string, manager lock.Manager) (*Container, error)
ctr.config.Labels["test"] = "testing"
- // Allocate a lock for the container
- lock, err := manager.AllocateLock()
+ // Allocate a containerLock for the container
+ containerLock, err := manager.AllocateLock()
if err != nil {
return nil, err
}
- ctr.lock = lock
- ctr.config.LockID = lock.ID()
+ ctr.lock = containerLock
+ ctr.config.LockID = containerLock.ID()
return ctr, nil
}
@@ -114,13 +114,13 @@ func getTestPod(id, name string, manager lock.Manager) (*Pod, error) {
valid: true,
}
- // Allocate a lock for the pod
- lock, err := manager.AllocateLock()
+ // Allocate a podLock for the pod
+ podLock, err := manager.AllocateLock()
if err != nil {
return nil, err
}
- pod.lock = lock
- pod.config.LockID = lock.ID()
+ pod.lock = podLock
+ pod.config.LockID = podLock.ID()
return pod, nil
}
diff --git a/libpod/container.go b/libpod/container.go
index bfbc47d76..a9b512de9 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -138,6 +138,9 @@ type Container struct {
// being checkpointed. If requestedIP is set it will be used instead
// of config.StaticIP.
requestedIP net.IP
+
+ // This is true if a container is restored from a checkpoint.
+ restoreFromCheckpoint bool
}
// ContainerState contains the current state of the container
diff --git a/libpod/container_attach_linux.go b/libpod/container_attach_linux.go
index fc53268c3..43dd7d579 100644
--- a/libpod/container_attach_linux.go
+++ b/libpod/container_attach_linux.go
@@ -10,6 +10,7 @@ import (
"path/filepath"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/libpod/pkg/kubeutils"
"github.com/containers/libpod/utils"
"github.com/docker/docker/pkg/term"
@@ -66,7 +67,7 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi
logrus.Debugf("Could not open ctl file: %v", err)
return
}
- defer controlFile.Close()
+ defer errorhandling.CloseQuiet(controlFile)
logrus.Debugf("Received a resize event: %+v", size)
if _, err = fmt.Fprintf(controlFile, "%d %d %d\n", 1, size.Height, size.Width); err != nil {
@@ -108,7 +109,9 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi
var err error
if streams.AttachInput {
_, err = utils.CopyDetachable(conn, streams.InputStream, detachKeys)
- conn.CloseWrite()
+ if err := conn.CloseWrite(); err != nil {
+ logrus.Error("failed to close write in attach")
+ }
}
stdinDone <- err
}()
@@ -145,7 +148,9 @@ func redirectResponseToOutputStreams(outputStream, errorStream io.Writer, writeO
default:
logrus.Infof("Received unexpected attach type %+d", buf[0])
}
-
+ if dst == nil {
+ return errors.New("output destination cannot be nil")
+ }
if doWrite {
nw, ew := dst.Write(buf[1:nr])
if ew != nil {
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 18e84e1f1..2de78254c 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -206,12 +206,12 @@ func (c *Container) Inspect(size bool) (*InspectContainerData, error) {
func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) (*InspectContainerData, error) {
config := c.config
runtimeInfo := c.state
- spec, err := c.specFromState()
+ stateSpec, err := c.specFromState()
if err != nil {
return nil, err
}
- // Process is allowed to be nil in the spec
+ // Process is allowed to be nil in the stateSpec
args := []string{}
if config.Spec.Process != nil {
args = config.Spec.Process.Args
@@ -244,7 +244,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
}
}
- mounts, err := c.getInspectMounts(spec)
+ mounts, err := c.getInspectMounts(stateSpec)
if err != nil {
return nil, err
}
@@ -255,7 +255,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
Path: path,
Args: args,
State: &InspectContainerState{
- OciVersion: spec.Version,
+ OciVersion: stateSpec.Version,
Status: runtimeInfo.State.String(),
Running: runtimeInfo.State == define.ContainerStateRunning,
Paused: runtimeInfo.State == define.ContainerStatePaused,
@@ -285,9 +285,9 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
Driver: driverData.Name,
MountLabel: config.MountLabel,
ProcessLabel: config.ProcessLabel,
- EffectiveCaps: spec.Process.Capabilities.Effective,
- BoundingCaps: spec.Process.Capabilities.Bounding,
- AppArmorProfile: spec.Process.ApparmorProfile,
+ EffectiveCaps: stateSpec.Process.Capabilities.Effective,
+ BoundingCaps: stateSpec.Process.Capabilities.Bounding,
+ AppArmorProfile: stateSpec.Process.ApparmorProfile,
ExecIDs: execIDs,
GraphDriver: driverData,
Mounts: mounts,
@@ -338,7 +338,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
// Get information on the container's network namespace (if present)
data = c.getContainerNetworkInfo(data)
- inspectConfig, err := c.generateInspectContainerConfig(spec)
+ inspectConfig, err := c.generateInspectContainerConfig(stateSpec)
if err != nil {
return nil, err
}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 611fa9800..c409da96a 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -352,6 +352,16 @@ func (c *Container) setupStorage(ctx context.Context) error {
},
LabelOpts: c.config.LabelOpts,
}
+ if c.restoreFromCheckpoint {
+ // If restoring from a checkpoint, the root file-system
+ // needs to be mounted with the same SELinux labels as
+ // it was mounted previously.
+ if options.Flags == nil {
+ options.Flags = make(map[string]interface{})
+ }
+ options.Flags["ProcessLabel"] = c.config.ProcessLabel
+ options.Flags["MountLabel"] = c.config.MountLabel
+ }
if c.config.Privileged {
privOpt := func(opt string) bool {
for _, privopt := range []string{"nodev", "nosuid", "noexec"} {
@@ -555,7 +565,7 @@ func (c *Container) removeConmonFiles() error {
if !os.IsNotExist(err) {
return errors.Wrapf(err, "error running stat on container %s exit file", c.ID())
}
- } else if err == nil {
+ } else {
// Rename should replace the old exit file (if it exists)
if err := os.Rename(exitFile, oldExitFile); err != nil {
return errors.Wrapf(err, "error renaming container %s exit file", c.ID())
@@ -568,11 +578,11 @@ func (c *Container) removeConmonFiles() error {
func (c *Container) export(path string) error {
mountPoint := c.state.Mountpoint
if !c.state.Mounted {
- mount, err := c.runtime.store.Mount(c.ID(), c.config.MountLabel)
+ containerMount, err := c.runtime.store.Mount(c.ID(), c.config.MountLabel)
if err != nil {
return errors.Wrapf(err, "error mounting container %q", c.ID())
}
- mountPoint = mount
+ mountPoint = containerMount
defer func() {
if _, err := c.runtime.store.Unmount(c.ID(), false); err != nil {
logrus.Errorf("error unmounting container %q: %v", c.ID(), err)
@@ -856,18 +866,18 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error {
span.SetTag("struct", "container")
defer span.Finish()
- // Generate the OCI spec
- spec, err := c.generateSpec(ctx)
+ // Generate the OCI newSpec
+ newSpec, err := c.generateSpec(ctx)
if err != nil {
return err
}
- // Save the OCI spec to disk
- if err := c.saveSpec(spec); err != nil {
+ // Save the OCI newSpec to disk
+ if err := c.saveSpec(newSpec); err != nil {
return err
}
- // With the spec complete, do an OCI create
+ // With the newSpec complete, do an OCI create
if err := c.ociRuntime.createContainer(c, c.config.CgroupParent, nil); err != nil {
return err
}
@@ -1167,8 +1177,8 @@ func (c *Container) cleanupStorage() error {
return nil
}
- for _, mount := range c.config.Mounts {
- if err := c.unmountSHM(mount); err != nil {
+ for _, containerMount := range c.config.Mounts {
+ if err := c.unmountSHM(containerMount); err != nil {
return err
}
}
@@ -1399,14 +1409,14 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (exten
}
return nil, err
}
- hooks, err := manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0)
+ ociHooks, err := manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0)
if err != nil {
return nil, err
}
- if len(hooks) > 0 || config.Hooks != nil {
- logrus.Warnf("implicit hook directories are deprecated; set --hooks-dir=%q explicitly to continue to load hooks from this directory", hDir)
+ if len(ociHooks) > 0 || config.Hooks != nil {
+ logrus.Warnf("implicit hook directories are deprecated; set --ociHooks-dir=%q explicitly to continue to load ociHooks from this directory", hDir)
}
- for i, hook := range hooks {
+ for i, hook := range ociHooks {
allHooks[i] = hook
}
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index fad45233a..aa477611f 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -185,9 +185,13 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
// If network namespace was requested, add it now
if c.config.CreateNetNS {
if c.config.PostConfigureNetNS {
- g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, "")
+ if err := g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, ""); err != nil {
+ return nil, err
+ }
} else {
- g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path())
+ if err := g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path()); err != nil {
+ return nil, err
+ }
}
}
@@ -415,7 +419,9 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
if rootPropagation != "" {
logrus.Debugf("set root propagation to %q", rootPropagation)
- g.SetLinuxRootPropagation(rootPropagation)
+ if err := g.SetLinuxRootPropagation(rootPropagation); err != nil {
+ return nil, err
+ }
}
// Warning: precreate hooks may alter g.Config in place.
@@ -561,7 +567,9 @@ func (c *Container) checkpointRestoreLabelLog(fileName string) (err error) {
if err != nil {
return errors.Wrapf(err, "failed to create CRIU log file %q", dumpLog)
}
- logFile.Close()
+ if err := logFile.Close(); err != nil {
+ logrus.Errorf("unable to close log file: %q", err)
+ }
if err = label.SetFileLabel(dumpLog, c.MountLabel()); err != nil {
return errors.Wrapf(err, "failed to label CRIU log file %q", dumpLog)
}
@@ -620,12 +628,15 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
"config.dump",
"spec.dump",
}
- for _, delete := range cleanup {
- file := filepath.Join(c.bundlePath(), delete)
- os.Remove(file)
+ for _, del := range cleanup {
+ file := filepath.Join(c.bundlePath(), del)
+ if err := os.Remove(file); err != nil {
+ logrus.Debugf("unable to remove file %s", file)
+ }
}
}
+ c.state.FinishedTime = time.Now()
return c.save()
}
@@ -702,7 +713,9 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
if err != nil {
return err
}
- json.Unmarshal(networkJSON, &networkStatus)
+ if err := json.Unmarshal(networkJSON, &networkStatus); err != nil {
+ return err
+ }
// Take the first IP address
var IP net.IP
if len(networkStatus) > 0 {
@@ -744,7 +757,9 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
// We want to have the same network namespace as before.
if c.config.CreateNetNS {
- g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path())
+ if err := g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path()); err != nil {
+ return err
+ }
}
if err := c.makeBindMounts(); err != nil {
@@ -769,7 +784,9 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
// Cleanup for a working restore.
- c.removeConmonFiles()
+ if err := c.removeConmonFiles(); err != nil {
+ return err
+ }
// Save the OCI spec to disk
if err := c.saveSpec(g.Spec()); err != nil {
@@ -793,8 +810,8 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
logrus.Debugf("Non-fatal: removal of checkpoint directory (%s) failed: %v", c.CheckpointPath(), err)
}
cleanup := [...]string{"restore.log", "dump.log", "stats-dump", "stats-restore", "network.status"}
- for _, delete := range cleanup {
- file := filepath.Join(c.bundlePath(), delete)
+ for _, del := range cleanup {
+ file := filepath.Join(c.bundlePath(), del)
err = os.Remove(file)
if err != nil {
logrus.Debugf("Non-fatal: removal of checkpoint file (%s) failed: %v", file, err)
@@ -824,14 +841,14 @@ func (c *Container) makeBindMounts() error {
// will recreate. Only do this if we aren't sharing them with
// another container.
if c.config.NetNsCtr == "" {
- if path, ok := c.state.BindMounts["/etc/resolv.conf"]; ok {
- if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
+ if resolvePath, ok := c.state.BindMounts["/etc/resolv.conf"]; ok {
+ if err := os.Remove(resolvePath); err != nil && !os.IsNotExist(err) {
return errors.Wrapf(err, "error removing container %s resolv.conf", c.ID())
}
delete(c.state.BindMounts, "/etc/resolv.conf")
}
- if path, ok := c.state.BindMounts["/etc/hosts"]; ok {
- if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
+ if hostsPath, ok := c.state.BindMounts["/etc/hosts"]; ok {
+ if err := os.Remove(hostsPath); err != nil && !os.IsNotExist(err) {
return errors.Wrapf(err, "error removing container %s hosts", c.ID())
}
delete(c.state.BindMounts, "/etc/hosts")
@@ -968,10 +985,10 @@ func (c *Container) makeBindMounts() error {
// generateResolvConf generates a containers resolv.conf
func (c *Container) generateResolvConf() (string, error) {
resolvConf := "/etc/resolv.conf"
- for _, ns := range c.config.Spec.Linux.Namespaces {
- if ns.Type == spec.NetworkNamespace {
- if ns.Path != "" && !strings.HasPrefix(ns.Path, "/proc/") {
- definedPath := filepath.Join("/etc/netns", filepath.Base(ns.Path), "resolv.conf")
+ for _, namespace := range c.config.Spec.Linux.Namespaces {
+ if namespace.Type == spec.NetworkNamespace {
+ if namespace.Path != "" && !strings.HasPrefix(namespace.Path, "/proc/") {
+ definedPath := filepath.Join("/etc/netns", filepath.Base(namespace.Path), "resolv.conf")
_, err := os.Stat(definedPath)
if err == nil {
resolvConf = definedPath
@@ -1096,10 +1113,10 @@ func (c *Container) generatePasswd() (string, error) {
if c.config.User == "" {
return "", nil
}
- spec := strings.SplitN(c.config.User, ":", 2)
- userspec := spec[0]
- if len(spec) > 1 {
- groupspec = spec[1]
+ splitSpec := strings.SplitN(c.config.User, ":", 2)
+ userspec := splitSpec[0]
+ if len(splitSpec) > 1 {
+ groupspec = splitSpec[1]
}
// If a non numeric User, then don't generate passwd
uid, err := strconv.ParseUint(userspec, 10, 32)
@@ -1137,7 +1154,7 @@ func (c *Container) generatePasswd() (string, error) {
if err != nil {
return "", errors.Wrapf(err, "failed to create temporary passwd file")
}
- if os.Chmod(passwdFile, 0644); err != nil {
+ if err := os.Chmod(passwdFile, 0644); err != nil {
return "", err
}
return passwdFile, nil
diff --git a/libpod/healthcheck_linux.go b/libpod/healthcheck_linux.go
index d47a3b7cd..53fb271d1 100644
--- a/libpod/healthcheck_linux.go
+++ b/libpod/healthcheck_linux.go
@@ -4,13 +4,50 @@ import (
"fmt"
"os"
"os/exec"
+ "path/filepath"
+ "strconv"
"strings"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/coreos/go-systemd/dbus"
+ godbus "github.com/godbus/dbus"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
+func dbusAuthRootlessConnection(createBus func(opts ...godbus.ConnOption) (*godbus.Conn, error)) (*godbus.Conn, error) {
+ conn, err := createBus()
+ if err != nil {
+ return nil, err
+ }
+
+ methods := []godbus.Auth{godbus.AuthExternal(strconv.Itoa(rootless.GetRootlessUID()))}
+
+ err = conn.Auth(methods)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+
+ return conn, nil
+}
+
+func newRootlessConnection() (*dbus.Conn, error) {
+ return dbus.NewConnection(func() (*godbus.Conn, error) {
+ return dbusAuthRootlessConnection(func(opts ...godbus.ConnOption) (*godbus.Conn, error) {
+ path := filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "systemd/private")
+ return godbus.Dial(fmt.Sprintf("unix:path=%s", path))
+ })
+ })
+}
+
+func getConnection() (*dbus.Conn, error) {
+ if rootless.IsRootless() {
+ return newRootlessConnection()
+ }
+ return dbus.NewSystemdConnection()
+}
+
// createTimer systemd timers for healthchecks of a container
func (c *Container) createTimer() error {
if c.disableHealthCheckSystemd() {
@@ -21,9 +58,13 @@ func (c *Container) createTimer() error {
return errors.Wrapf(err, "failed to get path for podman for a health check timer")
}
- var cmd = []string{"--unit", fmt.Sprintf("%s", c.ID()), fmt.Sprintf("--on-unit-inactive=%s", c.HealthCheckConfig().Interval.String()), "--timer-property=AccuracySec=1s", podman, "healthcheck", "run", c.ID()}
+ var cmd = []string{}
+ if rootless.IsRootless() {
+ cmd = append(cmd, "--user")
+ }
+ cmd = append(cmd, "--unit", fmt.Sprintf("%s", c.ID()), fmt.Sprintf("--on-unit-inactive=%s", c.HealthCheckConfig().Interval.String()), "--timer-property=AccuracySec=1s", podman, "healthcheck", "run", c.ID())
- conn, err := dbus.NewSystemdConnection()
+ conn, err := getConnection()
if err != nil {
return errors.Wrapf(err, "unable to get systemd connection to add healthchecks")
}
@@ -42,7 +83,7 @@ func (c *Container) startTimer() error {
if c.disableHealthCheckSystemd() {
return nil
}
- conn, err := dbus.NewSystemdConnection()
+ conn, err := getConnection()
if err != nil {
return errors.Wrapf(err, "unable to get systemd connection to start healthchecks")
}
@@ -57,7 +98,7 @@ func (c *Container) removeTimer() error {
if c.disableHealthCheckSystemd() {
return nil
}
- conn, err := dbus.NewSystemdConnection()
+ conn, err := getConnection()
if err != nil {
return errors.Wrapf(err, "unable to get systemd connection to remove healthchecks")
}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 76e46f74f..6509134ac 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -323,7 +323,7 @@ func (i *Image) Names() []string {
// RepoDigests returns a string array of repodigests associated with the image
func (i *Image) RepoDigests() ([]string, error) {
var repoDigests []string
- digest := i.Digest()
+ imageDigest := i.Digest()
for _, name := range i.Names() {
named, err := reference.ParseNormalizedNamed(name)
@@ -331,7 +331,7 @@ func (i *Image) RepoDigests() ([]string, error) {
return nil, err
}
- canonical, err := reference.WithDigest(reference.TrimNamed(named), digest)
+ canonical, err := reference.WithDigest(reference.TrimNamed(named), imageDigest)
if err != nil {
return nil, err
}
@@ -462,11 +462,11 @@ func getImageDigest(ctx context.Context, src types.ImageReference, sc *types.Sys
return "", err
}
defer newImg.Close()
- digest := newImg.ConfigInfo().Digest
- if err = digest.Validate(); err != nil {
+ imageDigest := newImg.ConfigInfo().Digest
+ if err = imageDigest.Validate(); err != nil {
return "", errors.Wrapf(err, "error getting config info")
}
- return "@" + digest.Hex(), nil
+ return "@" + imageDigest.Hex(), nil
}
// normalizedTag returns the canonical version of tag for use in Image.Names()
@@ -495,7 +495,9 @@ func normalizedTag(tag string) (reference.Named, error) {
// TagImage adds a tag to the given image
func (i *Image) TagImage(tag string) error {
- i.reloadImage()
+ if err := i.reloadImage(); err != nil {
+ return err
+ }
ref, err := normalizedTag(tag)
if err != nil {
return err
@@ -508,14 +510,18 @@ func (i *Image) TagImage(tag string) error {
if err := i.imageruntime.store.SetNames(i.ID(), tags); err != nil {
return err
}
- i.reloadImage()
+ if err := i.reloadImage(); err != nil {
+ return err
+ }
defer i.newImageEvent(events.Tag)
return nil
}
// UntagImage removes a tag from the given image
func (i *Image) UntagImage(tag string) error {
- i.reloadImage()
+ if err := i.reloadImage(); err != nil {
+ return err
+ }
var newTags []string
tags := i.Names()
if !util.StringInSlice(tag, tags) {
@@ -529,7 +535,9 @@ func (i *Image) UntagImage(tag string) error {
if err := i.imageruntime.store.SetNames(i.ID(), newTags); err != nil {
return err
}
- i.reloadImage()
+ if err := i.reloadImage(); err != nil {
+ return err
+ }
defer i.newImageEvent(events.Untag)
return nil
}
@@ -825,7 +833,7 @@ func (i *Image) GetLabel(ctx context.Context, label string) (string, error) {
// Annotations returns the annotations of an image
func (i *Image) Annotations(ctx context.Context) (map[string]string, error) {
- manifest, manifestType, err := i.Manifest(ctx)
+ imageManifest, manifestType, err := i.Manifest(ctx)
if err != nil {
return nil, err
}
@@ -833,7 +841,7 @@ func (i *Image) Annotations(ctx context.Context) (map[string]string, error) {
switch manifestType {
case ociv1.MediaTypeImageManifest:
var m ociv1.Manifest
- if err := json.Unmarshal(manifest, &m); err == nil {
+ if err := json.Unmarshal(imageManifest, &m); err == nil {
for k, v := range m.Annotations {
annotations[k] = v
}
diff --git a/libpod/image/pull.go b/libpod/image/pull.go
index e5765febc..ce8a19fbc 100644
--- a/libpod/image/pull.go
+++ b/libpod/image/pull.go
@@ -263,7 +263,9 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa
copyOptions.SourceCtx.SystemRegistriesConfPath = systemRegistriesConfPath // FIXME: Set this more globally. Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place.
// Print the following statement only when pulling from a docker or atomic registry
if writer != nil && (imageInfo.srcRef.Transport().Name() == DockerTransport || imageInfo.srcRef.Transport().Name() == AtomicTransport) {
- io.WriteString(writer, fmt.Sprintf("Trying to pull %s...", imageInfo.image))
+ if _, err := io.WriteString(writer, fmt.Sprintf("Trying to pull %s...", imageInfo.image)); err != nil {
+ return nil, err
+ }
}
// If the label is not nil, check if the label exists and if not, return err
if label != nil {
@@ -277,7 +279,7 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa
pullErrors = multierror.Append(pullErrors, err)
logrus.Errorf("Error pulling image ref %s: %v", imageInfo.srcRef.StringWithinTransport(), err)
if writer != nil {
- io.WriteString(writer, "Failed\n")
+ _, _ = io.WriteString(writer, "Failed\n")
}
} else {
if !goal.pullAllPairs {
diff --git a/libpod/image/search.go b/libpod/image/search.go
index 03a67636b..9984e5234 100644
--- a/libpod/image/search.go
+++ b/libpod/image/search.go
@@ -99,7 +99,9 @@ func SearchImages(term string, options SearchOptions) ([]SearchResult, error) {
ctx := context.Background()
for i := range registries {
- sem.Acquire(ctx, 1)
+ if err := sem.Acquire(ctx, 1); err != nil {
+ return nil, err
+ }
go searchImageInRegistryHelper(i, registries[i])
}
diff --git a/libpod/kube.go b/libpod/kube.go
index 08ab7a4a4..409937010 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -17,7 +17,6 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -324,22 +323,6 @@ func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) {
return envVars, nil
}
-// Is this worth it?
-func libpodMaxAndMinToResourceList(c *Container) (v1.ResourceList, v1.ResourceList) { //nolint
- // It does not appear we can properly calculate CPU resources from the information
- // we know in libpod. Libpod knows CPUs by time, shares, etc.
-
- // We also only know about a memory limit; no memory minimum
- maxResources := make(map[v1.ResourceName]resource.Quantity)
- minResources := make(map[v1.ResourceName]resource.Quantity)
- config := c.Config()
- maxMem := config.Spec.Linux.Resources.Memory.Limit
-
- _ = maxMem
-
- return maxResources, minResources
-}
-
// libpodMountsToKubeVolumeMounts converts the containers mounts to a struct kube understands
func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, error) {
var vms []v1.VolumeMount
@@ -427,16 +410,14 @@ func determineCapAddDropFromCapabilities(defaultCaps, containerCaps []string) *v
// those indicate a dropped cap
for _, capability := range defaultCaps {
if !util.StringInSlice(capability, containerCaps) {
- cap := v1.Capability(capability)
- drop = append(drop, cap)
+ drop = append(drop, v1.Capability(capability))
}
}
// Find caps in the container but not in the defaults; those indicate
// an added cap
for _, capability := range containerCaps {
if !util.StringInSlice(capability, defaultCaps) {
- cap := v1.Capability(capability)
- add = append(add, cap)
+ add = append(add, v1.Capability(capability))
}
}
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 27585b8d5..987c1fc5b 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -5,6 +5,7 @@ package libpod
import (
"crypto/rand"
"fmt"
+ "github.com/containers/libpod/pkg/errorhandling"
"net"
"os"
"os/exec"
@@ -168,8 +169,8 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
if err != nil {
return errors.Wrapf(err, "failed to open pipe")
}
- defer syncR.Close()
- defer syncW.Close()
+ defer errorhandling.CloseQuiet(syncR)
+ defer errorhandling.CloseQuiet(syncW)
havePortMapping := len(ctr.Config().PortMappings) > 0
apiSocket := filepath.Join(ctr.ociRuntime.tmpDir, fmt.Sprintf("%s.net", ctr.config.ID))
@@ -294,14 +295,14 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
return errors.Wrapf(err, "cannot shutdown the socket %s", apiSocket)
}
buf := make([]byte, 2048)
- len, err := conn.Read(buf)
+ readLength, err := conn.Read(buf)
if err != nil {
return errors.Wrapf(err, "cannot read from control socket %s", apiSocket)
}
// if there is no 'error' key in the received JSON data, then the operation was
// successful.
var y map[string]interface{}
- if err := json.Unmarshal(buf[0:len], &y); err != nil {
+ if err := json.Unmarshal(buf[0:readLength], &y); err != nil {
return errors.Wrapf(err, "error parsing error status from slirp4netns")
}
if e, found := y["error"]; found {
@@ -332,7 +333,9 @@ func (r *Runtime) setupNetNS(ctr *Container) (err error) {
if err != nil {
return errors.Wrapf(err, "cannot open %s", nsPath)
}
- mountPointFd.Close()
+ if err := mountPointFd.Close(); err != nil {
+ return err
+ }
if err := unix.Mount(nsProcess, nsPath, "none", unix.MS_BIND, ""); err != nil {
return errors.Wrapf(err, "cannot mount %s", nsPath)
@@ -352,12 +355,12 @@ func (r *Runtime) setupNetNS(ctr *Container) (err error) {
// Join an existing network namespace
func joinNetNS(path string) (ns.NetNS, error) {
- ns, err := ns.GetNS(path)
+ netNS, err := ns.GetNS(path)
if err != nil {
return nil, errors.Wrapf(err, "error retrieving network namespace at %s", path)
}
- return ns, nil
+ return netNS, nil
}
// Close a network namespace.
diff --git a/libpod/oci.go b/libpod/oci.go
index fdd783100..6aad79cdf 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -263,7 +263,9 @@ func (r *OCIRuntime) updateContainerStatus(ctr *Container, useRuntime bool) erro
return errors.Wrapf(err, "error getting container %s state", ctr.ID())
}
if strings.Contains(string(out), "does not exist") {
- ctr.removeConmonFiles()
+ if err := ctr.removeConmonFiles(); err != nil {
+ logrus.Debugf("unable to remove conmon files for container %s", ctr.ID())
+ }
ctr.state.ExitCode = -1
ctr.state.FinishedTime = time.Now()
ctr.state.State = define.ContainerStateExited
@@ -273,7 +275,9 @@ func (r *OCIRuntime) updateContainerStatus(ctr *Container, useRuntime bool) erro
}
defer cmd.Wait()
- errPipe.Close()
+ if err := errPipe.Close(); err != nil {
+ return err
+ }
out, err := ioutil.ReadAll(outPipe)
if err != nil {
return errors.Wrapf(err, "error reading stdout: %s", ctr.ID())
@@ -433,8 +437,8 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
args = append(args, "--no-new-privs")
}
- for _, cap := range capAdd {
- args = append(args, "--cap", cap)
+ for _, capabilityAdd := range capAdd {
+ args = append(args, "--cap", capabilityAdd)
}
for _, envVar := range env {
@@ -475,7 +479,9 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
for fd := 3; fd < 3+preserveFDs; fd++ {
// These fds were passed down to the runtime. Close them
// and not interfere
- os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close()
+ if err := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close(); err != nil {
+ logrus.Debugf("unable to close file fd-%d", fd)
+ }
}
}
@@ -484,7 +490,9 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
// checkpointContainer checkpoints the given container
func (r *OCIRuntime) checkpointContainer(ctr *Container, options ContainerCheckpointOptions) error {
- label.SetSocketLabel(ctr.ProcessLabel())
+ if err := label.SetSocketLabel(ctr.ProcessLabel()); err != nil {
+ return err
+ }
// imagePath is used by CRIU to store the actual checkpoint files
imagePath := ctr.CheckpointPath()
// workPath will be used to store dump.log and stats-dump
diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go
index 24502ef4f..ca13d5517 100644
--- a/libpod/oci_linux.go
+++ b/libpod/oci_linux.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/cgroups"
+ "github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
@@ -117,7 +118,7 @@ func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restor
if err != nil {
return err
}
- defer fd.Close()
+ defer errorhandling.CloseQuiet(fd)
// create a new mountns on the current thread
if err = unix.Unshare(unix.CLONE_NEWNS); err != nil {
@@ -207,8 +208,8 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
return errors.Wrapf(err, "error creating socket pair for start pipe")
}
- defer parentPipe.Close()
- defer parentStartPipe.Close()
+ defer errorhandling.CloseQuiet(parentPipe)
+ defer errorhandling.CloseQuiet(parentStartPipe)
ociLog := filepath.Join(ctr.state.RunDir, "oci-log")
logLevel := logrus.GetLevel()
@@ -342,7 +343,9 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
)
plabel, err = selinux.CurrentLabel()
if err != nil {
- childPipe.Close()
+ if err := childPipe.Close(); err != nil {
+ logrus.Errorf("failed to close child pipe: %q", err)
+ }
return errors.Wrapf(err, "Failed to get current SELinux label")
}
@@ -362,20 +365,26 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
err = cmd.Start()
// Ignore error returned from SetProcessLabel("") call,
// can't recover.
- label.SetProcessLabel("")
+ if err := label.SetProcessLabel(""); err != nil {
+ _ = err
+ }
runtime.UnlockOSThread()
} else {
err = cmd.Start()
}
if err != nil {
- childPipe.Close()
+ errorhandling.CloseQuiet(childPipe)
return err
}
defer cmd.Wait()
// We don't need childPipe on the parent side
- childPipe.Close()
- childStartPipe.Close()
+ if err := childPipe.Close(); err != nil {
+ return err
+ }
+ if err := childStartPipe.Close(); err != nil {
+ return err
+ }
// Move conmon to specified cgroup
if err := r.moveConmonToCgroup(ctr, cgroupParent, cmd); err != nil {
diff --git a/libpod/options.go b/libpod/options.go
index 78634e953..4f8bb42df 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -325,7 +325,7 @@ func WithMaxLogSize(limit int64) RuntimeOption {
// WithNoPivotRoot sets the runtime to use MS_MOVE instead of PIVOT_ROOT when
// starting containers.
-func WithNoPivotRoot(noPivot bool) RuntimeOption {
+func WithNoPivotRoot() RuntimeOption {
return func(rt *Runtime) error {
if rt.valid {
return config2.ErrRuntimeFinalized
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 6c61e15d3..9196547a2 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -245,7 +245,7 @@ type RuntimeConfig struct {
// EventsLogger determines where events should be logged
EventsLogger string `toml:"events_logger"`
// EventsLogFilePath is where the events log is stored.
- EventsLogFilePath string `toml:-"events_logfile_path"`
+ EventsLogFilePath string `toml:"-events_logfile_path"`
//DetachKeys is the sequence of keys used to detach a container
DetachKeys string `toml:"detach_keys"`
}
@@ -643,7 +643,9 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options ..
}
if configPath != "" {
- os.MkdirAll(filepath.Dir(configPath), 0755)
+ if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {
+ return nil, err
+ }
file, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
if err != nil && !os.IsExist(err) {
return nil, errors.Wrapf(err, "cannot open file %s", configPath)
@@ -652,7 +654,9 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options ..
defer file.Close()
enc := toml.NewEncoder(file)
if err := enc.Encode(runtime.config); err != nil {
- os.Remove(configPath)
+ if removeErr := os.Remove(configPath); removeErr != nil {
+ logrus.Debugf("unable to remove %s: %q", configPath, err)
+ }
}
}
}
@@ -1158,6 +1162,13 @@ func (r *Runtime) GetConfig() (*RuntimeConfig, error) {
return config, nil
}
+// DeferredShutdown shuts down the runtime without exposing any
+// errors. This is only meant to be used when the runtime is being
+// shutdown within a defer statement; else use Shutdown
+func (r *Runtime) DeferredShutdown(force bool) {
+ _ = r.Shutdown(force)
+}
+
// Shutdown shuts down the runtime and associated containers and storage
// If force is true, containers and mounted storage will be shut down before
// cleaning up; if force is false, an error will be returned if there are
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 9daac161c..760a07daf 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -52,7 +52,7 @@ func (r *Runtime) RestoreContainer(ctx context.Context, rSpec *spec.Spec, config
if err != nil {
return nil, errors.Wrapf(err, "error initializing container variables")
}
- return r.setupContainer(ctx, ctr, true)
+ return r.setupContainer(ctx, ctr)
}
func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConfig) (c *Container, err error) {
@@ -68,6 +68,7 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf
ctr.config.ShmSize = DefaultShmSize
} else {
// This is a restore from an imported checkpoint
+ ctr.restoreFromCheckpoint = true
if err := JSONDeepCopy(config, ctr.config); err != nil {
return nil, errors.Wrapf(err, "error copying container config for restore")
}
@@ -119,10 +120,10 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
return nil, errors.Wrapf(err, "error running container create option")
}
}
- return r.setupContainer(ctx, ctr, false)
+ return r.setupContainer(ctx, ctr)
}
-func (r *Runtime) setupContainer(ctx context.Context, ctr *Container, restore bool) (c *Container, err error) {
+func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (c *Container, err error) {
// Allocate a lock for the container
lock, err := r.lockManager.AllocateLock()
if err != nil {
@@ -211,7 +212,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container, restore bo
return nil, errors.Wrapf(config2.ErrInvalidArg, "unsupported CGroup manager: %s - cannot validate cgroup parent", r.config.CgroupManager)
}
- if restore {
+ if ctr.restoreFromCheckpoint {
// Remove information about bind mount
// for new container from imported checkpoint
g := generate.Generator{Config: ctr.config.Spec}
@@ -236,7 +237,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container, restore bo
}
}()
- if rootless.IsRootless() && ctr.config.ConmonPidFile == "" {
+ if ctr.config.ConmonPidFile == "" {
ctr.config.ConmonPidFile = filepath.Join(ctr.state.RunDir, "conmon.pid")
}
@@ -430,12 +431,10 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
// 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("removing container from pod: %v", err)
- }
+ if cleanupErr == nil {
+ cleanupErr = err
+ } else {
+ logrus.Errorf("removing container from pod: %v", err)
}
}
} else {
diff --git a/libpod/runtime_migrate.go b/libpod/runtime_migrate.go
index ad45579d3..c363991e6 100644
--- a/libpod/runtime_migrate.go
+++ b/libpod/runtime_migrate.go
@@ -37,7 +37,9 @@ func stopPauseProcess() error {
if err := os.Remove(pausePidPath); err != nil {
return errors.Wrapf(err, "cannot delete pause pid file %s", pausePidPath)
}
- syscall.Kill(pausePid, syscall.SIGKILL)
+ if err := syscall.Kill(pausePid, syscall.SIGKILL); err != nil {
+ return err
+ }
}
return nil
}
diff --git a/libpod/stats.go b/libpod/stats.go
index eb5ed95c4..52af824bb 100644
--- a/libpod/stats.go
+++ b/libpod/stats.go
@@ -46,10 +46,6 @@ func (c *Container) GetContainerStats(previousStats *ContainerStats) (*Container
return stats, errors.Wrapf(err, "unable to obtain cgroup stats")
}
conState := c.state.State
- if err != nil {
- return stats, errors.Wrapf(err, "unable to determine container state")
- }
-
netStats, err := getContainerNetIO(c)
if err != nil {
return nil, err
diff --git a/libpod/util.go b/libpod/util.go
index b0c25074b..b60575264 100644
--- a/libpod/util.go
+++ b/libpod/util.go
@@ -9,8 +9,6 @@ import (
"strings"
"time"
- "github.com/containers/image/signature"
- "github.com/containers/image/types"
"github.com/containers/libpod/libpod/define"
"github.com/fsnotify/fsnotify"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -32,24 +30,6 @@ func FuncTimer(funcName string) {
fmt.Printf("%s executed in %d ms\n", funcName, elapsed)
}
-// CopyStringStringMap deep copies a map[string]string and returns the result
-func CopyStringStringMap(m map[string]string) map[string]string {
- n := map[string]string{}
- for k, v := range m {
- n[k] = v
- }
- return n
-}
-
-// GetPolicyContext creates a signature policy context for the given signature policy path
-func GetPolicyContext(path string) (*signature.PolicyContext, error) {
- policy, err := signature.DefaultPolicy(&types.SystemContext{SignaturePolicyPath: path})
- if err != nil {
- return nil, err
- }
- return signature.NewPolicyContext(policy)
-}
-
// RemoveScientificNotationFromFloat returns a float without any
// scientific notation if the number has any.
// golang does not handle conversion of float64s that have scientific
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 10720886b..1cf9d686a 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -95,8 +95,8 @@ func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopVa
}
pool.Add(shared.Job{
- c.ID(),
- func() error {
+ ID: c.ID(),
+ Fn: func() error {
err := c.StopWithTimeout(*timeout)
if err != nil {
if errors.Cause(err) == define.ErrCtrStopped {
@@ -134,8 +134,8 @@ func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillVa
c := c
pool.Add(shared.Job{
- c.ID(),
- func() error {
+ ID: c.ID(),
+ Fn: func() error {
return c.Kill(uint(signal))
},
})
@@ -163,8 +163,8 @@ func (r *LocalRuntime) InitContainers(ctx context.Context, cli *cliconfig.InitVa
ctr := c
pool.Add(shared.Job{
- ctr.ID(),
- func() error {
+ ID: ctr.ID(),
+ Fn: func() error {
err := ctr.Init(ctx)
if err != nil {
// If we're initializing all containers, ignore invalid state errors
@@ -1058,7 +1058,14 @@ func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (stri
if c.Name {
name = ctr.Name()
}
- return systemdgen.CreateSystemdUnitAsString(name, ctr.ID(), c.RestartPolicy, ctr.Config().StaticDir, timeout)
+
+ config := ctr.Config()
+ conmonPidFile := config.ConmonPidFile
+ if conmonPidFile == "" {
+ return "", errors.Errorf("conmon PID file path is empty, try to recreate the container with --conmon-pidfile flag")
+ }
+
+ return systemdgen.CreateSystemdUnitAsString(name, ctr.ID(), c.RestartPolicy, conmonPidFile, timeout)
}
// GetNamespaces returns namespace information about a container for PS
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 800ed7569..db3f23629 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -97,6 +97,14 @@ func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime,
}, nil
}
+// DeferredShutdown is a bogus wrapper for compaat with the libpod
+// runtime and should only be run when a defer is being used
+func (r RemoteRuntime) DeferredShutdown(force bool) {
+ if err := r.Shutdown(force); err != nil {
+ logrus.Error("unable to shutdown runtime")
+ }
+}
+
// Shutdown is a bogus wrapper for compat with the libpod runtime
func (r RemoteRuntime) Shutdown(force bool) error {
return nil
diff --git a/pkg/adapter/sigproxy_linux.go b/pkg/adapter/sigproxy_linux.go
index af968cb89..efa6afa7b 100644
--- a/pkg/adapter/sigproxy_linux.go
+++ b/pkg/adapter/sigproxy_linux.go
@@ -27,7 +27,9 @@ func ProxySignals(ctr *libpod.Container) {
if err := ctr.Kill(uint(s.(syscall.Signal))); err != nil {
logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err)
signal.StopCatch(sigBuffer)
- syscall.Kill(syscall.Getpid(), s.(syscall.Signal))
+ if err := syscall.Kill(syscall.Getpid(), s.(syscall.Signal)); err != nil {
+ logrus.Errorf("failed to kill pid %d", syscall.Getpid())
+ }
}
}
}()
diff --git a/pkg/adapter/terminal_linux.go b/pkg/adapter/terminal_linux.go
index 3c4c3bd38..be7dc0cb6 100644
--- a/pkg/adapter/terminal_linux.go
+++ b/pkg/adapter/terminal_linux.go
@@ -35,7 +35,9 @@ func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr,
}
logrus.SetFormatter(&RawTtyFormatter{})
- term.SetRawTerminal(os.Stdin.Fd())
+ if _, err := term.SetRawTerminal(os.Stdin.Fd()); err != nil {
+ return err
+ }
defer restoreTerminal(oldTermState)
}
diff --git a/pkg/cgroups/blkio.go b/pkg/cgroups/blkio.go
index ca9107d97..bacd4eb93 100644
--- a/pkg/cgroups/blkio.go
+++ b/pkg/cgroups/blkio.go
@@ -30,14 +30,14 @@ func (c *blkioHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error
// Create the cgroup
func (c *blkioHandler) Create(ctr *CgroupControl) (bool, error) {
if ctr.cgroup2 {
- return false, fmt.Errorf("io create not implemented for cgroup v2")
+ return false, nil
}
return ctr.createCgroupDirectory(Blkio)
}
// Destroy the cgroup
func (c *blkioHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(Blkio))
+ return rmDirRecursively(ctr.getCgroupv1Path(Blkio))
}
// Stat fills a metrics structure with usage stats for the controller
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index d6c19212b..081db772f 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -149,6 +149,51 @@ func (c *CgroupControl) getCgroupv1Path(name string) string {
return filepath.Join(cgroupRoot, name, c.path)
}
+// createCgroupv2Path creates the cgroupv2 path and enables all the available controllers
+func createCgroupv2Path(path string) (Err error) {
+ content, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers")
+ if err != nil {
+ return errors.Wrapf(err, "read /sys/fs/cgroup/cgroup.controllers")
+ }
+ if !filepath.HasPrefix(path, "/sys/fs/cgroup") {
+ return fmt.Errorf("invalid cgroup path %s", path)
+ }
+
+ res := ""
+ for i, c := range strings.Split(strings.TrimSpace(string(content)), " ") {
+ if i == 0 {
+ res = fmt.Sprintf("+%s", c)
+ } else {
+ res = res + fmt.Sprintf(" +%s", c)
+ }
+ }
+ resByte := []byte(res)
+
+ current := "/sys/fs"
+ elements := strings.Split(path, "/")
+ for i, e := range elements[3:] {
+ current = filepath.Join(current, e)
+ if i > 0 {
+ if err := os.Mkdir(current, 0755); err != nil {
+ if !os.IsExist(err) {
+ return errors.Wrapf(err, "mkdir %s", path)
+ }
+ } else {
+ // If the directory was created, be sure it is not left around on errors.
+ defer func() {
+ if Err != nil {
+ os.Remove(current)
+ }
+ }()
+ }
+ }
+ if err := ioutil.WriteFile(filepath.Join(current, "cgroup.subtree_control"), resByte, 0755); err != nil {
+ return errors.Wrapf(err, "write %s", filepath.Join(current, "cgroup.subtree_control"))
+ }
+ }
+ return nil
+}
+
// initialize initializes the specified hierarchy
func (c *CgroupControl) initialize() (err error) {
createdSoFar := map[string]controllerHandler{}
@@ -161,6 +206,11 @@ func (c *CgroupControl) initialize() (err error) {
}
}
}()
+ if c.cgroup2 {
+ if err := createCgroupv2Path(filepath.Join(cgroupRoot, c.path)); err != nil {
+ return errors.Wrapf(err, "error creating cgroup path %s", c.path)
+ }
+ }
for name, handler := range handlers {
created, err := handler.Create(c)
if err != nil {
@@ -278,6 +328,13 @@ func Load(path string) (*CgroupControl, error) {
systemd: false,
}
if !cgroup2 {
+ controllers, err := getAvailableControllers(handlers, false)
+ if err != nil {
+ return nil, err
+ }
+ control.additionalControllers = controllers
+ }
+ if !cgroup2 {
for name := range handlers {
p := control.getCgroupv1Path(name)
if _, err := os.Stat(p); err != nil {
@@ -305,11 +362,40 @@ func (c *CgroupControl) Delete() error {
return c.DeleteByPath(c.path)
}
+// rmDirRecursively delete recursively a cgroup directory.
+// It differs from os.RemoveAll as it doesn't attempt to unlink files.
+// On cgroupfs we are allowed only to rmdir empty directories.
+func rmDirRecursively(path string) error {
+ if err := os.Remove(path); err == nil || os.IsNotExist(err) {
+ return nil
+ }
+ entries, err := ioutil.ReadDir(path)
+ if err != nil {
+ return errors.Wrapf(err, "read %s", path)
+ }
+ for _, i := range entries {
+ if i.IsDir() {
+ if err := rmDirRecursively(filepath.Join(path, i.Name())); err != nil {
+ return err
+ }
+ }
+ }
+ if os.Remove(path); err != nil {
+ if !os.IsNotExist(err) {
+ return errors.Wrapf(err, "remove %s", path)
+ }
+ }
+ return nil
+}
+
// DeleteByPath deletes the specified cgroup path
func (c *CgroupControl) DeleteByPath(path string) error {
if c.systemd {
return systemdDestroy(path)
}
+ if c.cgroup2 {
+ return rmDirRecursively(filepath.Join(cgroupRoot, c.path))
+ }
var lastError error
for _, h := range handlers {
if err := h.Destroy(c); err != nil {
@@ -318,8 +404,11 @@ func (c *CgroupControl) DeleteByPath(path string) error {
}
for _, ctr := range c.additionalControllers {
+ if ctr.symlink {
+ continue
+ }
p := c.getCgroupv1Path(ctr.name)
- if err := os.Remove(p); err != nil {
+ if err := rmDirRecursively(p); err != nil {
lastError = errors.Wrapf(err, "remove %s", p)
}
}
@@ -341,7 +430,7 @@ func (c *CgroupControl) AddPid(pid int) error {
pidString := []byte(fmt.Sprintf("%d\n", pid))
if c.cgroup2 {
- p := filepath.Join(cgroupRoot, c.path, "tasks")
+ p := filepath.Join(cgroupRoot, c.path, "cgroup.procs")
if err := ioutil.WriteFile(p, pidString, 0644); err != nil {
return errors.Wrapf(err, "write %s", p)
}
diff --git a/pkg/cgroups/cpu.go b/pkg/cgroups/cpu.go
index 8640d490e..03677f1ef 100644
--- a/pkg/cgroups/cpu.go
+++ b/pkg/cgroups/cpu.go
@@ -61,14 +61,14 @@ func (c *cpuHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error {
// Create the cgroup
func (c *cpuHandler) Create(ctr *CgroupControl) (bool, error) {
if ctr.cgroup2 {
- return false, fmt.Errorf("cpu create not implemented for cgroup v2")
+ return false, nil
}
return ctr.createCgroupDirectory(CPU)
}
// Destroy the cgroup
func (c *cpuHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(CPU))
+ return rmDirRecursively(ctr.getCgroupv1Path(CPU))
}
// Stat fills a metrics structure with usage stats for the controller
@@ -98,15 +98,24 @@ func (c *cpuHandler) Stat(ctr *CgroupControl, m *Metrics) error {
} else {
usage.Total, err = readAcct(ctr, "cpuacct.usage")
if err != nil {
- return err
+ if !os.IsNotExist(errors.Cause(err)) {
+ return err
+ }
+ usage.Total = 0
}
usage.Kernel, err = readAcct(ctr, "cpuacct.usage_sys")
if err != nil {
- return err
+ if !os.IsNotExist(errors.Cause(err)) {
+ return err
+ }
+ usage.Kernel = 0
}
usage.PerCPU, err = readAcctList(ctr, "cpuacct.usage_percpu")
if err != nil {
- return err
+ if !os.IsNotExist(errors.Cause(err)) {
+ return err
+ }
+ usage.PerCPU = nil
}
}
m.CPU = CPUMetrics{Usage: usage}
diff --git a/pkg/cgroups/cpuset.go b/pkg/cgroups/cpuset.go
index 9aef493c9..46d0484f2 100644
--- a/pkg/cgroups/cpuset.go
+++ b/pkg/cgroups/cpuset.go
@@ -3,7 +3,6 @@ package cgroups
import (
"fmt"
"io/ioutil"
- "os"
"path/filepath"
"strings"
@@ -14,19 +13,23 @@ import (
type cpusetHandler struct {
}
-func cpusetCopyFileFromParent(dir, file string) ([]byte, error) {
+func cpusetCopyFileFromParent(dir, file string, cgroupv2 bool) ([]byte, error) {
if dir == cgroupRoot {
return nil, fmt.Errorf("could not find parent to initialize cpuset %s", file)
}
path := filepath.Join(dir, file)
- data, err := ioutil.ReadFile(path)
+ parentPath := path
+ if cgroupv2 {
+ parentPath = fmt.Sprintf("%s.effective", parentPath)
+ }
+ data, err := ioutil.ReadFile(parentPath)
if err != nil {
return nil, errors.Wrapf(err, "open %s", path)
}
if len(strings.Trim(string(data), "\n")) != 0 {
return data, nil
}
- data, err = cpusetCopyFileFromParent(filepath.Dir(dir), file)
+ data, err = cpusetCopyFileFromParent(filepath.Dir(dir), file, cgroupv2)
if err != nil {
return nil, err
}
@@ -36,9 +39,9 @@ func cpusetCopyFileFromParent(dir, file string) ([]byte, error) {
return data, nil
}
-func cpusetCopyFromParent(path string) error {
+func cpusetCopyFromParent(path string, cgroupv2 bool) error {
for _, file := range []string{"cpuset.cpus", "cpuset.mems"} {
- if _, err := cpusetCopyFileFromParent(path, file); err != nil {
+ if _, err := cpusetCopyFileFromParent(path, file, cgroupv2); err != nil {
return err
}
}
@@ -60,19 +63,20 @@ func (c *cpusetHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) erro
// Create the cgroup
func (c *cpusetHandler) Create(ctr *CgroupControl) (bool, error) {
if ctr.cgroup2 {
- return false, fmt.Errorf("cpuset create not implemented for cgroup v2")
+ path := filepath.Join(cgroupRoot, ctr.path)
+ return true, cpusetCopyFromParent(path, true)
}
created, err := ctr.createCgroupDirectory(CPUset)
if !created || err != nil {
return created, err
}
- return true, cpusetCopyFromParent(ctr.getCgroupv1Path(CPUset))
+ return true, cpusetCopyFromParent(ctr.getCgroupv1Path(CPUset), false)
}
// Destroy the cgroup
func (c *cpusetHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(CPUset))
+ return rmDirRecursively(ctr.getCgroupv1Path(CPUset))
}
// Stat fills a metrics structure with usage stats for the controller
diff --git a/pkg/cgroups/memory.go b/pkg/cgroups/memory.go
index 0505eac40..b3991f7e3 100644
--- a/pkg/cgroups/memory.go
+++ b/pkg/cgroups/memory.go
@@ -2,7 +2,6 @@ package cgroups
import (
"fmt"
- "os"
"path/filepath"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -26,14 +25,14 @@ func (c *memHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error {
// Create the cgroup
func (c *memHandler) Create(ctr *CgroupControl) (bool, error) {
if ctr.cgroup2 {
- return false, fmt.Errorf("memory create not implemented for cgroup v2")
+ return false, nil
}
return ctr.createCgroupDirectory(Memory)
}
// Destroy the cgroup
func (c *memHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(Memory))
+ return rmDirRecursively(ctr.getCgroupv1Path(Memory))
}
// Stat fills a metrics structure with usage stats for the controller
diff --git a/pkg/cgroups/pids.go b/pkg/cgroups/pids.go
index c90dc1c02..65b9b5b34 100644
--- a/pkg/cgroups/pids.go
+++ b/pkg/cgroups/pids.go
@@ -3,7 +3,6 @@ package cgroups
import (
"fmt"
"io/ioutil"
- "os"
"path/filepath"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -35,15 +34,12 @@ func (c *pidHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error {
// Create the cgroup
func (c *pidHandler) Create(ctr *CgroupControl) (bool, error) {
- if ctr.cgroup2 {
- return false, fmt.Errorf("pid create not implemented for cgroup v2")
- }
return ctr.createCgroupDirectory(Pids)
}
// Destroy the cgroup
func (c *pidHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(Pids))
+ return rmDirRecursively(ctr.getCgroupv1Path(Pids))
}
// Stat fills a metrics structure with usage stats for the controller
diff --git a/pkg/channelwriter/channelwriter.go b/pkg/channelwriter/channelwriter.go
new file mode 100644
index 000000000..d51400eb3
--- /dev/null
+++ b/pkg/channelwriter/channelwriter.go
@@ -0,0 +1,34 @@
+package channelwriter
+
+import "github.com/pkg/errors"
+
+// Writer is an io.writer-like object that "writes" to a channel
+// instead of a buffer or file, etc. It is handy for varlink endpoints when
+// needing to handle endpoints that do logging "real-time"
+type Writer struct {
+ ByteChannel chan []byte
+}
+
+// NewChannelWriter creates a new channel writer and adds a
+// byte slice channel into it.
+func NewChannelWriter() *Writer {
+ byteChannel := make(chan []byte)
+ return &Writer{
+ ByteChannel: byteChannel,
+ }
+}
+
+// Write method for Writer
+func (c *Writer) Write(w []byte) (int, error) {
+ if c.ByteChannel == nil {
+ return 0, errors.New("channel writer channel cannot be nil")
+ }
+ c.ByteChannel <- w
+ return len(w), nil
+}
+
+// Close method for Writer
+func (c *Writer) Close() error {
+ close(c.ByteChannel)
+ return nil
+}
diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go
new file mode 100644
index 000000000..970d47636
--- /dev/null
+++ b/pkg/errorhandling/errorhandling.go
@@ -0,0 +1,23 @@
+package errorhandling
+
+import (
+ "os"
+
+ "github.com/sirupsen/logrus"
+)
+
+// SyncQuiet syncs a file and logs any error. Should only be used within
+// a defer.
+func SyncQuiet(f *os.File) {
+ if err := f.Sync(); err != nil {
+ logrus.Errorf("unable to sync file %s: %q", f.Name(), err)
+ }
+}
+
+// CloseQuiet closes a file and logs any error. Should only be used within
+// a defer.
+func CloseQuiet(f *os.File) {
+ if err := f.Close(); err != nil {
+ logrus.Errorf("unable to close file %s: %q", f.Name(), err)
+ }
+}
diff --git a/pkg/firewall/firewalld.go b/pkg/firewall/firewalld.go
index 32c2337a0..15e845cb7 100644
--- a/pkg/firewall/firewalld.go
+++ b/pkg/firewall/firewalld.go
@@ -18,6 +18,7 @@ package firewall
import (
"fmt"
+ "github.com/sirupsen/logrus"
"strings"
"github.com/godbus/dbus"
@@ -113,7 +114,9 @@ func (fb *fwdBackend) Del(conf *FirewallNetConf) error {
// Remove firewalld rules which assigned the given source IP to the given zone
firewalldObj := fb.conn.Object(firewalldName, firewalldPath)
var res string
- firewalldObj.Call(firewalldZoneInterface+"."+firewalldRemoveSourceMethod, 0, getFirewalldZone(conf), ipStr).Store(&res)
+ if err := firewalldObj.Call(firewalldZoneInterface+"."+firewalldRemoveSourceMethod, 0, getFirewalldZone(conf), ipStr).Store(&res); err != nil {
+ logrus.Errorf("unable to store firewallobj")
+ }
}
return nil
}
diff --git a/pkg/firewall/iptables.go b/pkg/firewall/iptables.go
index 59d81b287..92d249f7b 100644
--- a/pkg/firewall/iptables.go
+++ b/pkg/firewall/iptables.go
@@ -21,6 +21,7 @@ package firewall
import (
"fmt"
+ "github.com/sirupsen/logrus"
"net"
"github.com/coreos/go-iptables/iptables"
@@ -53,7 +54,9 @@ func generateFilterRule(privChainName string) []string {
func cleanupRules(ipt *iptables.IPTables, privChainName string, rules [][]string) {
for _, rule := range rules {
- ipt.Delete("filter", privChainName, rule...)
+ if err := ipt.Delete("filter", privChainName, rule...); err != nil {
+ logrus.Errorf("failed to delete iptables rule %s", privChainName)
+ }
}
}
@@ -185,7 +188,9 @@ func (ib *iptablesBackend) Add(conf *FirewallNetConf) error {
func (ib *iptablesBackend) Del(conf *FirewallNetConf) error {
for proto, ipt := range ib.protos {
- ib.delRules(conf, ipt, proto)
+ if err := ib.delRules(conf, ipt, proto); err != nil {
+ logrus.Errorf("failed to delete iptables backend rule %s", conf.IptablesAdminChainName)
+ }
}
return nil
}
diff --git a/pkg/hooks/exec/exec.go b/pkg/hooks/exec/exec.go
index 0dd091561..4038e3d94 100644
--- a/pkg/hooks/exec/exec.go
+++ b/pkg/hooks/exec/exec.go
@@ -5,6 +5,7 @@ import (
"bytes"
"context"
"fmt"
+ "github.com/sirupsen/logrus"
"io"
osexec "os/exec"
"time"
@@ -54,7 +55,9 @@ func Run(ctx context.Context, hook *rspec.Hook, state []byte, stdout io.Writer,
case err = <-exit:
return err, err
case <-ctx.Done():
- cmd.Process.Kill()
+ if err := cmd.Process.Kill(); err != nil {
+ logrus.Errorf("failed to kill pid %v", cmd.Process)
+ }
timer := time.NewTimer(postKillTimeout)
defer timer.Stop()
select {
diff --git a/pkg/logs/logs.go b/pkg/logs/logs.go
index 0f684750e..89e4e5686 100644
--- a/pkg/logs/logs.go
+++ b/pkg/logs/logs.go
@@ -30,6 +30,7 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/errorhandling"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -153,7 +154,7 @@ func ReadLogs(logPath string, ctr *libpod.Container, opts *LogOptions) error {
if err != nil {
return errors.Wrapf(err, "failed to open log file %q", logPath)
}
- defer file.Close()
+ defer errorhandling.CloseQuiet(file)
msg := &logMessage{}
opts.bytes = -1
@@ -161,9 +162,9 @@ func ReadLogs(logPath string, ctr *libpod.Container, opts *LogOptions) error {
reader := bufio.NewReader(file)
if opts.Follow {
- followLog(reader, writer, opts, ctr, msg, logPath)
+ err = followLog(reader, writer, opts, ctr, msg, logPath)
} else {
- dumpLog(reader, writer, opts, msg, logPath)
+ err = dumpLog(reader, writer, opts, msg, logPath)
}
return err
}
diff --git a/pkg/netns/netns_linux.go b/pkg/netns/netns_linux.go
index a72a2d098..4a515c72a 100644
--- a/pkg/netns/netns_linux.go
+++ b/pkg/netns/netns_linux.go
@@ -83,7 +83,9 @@ func NewNS() (ns.NetNS, error) {
if err != nil {
return nil, err
}
- mountPointFd.Close()
+ if err := mountPointFd.Close(); err != nil {
+ return nil, err
+ }
// Ensure the mount point is cleaned up on errors; if the namespace
// was successfully mounted this will have no effect because the file
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 8028a359c..d7c2de81d 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -17,6 +17,7 @@ import (
"syscall"
"unsafe"
+ "github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/storage/pkg/idtools"
"github.com/docker/docker/pkg/signal"
"github.com/godbus/dbus"
@@ -41,8 +42,7 @@ const (
)
func runInUser() error {
- os.Setenv("_CONTAINERS_USERNS_CONFIGURED", "done")
- return nil
+ return os.Setenv("_CONTAINERS_USERNS_CONFIGURED", "done")
}
var (
@@ -57,9 +57,15 @@ func IsRootless() bool {
rootlessGIDInit := int(C.rootless_gid())
if rootlessUIDInit != 0 {
// This happens if we joined the user+mount namespace as part of
- os.Setenv("_CONTAINERS_USERNS_CONFIGURED", "done")
- os.Setenv("_CONTAINERS_ROOTLESS_UID", fmt.Sprintf("%d", rootlessUIDInit))
- os.Setenv("_CONTAINERS_ROOTLESS_GID", fmt.Sprintf("%d", rootlessGIDInit))
+ if err := os.Setenv("_CONTAINERS_USERNS_CONFIGURED", "done"); err != nil {
+ logrus.Errorf("failed to set environment variable %s as %s", "_CONTAINERS_USERNS_CONFIGURED", "done")
+ }
+ if err := os.Setenv("_CONTAINERS_ROOTLESS_UID", fmt.Sprintf("%d", rootlessUIDInit)); err != nil {
+ logrus.Errorf("failed to set environment variable %s as %d", "_CONTAINERS_ROOTLESS_UID", rootlessUIDInit)
+ }
+ if err := os.Setenv("_CONTAINERS_ROOTLESS_GID", fmt.Sprintf("%d", rootlessGIDInit)); err != nil {
+ logrus.Errorf("failed to set environment variable %s as %d", "_CONTAINERS_ROOTLESS_GID", rootlessGIDInit)
+ }
}
isRootless = os.Geteuid() != 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != ""
})
@@ -185,18 +191,24 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) {
}
if ns == currentNS {
- syscall.Close(int(nextFd))
+ if err := syscall.Close(int(nextFd)); err != nil {
+ return nil, err
+ }
// Drop O_CLOEXEC for the fd.
_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_SETFD, 0)
if errno != 0 {
- syscall.Close(int(fd))
+ if err := syscall.Close(int(fd)); err != nil {
+ logrus.Errorf("failed to close file descriptor %d", fd)
+ }
return nil, errno
}
return os.NewFile(fd, "userns child"), nil
}
- syscall.Close(int(fd))
+ if err := syscall.Close(int(fd)); err != nil {
+ return nil, err
+ }
fd = nextFd
}
}
@@ -252,7 +264,9 @@ func EnableLinger() (string, error) {
if lingerEnabled && lingerFile != "" {
f, err := os.Create(lingerFile)
if err == nil {
- f.Close()
+ if err := f.Close(); err != nil {
+ logrus.Errorf("failed to close %s", f.Name())
+ }
} else {
logrus.Debugf("could not create linger file: %v", err)
}
@@ -348,8 +362,8 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
}
r, w := os.NewFile(uintptr(fds[0]), "sync host"), os.NewFile(uintptr(fds[1]), "sync child")
- defer r.Close()
- defer w.Close()
+ defer errorhandling.CloseQuiet(r)
+ defer errorhandling.CloseQuiet(w)
defer w.Write([]byte("0"))
pidC := C.reexec_in_user_namespace(C.int(r.Fd()), cPausePid, cFileToRead, fileOutputFD)
@@ -361,9 +375,9 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
var uids, gids []idtools.IDMap
username := os.Getenv("USER")
if username == "" {
- user, err := user.LookupId(fmt.Sprintf("%d", os.Getuid()))
+ userID, err := user.LookupId(fmt.Sprintf("%d", os.Getuid()))
if err == nil {
- username = user.Username
+ username = userID.Username
}
}
mappings, err := idtools.NewIDMappings(username, username)
@@ -458,7 +472,9 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
continue
}
- syscall.Kill(int(pidC), s.(syscall.Signal))
+ if err := syscall.Kill(int(pidC), s.(syscall.Signal)); err != nil {
+ logrus.Errorf("failed to kill %d", int(pidC))
+ }
}
}()
@@ -519,17 +535,19 @@ func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []st
r, w := os.NewFile(uintptr(fds[0]), "read file"), os.NewFile(uintptr(fds[1]), "write file")
- defer w.Close()
- defer r.Close()
+ defer errorhandling.CloseQuiet(w)
+ defer errorhandling.CloseQuiet(r)
if _, _, err := becomeRootInUserNS("", path, w); err != nil {
lastErr = err
continue
}
- w.Close()
+ if err := w.Close(); err != nil {
+ return false, 0, err
+ }
defer func() {
- r.Close()
+ errorhandling.CloseQuiet(r)
C.reexec_in_user_namespace_wait(-1, 0)
}()
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index c9548f0d3..d44beb3e4 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -481,7 +481,9 @@ func addPidNS(config *CreateConfig, g *generate.Generator) error {
func addUserNS(config *CreateConfig, g *generate.Generator) error {
if IsNS(string(config.UsernsMode)) {
- g.AddOrReplaceLinuxNamespace(spec.UserNamespace, NS(string(config.UsernsMode)))
+ if err := g.AddOrReplaceLinuxNamespace(spec.UserNamespace, NS(string(config.UsernsMode))); err != nil {
+ return err
+ }
// runc complains if no mapping is specified, even if we join another ns. So provide a dummy mapping
g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1))
@@ -489,7 +491,9 @@ func addUserNS(config *CreateConfig, g *generate.Generator) error {
}
if (len(config.IDMappings.UIDMap) > 0 || len(config.IDMappings.GIDMap) > 0) && !config.UsernsMode.IsHost() {
- g.AddOrReplaceLinuxNamespace(spec.UserNamespace, "")
+ if err := g.AddOrReplaceLinuxNamespace(spec.UserNamespace, ""); err != nil {
+ return err
+ }
}
return nil
}
diff --git a/pkg/systemdgen/systemdgen.go b/pkg/systemdgen/systemdgen.go
index 3d1c31b5d..06c5ebde5 100644
--- a/pkg/systemdgen/systemdgen.go
+++ b/pkg/systemdgen/systemdgen.go
@@ -2,17 +2,18 @@ package systemdgen
import (
"fmt"
- "path/filepath"
+ "os"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
var template = `[Unit]
Description=%s Podman Container
[Service]
Restart=%s
-ExecStart=/usr/bin/podman start %s
-ExecStop=/usr/bin/podman stop -t %d %s
+ExecStart=%s start %s
+ExecStop=%s stop -t %d %s
KillMode=none
Type=forking
PIDFile=%s
@@ -33,11 +34,26 @@ func ValidateRestartPolicy(restart string) error {
// CreateSystemdUnitAsString takes variables to create a systemd unit file used to control
// a libpod container
-func CreateSystemdUnitAsString(name, cid, restart, pidPath string, stopTimeout int) (string, error) {
+func CreateSystemdUnitAsString(name, cid, restart, pidFile string, stopTimeout int) (string, error) {
+ podmanExe := getPodmanExecutable()
+ return createSystemdUnitAsString(podmanExe, name, cid, restart, pidFile, stopTimeout)
+}
+
+func createSystemdUnitAsString(exe, name, cid, restart, pidFile string, stopTimeout int) (string, error) {
if err := ValidateRestartPolicy(restart); err != nil {
return "", err
}
- pidFile := filepath.Join(pidPath, fmt.Sprintf("%s.pid", cid))
- unit := fmt.Sprintf(template, name, restart, name, stopTimeout, name, pidFile)
+
+ unit := fmt.Sprintf(template, name, restart, exe, name, exe, stopTimeout, name, pidFile)
return unit, nil
}
+
+func getPodmanExecutable() string {
+ podmanExe, err := os.Executable()
+ if err != nil {
+ podmanExe = "/usr/bin/podman"
+ logrus.Warnf("Could not obtain podman executable location, using default %s", podmanExe)
+ }
+
+ return podmanExe
+}
diff --git a/pkg/systemdgen/systemdgen_test.go b/pkg/systemdgen/systemdgen_test.go
index f2f49e750..e413b24ce 100644
--- a/pkg/systemdgen/systemdgen_test.go
+++ b/pkg/systemdgen/systemdgen_test.go
@@ -41,7 +41,7 @@ ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4
ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
KillMode=none
Type=forking
-PIDFile=/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid
+PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
[Install]
WantedBy=multi-user.target`
@@ -53,15 +53,16 @@ ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
KillMode=none
Type=forking
-PIDFile=/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid
+PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
[Install]
WantedBy=multi-user.target`
type args struct {
+ exe string
name string
cid string
restart string
- pidPath string
+ pidFile string
stopTimeout int
}
tests := []struct {
@@ -73,10 +74,11 @@ WantedBy=multi-user.target`
{"good with id",
args{
+ "/usr/bin/podman",
"639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
"639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
"always",
- "/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/",
+ "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
10,
},
goodID,
@@ -84,10 +86,11 @@ WantedBy=multi-user.target`
},
{"good with name",
args{
+ "/usr/bin/podman",
"foobar",
"639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
"always",
- "/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/",
+ "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
10,
},
goodName,
@@ -95,10 +98,11 @@ WantedBy=multi-user.target`
},
{"bad restart policy",
args{
+ "/usr/bin/podman",
"639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
"639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
"never",
- "/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/",
+ "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
10,
},
"",
@@ -107,7 +111,7 @@ WantedBy=multi-user.target`
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- got, err := CreateSystemdUnitAsString(tt.args.name, tt.args.cid, tt.args.restart, tt.args.pidPath, tt.args.stopTimeout)
+ got, err := createSystemdUnitAsString(tt.args.exe, tt.args.name, tt.args.cid, tt.args.restart, tt.args.pidFile, tt.args.stopTimeout)
if (err != nil) != tt.wantErr {
t.Errorf("CreateSystemdUnitAsString() error = %v, wantErr %v", err, tt.wantErr)
return
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 9e49f08a0..fba34a337 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -12,12 +12,14 @@ import (
"github.com/BurntSushi/toml"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/spf13/pflag"
"golang.org/x/crypto/ssh/terminal"
)
@@ -272,16 +274,20 @@ func getTomlStorage(storeOptions *storage.StoreOptions) *tomlConfig {
// WriteStorageConfigFile writes the configuration to a file
func WriteStorageConfigFile(storageOpts *storage.StoreOptions, storageConf string) error {
- os.MkdirAll(filepath.Dir(storageConf), 0755)
- file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
+ if err := os.MkdirAll(filepath.Dir(storageConf), 0755); err != nil {
+ return err
+ }
+ storageFile, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
if err != nil {
return errors.Wrapf(err, "cannot open %s", storageConf)
}
tomlConfiguration := getTomlStorage(storageOpts)
- defer file.Close()
- enc := toml.NewEncoder(file)
+ defer errorhandling.CloseQuiet(storageFile)
+ enc := toml.NewEncoder(storageFile)
if err := enc.Encode(tomlConfiguration); err != nil {
- os.Remove(storageConf)
+ if err := os.Remove(storageConf); err != nil {
+ logrus.Errorf("unable to remove file %s", storageConf)
+ }
return err
}
return nil
diff --git a/pkg/util/utils_supported.go b/pkg/util/utils_supported.go
index 99c9e4f1e..af55689a6 100644
--- a/pkg/util/utils_supported.go
+++ b/pkg/util/utils_supported.go
@@ -13,6 +13,7 @@ import (
"github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// GetRootlessRuntimeDir returns the runtime directory when running as non root
@@ -24,7 +25,9 @@ func GetRootlessRuntimeDir() (string, error) {
uid := fmt.Sprintf("%d", rootless.GetRootlessUID())
if runtimeDir == "" {
tmpDir := filepath.Join("/run", "user", uid)
- os.MkdirAll(tmpDir, 0700)
+ if err := os.MkdirAll(tmpDir, 0700); err != nil {
+ logrus.Errorf("unable to make temp dir %s", tmpDir)
+ }
st, err := os.Stat(tmpDir)
if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 {
runtimeDir = tmpDir
@@ -32,7 +35,9 @@ func GetRootlessRuntimeDir() (string, error) {
}
if runtimeDir == "" {
tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("run-%s", uid))
- os.MkdirAll(tmpDir, 0700)
+ if err := os.MkdirAll(tmpDir, 0700); err != nil {
+ logrus.Errorf("unable to make temp dir %s", tmpDir)
+ }
st, err := os.Stat(tmpDir)
if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 {
runtimeDir = tmpDir
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 0e2ad6bbf..2bebfd406 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -25,6 +25,7 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/channelwriter"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
"github.com/containers/storage/pkg/archive"
@@ -495,9 +496,19 @@ func (i *LibpodAPI) DeleteUnusedImages(call iopodman.VarlinkCall) error {
// Commit ...
func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, changes []string, author, message string, pause bool, manifestType string) error {
- var newImage *image.Image
+ var (
+ newImage *image.Image
+ log []string
+ mimeType string
+ )
+ output := channelwriter.NewChannelWriter()
+ channelClose := func() {
+ if err := output.Close(); err != nil {
+ logrus.Errorf("failed to close channel writer: %q", err)
+ }
+ }
+ defer channelClose()
- output := bytes.NewBuffer([]byte{})
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
return call.ReplyContainerNotFound(name, err.Error())
@@ -507,7 +518,6 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
return call.ReplyErrorOccurred(err.Error())
}
sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false)
- var mimeType string
switch manifestType {
case "oci", "": //nolint
mimeType = buildah.OCIv1ImageManifest
@@ -535,6 +545,7 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
}
c := make(chan error)
+ defer close(c)
go func() {
newImage, err = ctr.Commit(getContext(), imageName, options)
@@ -542,48 +553,22 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
c <- err
}
c <- nil
- close(c)
}()
- var log []string
- done := false
- for {
- line, err := output.ReadString('\n')
- if err == nil {
- log = append(log, line)
- continue
- } else if err == io.EOF {
- select {
- case err := <-c:
- if err != nil {
- logrus.Errorf("reading of output during commit failed for %s", name)
- return call.ReplyErrorOccurred(err.Error())
- }
- done = true
- default:
- if !call.WantsMore() {
- break
- }
- br := iopodman.MoreResponse{
- Logs: log,
- }
- call.ReplyCommit(br)
- log = []string{}
- }
- } else {
- return call.ReplyErrorOccurred(err.Error())
- }
- if done {
- break
- }
+ // reply is the func being sent to the output forwarder. in this case it is replying
+ // with a more response struct
+ reply := func(br iopodman.MoreResponse) error {
+ return call.ReplyCommit(br)
+ }
+ log, err = forwardOutput(log, c, call.WantsMore(), output, reply)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
}
call.Continues = false
-
br := iopodman.MoreResponse{
Logs: log,
Id: newImage.ID(),
}
-
return call.ReplyCommit(br)
}
@@ -636,6 +621,7 @@ func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination str
func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
var (
imageID string
+ err error
)
dockerRegistryOptions := image.DockerRegistryOptions{}
so := image.SigningOptions{}
@@ -643,8 +629,16 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
if call.WantsMore() {
call.Continues = true
}
- output := bytes.NewBuffer([]byte{})
+ output := channelwriter.NewChannelWriter()
+ channelClose := func() {
+ if err := output.Close(); err != nil {
+ logrus.Errorf("failed to close channel writer: %q", err)
+ }
+ }
+ defer channelClose()
c := make(chan error)
+ defer close(c)
+
go func() {
if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") {
srcRef, err := alltransports.ParseImageName(name)
@@ -666,43 +660,17 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
}
}
c <- nil
- close(c)
}()
var log []string
- done := false
- for {
- line, err := output.ReadString('\n')
- if err == nil {
- log = append(log, line)
- continue
- } else if err == io.EOF {
- select {
- case err := <-c:
- if err != nil {
- logrus.Errorf("reading of output during pull failed for %s", name)
- return call.ReplyErrorOccurred(err.Error())
- }
- done = true
- default:
- if !call.WantsMore() {
- break
- }
- br := iopodman.MoreResponse{
- Logs: log,
- }
- call.ReplyPullImage(br)
- log = []string{}
- }
- } else {
- return call.ReplyErrorOccurred(err.Error())
- }
- if done {
- break
- }
+ reply := func(br iopodman.MoreResponse) error {
+ return call.ReplyPullImage(br)
+ }
+ log, err = forwardOutput(log, c, call.WantsMore(), output, reply)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
}
call.Continues = false
-
br := iopodman.MoreResponse{
Logs: log,
Id: imageID,
diff --git a/pkg/varlinkapi/util.go b/pkg/varlinkapi/util.go
index a74105795..e8f74e6aa 100644
--- a/pkg/varlinkapi/util.go
+++ b/pkg/varlinkapi/util.go
@@ -13,6 +13,7 @@ import (
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/channelwriter"
"github.com/containers/storage/pkg/archive"
)
@@ -196,3 +197,42 @@ func makePsOpts(inOpts iopodman.PsOpts) shared.PsOptions {
Sync: derefBool(inOpts.Sync),
}
}
+
+// forwardOutput is a helper method for varlink endpoints that employ both more and without
+// more. it is capable of sending updates as the output writer gets them or append them
+// all to a log. the chan error is the error from the libpod call so we can honor
+// and error event in that case.
+func forwardOutput(log []string, c chan error, wantsMore bool, output *channelwriter.Writer, reply func(br iopodman.MoreResponse) error) ([]string, error) {
+ done := false
+ for {
+ select {
+ // We need to check if the libpod func being called has returned an
+ // error yet
+ case err := <-c:
+ if err != nil {
+ return nil, err
+ }
+ done = true
+ // if no error is found, we pull what we can from the log writer and
+ // append it to log string slice
+ case line := <-output.ByteChannel:
+ log = append(log, string(line))
+ // If the end point is being used in more mode, send what we have
+ if wantsMore {
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ if err := reply(br); err != nil {
+ return nil, err
+ }
+ // "reset" the log to empty because we are sending what we
+ // get as we get it
+ log = []string{}
+ }
+ }
+ if done {
+ break
+ }
+ }
+ return log, nil
+}
diff --git a/rootless.md b/rootless.md
index d397ae857..bdbc1becc 100644
--- a/rootless.md
+++ b/rootless.md
@@ -16,9 +16,9 @@ can easily fail
* Cgroups V2 development for container support is ongoing.
* Can not share container images with CRI-O or other users
* Difficult to use additional stores for sharing content
-* Does not work on NFS homedirs
- * NFS enforces file creation on different UIDs on the server side and does not understand User Namespace.
- * When a container root process like YUM attempts to create a file owned by a different UID, NFS Server denies the creation.
+* Does not work on NFS or parallel filesystem homedirs (e.g. [GPFS](https://www.ibm.com/support/knowledgecenter/en/SSFKCN/gpfs_welcome.html))
+ * NFS and parallel filesystems enforce file creation on different UIDs on the server side and does not understand User Namespace.
+ * When a container root process like YUM attempts to create a file owned by a different UID, NFS Server/GPFS denies the creation.
* Does not work with homedirs mounted with noexec/nodev
* User can setup storage to point to other directories they can write to that are not mounted noexec/nodev
* Can not use overlayfs driver, but does support fuse-overlayfs
@@ -26,7 +26,7 @@ can easily fail
* Only other supported driver is VFS.
* No KATA Container support
* No CNI Support
- * CNI wants to modify IPTables, plus other network manipulation that I requires CAP_SYS_ADMIN.
+ * CNI wants to modify IPTables, plus other network manipulation that requires CAP_SYS_ADMIN.
* There is potential we could probably do some sort of blacklisting of the relevant plugins, and add a new plugin for rootless networking - slirp4netns as one example and there may be others
* Cannot use ping
* [(Can be fixed by setting sysctl on host)](https://github.com/containers/libpod/blob/master/troubleshooting.md#5-rootless-containers-cannot-ping-hosts)
diff --git a/test/README.md b/test/README.md
index 4e61a0774..9bea679dc 100644
--- a/test/README.md
+++ b/test/README.md
@@ -110,19 +110,30 @@ make shell
This will run a container and give you a shell and you can follow the instructions above.
-# System test
+# System tests
System tests are used for testing the *podman* CLI in the context of a complete system. It
requires that *podman*, all dependencies, and configurations are in place. The intention of
system testing is to match as closely as possible with real-world user/developer use-cases
and environments. The orchestration of the environments and tests is left to external
tooling.
-* `PodmanTestSystem`: System test *struct* as a composite of `PodmanTest`. It will not add any
-options to the command by default. When you run system test, you can set GLOBALOPTIONS,
-PODMAN_SUBCMD_OPTIONS or PODMAN_BINARY in ENV to run the test suite for different test matrices.
+System tests use Bash Automated Testing System (`bats`) as a testing framework.
+Install it via your package manager or get latest stable version
+[directly from the repository](https://github.com/bats-core/bats-core), e.g.:
-## Run system test
-You can run the test with following command:
+```
+mkdir -p ~/tools/bats
+git clone --single-branch --branch v1.1.0 https://github.com/bats-core/bats-core.git ~/tools/bats
+```
+
+Make sure that `bats` binary (`bin/bats` in the repository) is in your `PATH`, if not - add it:
+
+```
+PATH=$PATH:~/tools/bats/bin
+```
+
+## Running system tests
+When `bats` is installed and is in your `PATH`, you can run the test suite with following command:
```
make localsystem
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index d452a062b..65daf5e94 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -3,9 +3,12 @@
package integration
import (
+ "math/rand"
"net"
"os"
"os/exec"
+ "strconv"
+ "time"
"github.com/containers/libpod/pkg/criu"
. "github.com/containers/libpod/test/utils"
@@ -13,6 +16,16 @@ import (
. "github.com/onsi/gomega"
)
+func getRunString(input []string) []string {
+ // To avoid IP collisions of initialize random seed for random IP addresses
+ rand.Seed(time.Now().UnixNano())
+ ip3 := strconv.Itoa(rand.Intn(230) + GinkgoParallelNode())
+ ip4 := strconv.Itoa(rand.Intn(230) + GinkgoParallelNode())
+ // CRIU does not work with seccomp correctly on RHEL7 : seccomp=unconfined
+ runString := []string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", "--ip", "10.88." + ip3 + "." + ip4}
+ return append(runString, input...)
+}
+
var _ = Describe("Podman checkpoint", func() {
var (
tempdir string
@@ -49,7 +62,6 @@ var _ = Describe("Podman checkpoint", func() {
if hostInfo.Distribution == "fedora" && hostInfo.Version < "29" {
Skip("Checkpoint/Restore with SELinux only works on Fedora >= 29")
}
-
})
AfterEach(func() {
@@ -72,8 +84,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint a running container by id", func() {
- // CRIU does not work with seccomp correctly on RHEL7
- session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", ALPINE, "top"})
+ localRunString := getRunString([]string{ALPINE, "top"})
+ session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
cid := session.OutputToString()
@@ -94,7 +106,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint a running container by name", func() {
- session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "--name", "test_name", "-d", ALPINE, "top"})
+ localRunString := getRunString([]string{"--name", "test_name", ALPINE, "top"})
+ session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -114,7 +127,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman pause a checkpointed container by id", func() {
- session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", ALPINE, "top"})
+ localRunString := getRunString([]string{ALPINE, "top"})
+ session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
cid := session.OutputToString()
@@ -151,11 +165,13 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint latest running container", func() {
- session1 := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "--name", "first", "-d", ALPINE, "top"})
+ localRunString := getRunString([]string{"--name", "first", ALPINE, "top"})
+ session1 := podmanTest.Podman(localRunString)
session1.WaitWithDefaultTimeout()
Expect(session1.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "--name", "second", "-d", ALPINE, "top"})
+ localRunString = getRunString([]string{"--name", "second", ALPINE, "top"})
+ session2 := podmanTest.Podman(localRunString)
session2.WaitWithDefaultTimeout()
Expect(session2.ExitCode()).To(Equal(0))
@@ -186,11 +202,13 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint all running container", func() {
- session1 := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "--name", "first", "-d", ALPINE, "top"})
+ localRunString := getRunString([]string{"--name", "first", ALPINE, "top"})
+ session1 := podmanTest.Podman(localRunString)
session1.WaitWithDefaultTimeout()
Expect(session1.ExitCode()).To(Equal(0))
- session2 := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "--name", "second", "-d", ALPINE, "top"})
+ localRunString = getRunString([]string{"--name", "second", ALPINE, "top"})
+ session2 := podmanTest.Podman(localRunString)
session2.WaitWithDefaultTimeout()
Expect(session2.ExitCode()).To(Equal(0))
@@ -221,7 +239,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint container with established tcp connections", func() {
- session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", redis})
+ localRunString := getRunString([]string{redis})
+ session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -275,7 +294,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint with --leave-running", func() {
- session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", ALPINE, "top"})
+ localRunString := getRunString([]string{ALPINE, "top"})
+ session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
cid := session.OutputToString()
@@ -312,7 +332,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint and restore container with same IP", func() {
- session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "--name", "test_name", "-d", ALPINE, "top"})
+ localRunString := getRunString([]string{"--name", "test_name", ALPINE, "top"})
+ session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -355,8 +376,10 @@ var _ = Describe("Podman checkpoint", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ cid := session.OutputToString()
+ fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
- result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", "/tmp/checkpoint.tar.gz"})
+ result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
@@ -369,7 +392,7 @@ var _ = Describe("Podman checkpoint", func() {
Expect(result.ExitCode()).To(Equal(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
- result = podmanTest.Podman([]string{"container", "restore", "-i", "/tmp/checkpoint.tar.gz"})
+ result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
@@ -377,7 +400,7 @@ var _ = Describe("Podman checkpoint", func() {
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
// Restore container a second time with different name
- result = podmanTest.Podman([]string{"container", "restore", "-i", "/tmp/checkpoint.tar.gz", "-n", "restore_again"})
+ result = podmanTest.Podman([]string{"container", "restore", "-i", fileName, "-n", "restore_again"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
@@ -390,6 +413,47 @@ var _ = Describe("Podman checkpoint", func() {
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
// Remove exported checkpoint
- os.Remove("/tmp/checkpoint.tar.gz")
+ os.Remove(fileName)
+ })
+
+ It("podman checkpoint and run exec in restored container", func() {
+ // Start the container
+ localRunString := getRunString([]string{"--rm", ALPINE, "top"})
+ session := podmanTest.Podman(localRunString)
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ cid := session.OutputToString()
+ fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
+
+ // Checkpoint the container
+ result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
+ result.WaitWithDefaultTimeout()
+
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(0))
+
+ // Restore the container
+ result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
+ result.WaitWithDefaultTimeout()
+
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(1))
+ Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
+
+ // Exec in the container
+ result = podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "echo " + cid + " > /test.output"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+
+ result = podmanTest.Podman([]string{"exec", "-l", "cat", "/test.output"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(ContainSubstring(cid))
+
+ // Remove exported checkpoint
+ os.Remove(fileName)
})
})
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index c3a37236b..21afc4b84 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -530,6 +530,19 @@ func (p *PodmanTestIntegration) RunHealthCheck(cid string) error {
if hc.ExitCode() == 0 {
return nil
}
+ // Restart container if it's not running
+ ps := p.Podman([]string{"ps", "--no-trunc", "--q", "--filter", fmt.Sprintf("id=%s", cid)})
+ ps.WaitWithDefaultTimeout()
+ if ps.ExitCode() == 0 {
+ if !strings.Contains(ps.OutputToString(), cid) {
+ fmt.Printf("Container %s is not running, restarting", cid)
+ restart := p.Podman([]string{"restart", cid})
+ restart.WaitWithDefaultTimeout()
+ if restart.ExitCode() != 0 {
+ return errors.Errorf("unable to restart %s", cid)
+ }
+ }
+ }
fmt.Printf("Waiting for %s to pass healthcheck\n", cid)
time.Sleep(1 * time.Second)
}
diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go
index 0d3f47f30..f0689f152 100644
--- a/test/e2e/pod_rm_test.go
+++ b/test/e2e/pod_rm_test.go
@@ -3,6 +3,8 @@ package integration
import (
"fmt"
"os"
+ "path/filepath"
+ "strings"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
@@ -40,6 +42,21 @@ var _ = Describe("Podman pod rm", func() {
result := podmanTest.Podman([]string{"pod", "rm", podid})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
+
+ // Also check that we don't leak cgroups
+ err := filepath.Walk("/sys/fs/cgroup", func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if !info.IsDir() {
+ Expect(err).To(BeNil())
+ }
+ if strings.Contains(info.Name(), podid) {
+ return fmt.Errorf("leaking cgroup path %s", path)
+ }
+ return nil
+ })
+ Expect(err).To(BeNil())
})
It("podman pod rm latest pod", func() {
diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go
index de2416868..cf6279f2f 100644
--- a/test/e2e/push_test.go
+++ b/test/e2e/push_test.go
@@ -8,6 +8,7 @@ import (
"path/filepath"
"strings"
+ "github.com/containers/libpod/pkg/rootless"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -59,6 +60,9 @@ var _ = Describe("Podman push", func() {
if podmanTest.Host.Arch == "ppc64le" {
Skip("No registry image for ppc64le")
}
+ if rootless.IsRootless() {
+ podmanTest.RestoreArtifact(registry)
+ }
lock := GetPortLock("5000")
defer lock.Unlock()
session := podmanTest.PodmanNoCache([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go
index 1687bf764..1b0329a83 100644
--- a/test/e2e/rmi_test.go
+++ b/test/e2e/rmi_test.go
@@ -55,7 +55,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi all images", func() {
- podmanTest.PullImages([]string{nginx})
+ podmanTest.RestoreArtifact(nginx)
session := podmanTest.PodmanNoCache([]string{"rmi", "-a"})
session.WaitWithDefaultTimeout()
images := podmanTest.PodmanNoCache([]string{"images"})
@@ -66,7 +66,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi all images forcibly with short options", func() {
- podmanTest.PullImages([]string{nginx})
+ podmanTest.RestoreArtifact(nginx)
session := podmanTest.PodmanNoCache([]string{"rmi", "-fa"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/run_signal_test.go b/test/e2e/run_signal_test.go
index 3a5ed483c..1dbac1dc9 100644
--- a/test/e2e/run_signal_test.go
+++ b/test/e2e/run_signal_test.go
@@ -11,6 +11,7 @@ import (
"syscall"
"time"
+ "github.com/containers/libpod/pkg/rootless"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -53,7 +54,9 @@ var _ = Describe("Podman run with --sig-proxy", func() {
os.Mkdir(udsDir, 0700)
udsPath := filepath.Join(udsDir, "fifo")
syscall.Mkfifo(udsPath, 0600)
-
+ if rootless.IsRootless() {
+ podmanTest.RestoreArtifact(fedoraMinimal)
+ }
_, pid := podmanTest.PodmanPID([]string{"run", "-it", "-v", fmt.Sprintf("%s:/h:Z", udsDir), fedoraMinimal, "bash", "-c", sigCatch})
uds, _ := os.OpenFile(udsPath, os.O_RDONLY|syscall.O_NONBLOCK, 0600)
@@ -108,6 +111,9 @@ var _ = Describe("Podman run with --sig-proxy", func() {
Specify("signals are not forwarded to container with sig-proxy false", func() {
signal := syscall.SIGPOLL
+ if rootless.IsRootless() {
+ podmanTest.RestoreArtifact(fedoraMinimal)
+ }
session, pid := podmanTest.PodmanPID([]string{"run", "--name", "test2", "--sig-proxy=false", fedoraMinimal, "bash", "-c", sigCatch})
ok := WaitForContainer(podmanTest)
diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go
index 45511edb8..4000ab33a 100644
--- a/test/e2e/stats_test.go
+++ b/test/e2e/stats_test.go
@@ -65,7 +65,7 @@ var _ = Describe("Podman stats", func() {
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"stats", "--all", "--no-stream", "--format", "\"{{.Container}}\""})
+ session = podmanTest.Podman([]string{"stats", "--all", "--no-stream", "--format", "\"{{.ID}}\""})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
diff --git a/test/e2e/tree_test.go b/test/e2e/tree_test.go
index 2db7aeb5e..c445328fa 100644
--- a/test/e2e/tree_test.go
+++ b/test/e2e/tree_test.go
@@ -37,10 +37,6 @@ var _ = Describe("Podman image tree", func() {
if podmanTest.RemoteTest {
Skip("Does not work on remote client")
}
- session := podmanTest.PodmanNoCache([]string{"pull", "docker.io/library/busybox:latest"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
-
dockerfile := `FROM docker.io/library/busybox:latest
RUN mkdir hello
RUN touch test.txt
@@ -48,7 +44,7 @@ ENV foo=bar
`
podmanTest.BuildImage(dockerfile, "test:latest", "true")
- session = podmanTest.PodmanNoCache([]string{"image", "tree", "test:latest"})
+ session := podmanTest.PodmanNoCache([]string{"image", "tree", "test:latest"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.PodmanNoCache([]string{"image", "tree", "--whatrequires", "docker.io/library/busybox:latest"})
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
index 53acf6edd..c1e7c7ec4 100644
--- a/test/system/070-build.bats
+++ b/test/system/070-build.bats
@@ -20,15 +20,16 @@ load helpers
dockerfile=$tmpdir/Dockerfile
cat >$dockerfile <<EOF
FROM $IMAGE
+RUN apk add nginx
RUN echo $rand_content > /$rand_filename
EOF
run_podman build -t build_test --format=docker $tmpdir
+ is "$output" ".*STEP 4: COMMIT" "COMMIT seen in log"
run_podman run --rm build_test cat /$rand_filename
is "$output" "$rand_content" "reading generated file in image"
run_podman rmi build_test
}
-
# vim: filetype=sh
diff --git a/test/system/250-generate-systemd.bats b/test/system/250-generate-systemd.bats
new file mode 100644
index 000000000..80199af5f
--- /dev/null
+++ b/test/system/250-generate-systemd.bats
@@ -0,0 +1,46 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# Tests generated configurations for systemd.
+#
+
+load helpers
+
+# Be extra paranoid in naming to avoid collisions.
+SERVICE_NAME="podman_test_$(random_string)"
+UNIT_DIR="$HOME/.config/systemd/user"
+UNIT_FILE="$UNIT_DIR/$SERVICE_NAME.service"
+
+function setup() {
+ skip_if_not_systemd
+ skip_if_remote
+
+ basic_setup
+
+ if [ ! -d "$UNIT_DIR" ]; then
+ mkdir -p "$UNIT_DIR"
+ systemctl --user daemon-reload
+ fi
+}
+
+function teardown() {
+ rm -f "$UNIT_FILE"
+ systemctl --user stop "$SERVICE_NAME"
+ basic_teardown
+}
+
+@test "podman generate - systemd - basic" {
+ run_podman create $IMAGE echo "I'm alive!"
+ cid="$output"
+
+ run_podman generate systemd $cid > "$UNIT_FILE"
+
+ run systemctl --user start "$SERVICE_NAME"
+ if [ $status -ne 0 ]; then
+ die "The systemd service $SERVICE_NAME did not start correctly, output: $output"
+ fi
+
+ run_podman logs $cid
+ is "$output" "I'm alive!" "Container output"
+}
+
+# vim: filetype=sh
diff --git a/test/system/README.md b/test/system/README.md
index 6ac408f4e..d98b1c0fe 100644
--- a/test/system/README.md
+++ b/test/system/README.md
@@ -42,6 +42,15 @@ should be reserved for a first-pass fail-fast subset of tests:
without having to wait for the entire test suite.
+Running tests
+=============
+To run the tests locally in your sandbox, you can use one of these methods:
+* make;PODMAN=./bin/podman bats ./test/system/070-build.bats # runs just the specified test
+* make;PODMAN=./bin/podman bats ./test/system # runs all
+
+To test as root:
+* $ PODMAN=./bin/podman sudo --preserve-env=PODMAN bats test/system
+
Analyzing test failures
=======================
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
index 29ef19ecc..1db80f111 100644
--- a/test/system/helpers.bash
+++ b/test/system/helpers.bash
@@ -236,6 +236,17 @@ function skip_if_remote() {
skip "${1:-test does not work with podman-remote}"
}
+#########################
+# skip_if_not_systemd # ...with an optional message
+#########################
+function skip_if_not_systemd() {
+ if systemctl --user >/dev/null 2>&1; then
+ return
+ fi
+
+ skip "${1:-no systemd or daemon does not respond}"
+}
+
#########
# die # Abort with helpful message
#########
diff --git a/test/test_podman_baseline.sh b/test/test_podman_baseline.sh
index 92bc8e20c..d205f544a 100755
--- a/test/test_podman_baseline.sh
+++ b/test/test_podman_baseline.sh
@@ -536,6 +536,28 @@ EOF
fi
########
+# Build Dockerfile for RUN with priv'd command test
+########
+FILE=./Dockerfile
+/bin/cat <<EOM >$FILE
+FROM alpine
+RUN apk add nginx
+EOM
+chmod +x $FILE
+
+########
+# Build with the Dockerfile
+########
+podman build -f Dockerfile -t build-priv
+
+########
+# Cleanup
+########
+podman rm -a -f
+podman rmi -a -f
+rm ./Dockerfile
+
+########
# Build Dockerfile for WhaleSays test
########
FILE=./Dockerfile
diff --git a/utils/utils.go b/utils/utils.go
index 0ac6bc6d3..3c8c0a9b0 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -48,11 +48,6 @@ func ExecCmdWithStdStreams(stdin io.Reader, stdout, stderr io.Writer, env []stri
return nil
}
-// StatusToExitCode converts wait status code to an exit code
-func StatusToExitCode(status int) int {
- return ((status) & 0xff00) >> 8
-}
-
// ErrDetach is an error indicating that the user manually detached from the
// container.
var ErrDetach = errors.New("detached from container")
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 6a7c04267..ad2f69976 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -537,18 +537,18 @@ gopkg.in/yaml.v2
# k8s.io/api v0.0.0-20190624085159-95846d7ef82a
k8s.io/api/core/v1
# k8s.io/apimachinery v0.0.0-20190624085041-961b39a1baa0
-k8s.io/apimachinery/pkg/fields
-k8s.io/apimachinery/pkg/api/resource
k8s.io/apimachinery/pkg/apis/meta/v1
k8s.io/apimachinery/pkg/util/wait
k8s.io/apimachinery/pkg/util/runtime
-k8s.io/apimachinery/pkg/selection
+k8s.io/apimachinery/pkg/api/resource
k8s.io/apimachinery/pkg/runtime
k8s.io/apimachinery/pkg/runtime/schema
k8s.io/apimachinery/pkg/types
k8s.io/apimachinery/pkg/util/intstr
k8s.io/apimachinery/pkg/conversion
+k8s.io/apimachinery/pkg/fields
k8s.io/apimachinery/pkg/labels
+k8s.io/apimachinery/pkg/selection
k8s.io/apimachinery/pkg/watch
k8s.io/apimachinery/pkg/util/httpstream
k8s.io/apimachinery/pkg/util/remotecommand