diff options
83 files changed, 916 insertions, 308 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 968854771..9897a9f7f 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -637,6 +637,33 @@ rootless_system_test_task: main_script: *main always: *logs_artifacts +rootless_gitlab_test_task: + name: *std_name_fmt + alias: rootless_gitlab_test + skip: *tags + only_if: *not_docs + # Community-maintained downstream test may fail unexpectedly. + # Ref. repository: https://gitlab.com/gitlab-org/gitlab-runner + # If necessary, uncomment the next line and file issue(s) with details. + # allow_failures: $CI == $CI + depends_on: + - rootless_integration_test + gce_instance: *standardvm + env: + <<: *ubuntu_envvars + TEST_FLAVOR: 'gitlab' + PRIV_NAME: rootless + clone_script: *noop # Comes from cache + gopath_cache: *ro_gopath_cache + setup_script: *setup + main_script: *main + always: + <<: *logs_artifacts + junit_artifacts: + path: gitlab-runner-podman.xml + type: text/xml + format: junit + upgrade_test_task: name: "Upgrade test: from $PODMAN_UPGRADE_FROM" alias: upgrade_test @@ -720,6 +747,7 @@ success_task: - local_system_test - remote_system_test - rootless_system_test + - rootless_gitlab_test - upgrade_test - buildah_bud_test - meta diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 568cf7240..f5f0b21be 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,41 @@ <!-- Thanks for sending a pull request! -Please make sure you've read our contributing guidelines and how to submit a pull request (https://github.com/containers/podman/blob/master/CONTRIBUTING.md#submitting-pull-requests). +Please make sure you've read our contributing guidelines and how to submit a pull request (https://github.com/containers/podman/blob/main/CONTRIBUTING.md#submitting-pull-requests). In case you're only changing docs, make sure to prefix the pull-request title with "[CI:DOCS]". That will prevent functional tests from running and save time and energy. + +Finally, be sure to sign commits with your real name. Since by opening +a PR you already have commits, you can add signatures if needed with +something like `git commit -s --amend`. --> + +#### What this PR does / why we need it: + +<!--- +Please put your overall PR description here +--> + +#### How to verify it + +<!--- +Please specify the precise conditions and/or the specific test(s) which must pass. +--> + +#### Which issue(s) this PR fixes: + +<!-- +Please uncomment this block and include only one of the following on a +line by itself: + +None + +-OR- + +Fixes #<issue number> + +*** Please also put 'Fixes #' in the commit and PR description*** + +--> + +#### Special notes for your reviewer: @@ -412,9 +412,9 @@ completions: podman podman-remote declare -A outfiles=([bash]=%s [zsh]=_%s [fish]=%s.fish [powershell]=%s.ps1);\ for shell in $${!outfiles[*]}; do \ for remote in "" "-remote"; do \ - podman="podman$$remote"; \ - outfile=$$(printf "completions/$$shell/$${outfiles[$$shell]}" $$podman); \ - ./bin/$$podman completion $$shell >| $$outfile; \ + podman="podman$$remote"; \ + outfile=$$(printf "completions/$$shell/$${outfiles[$$shell]}" $$podman); \ + ./bin/$$podman completion $$shell >| $$outfile; \ done;\ done @@ -432,10 +432,10 @@ $(MANPAGES): %: %.md .install.md2man docdir ### this ensures that manpages are renderd correctly @sed -e 's/\((podman[^)]*\.md\(#.*\)\?)\)//g' \ - -e 's/\[\(podman[^]]*\)\]/\1/g' \ + -e 's/\[\(podman[^]]*\)\]/\1/g' \ -e 's/\[\([^]]*\)](http[^)]\+)/\1/g' \ - -e 's;<\(/\)\?\(a\|a\s\+[^>]*\|sup\)>;;g' \ - -e 's/\\$$/ /g' $< | \ + -e 's;<\(/\)\?\(a\|a\s\+[^>]*\|sup\)>;;g' \ + -e 's/\\$$/ /g' $< | \ $(GOMD2MAN) -in /dev/stdin -out $(subst source/markdown,build/man,$@) .PHONY: docdir @@ -672,7 +672,7 @@ podman-v$(RELEASE_NUMBER).msi: podman-remote-windows podman-remote-windows-docs --directory-ref INSTALLDIR --prefix $(DOCFILE)/ > \ $(DOCFILE)/pages.wsx wixl -D VERSION=$(call err_if_empty,RELEASE_VERSION) -D ManSourceDir=$(DOCFILE) \ - -o $@ contrib/msi/podman.wxs $(DOCFILE)/pages.wsx + -o $@ contrib/msi/podman.wxs $(DOCFILE)/pages.wsx --arch x64 .PHONY: package package: ## Build rpm packages @@ -759,6 +759,8 @@ install.docker: install.docker-docs-nobuild: install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(MANDIR)/man1 install ${SELINUXOPT} -m 644 docs/build/man/docker*.1 -t $(DESTDIR)$(MANDIR)/man1 + install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(MANDIR)/man5 + install ${SELINUXOPT} -m 644 docs/build/man/docker*.5 -t $(DESTDIR)$(MANDIR)/man5 .PHONY: install.docker-docs install.docker-docs: docker-docs install.docker-docs-nobuild @@ -809,7 +811,7 @@ install.tools: .install.goimports .install.gitvalidation .install.md2man .instal .PHONY: .install.golangci-lint .install.golangci-lint: .gopathok - VERSION=1.36.0 GOBIN=$(GOBIN) sh ./hack/install_golangci.sh + VERSION=1.36.0 GOBIN=$(GOBIN) ./hack/install_golangci.sh .PHONY: .install.bats .install.bats: .gopathok diff --git a/cmd/podman/generate/generate.go b/cmd/podman/generate/generate.go index 6b48a342e..a42aa9f21 100644 --- a/cmd/podman/generate/generate.go +++ b/cmd/podman/generate/generate.go @@ -11,7 +11,7 @@ var ( // Command: podman _generate_ generateCmd = &cobra.Command{ Use: "generate", - Short: "Generate structured data based on containers, pods or volumes.", + Short: "Generate structured data based on containers, pods or volumes", Long: "Generate structured data (e.g., Kubernetes YAML or systemd units) based on containers, pods or volumes.", RunE: validate.SubCommandExists, } diff --git a/cmd/podman/images/prune.go b/cmd/podman/images/prune.go index 7e6a29d94..6c39e5c69 100644 --- a/cmd/podman/images/prune.go +++ b/cmd/podman/images/prune.go @@ -41,6 +41,7 @@ func init() { flags := pruneCmd.Flags() flags.BoolVarP(&pruneOpts.All, "all", "a", false, "Remove all images not in use by containers, not just dangling ones") + flags.BoolVarP(&pruneOpts.External, "external", "", false, "Remove images even when they are used by external containers (e.g., by build containers)") flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation") filterFlagName := "filter" diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go index 19f31d1a6..adde887f7 100644 --- a/cmd/podman/machine/init.go +++ b/cmd/podman/machine/init.go @@ -42,7 +42,7 @@ func init() { cpusFlagName := "cpus" flags.Uint64Var( &initOpts.CPUS, - cpusFlagName, 1, + cpusFlagName, cfg.Machine.CPUs, "Number of CPUs", ) _ = initCmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone) @@ -50,7 +50,7 @@ func init() { diskSizeFlagName := "disk-size" flags.Uint64Var( &initOpts.DiskSize, - diskSizeFlagName, 10, + diskSizeFlagName, cfg.Machine.DiskSize, "Disk size in GB", ) @@ -59,7 +59,7 @@ func init() { memoryFlagName := "memory" flags.Uint64VarP( &initOpts.Memory, - memoryFlagName, "m", 2048, + memoryFlagName, "m", cfg.Machine.Memory, "Memory in MB", ) _ = initCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone) @@ -71,7 +71,7 @@ func init() { ) ImagePathFlagName := "image-path" - flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Engine.MachineImage, "Path to qcow image") + flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Machine.Image, "Path to qcow image") _ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault) IgnitionPathFlagName := "ignition-path" diff --git a/cmd/podman/play/play.go b/cmd/podman/play/play.go index f121d6a2d..d676bd701 100644 --- a/cmd/podman/play/play.go +++ b/cmd/podman/play/play.go @@ -10,7 +10,7 @@ var ( // Command: podman _play_ playCmd = &cobra.Command{ Use: "play", - Short: "Play containers, pods or volumes from a structured file.", + Short: "Play containers, pods or volumes from a structured file", Long: "Play structured data (e.g., Kubernetes YAML) based on containers, pods or volumes.", RunE: validate.SubCommandExists, } diff --git a/cmd/podman/root.go b/cmd/podman/root.go index 58cab0268..eb30f1ef6 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -92,6 +92,11 @@ func Execute() { if registry.GetExitCode() == 0 { registry.SetExitCode(define.ExecErrorCodeGeneric) } + if registry.IsRemote() { + if strings.Contains(err.Error(), "unable to connect to Podman") { + fmt.Fprintln(os.Stderr, "Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM") + } + } fmt.Fprintln(os.Stderr, formatError(err)) } os.Exit(registry.GetExitCode()) diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh index 128398c38..22a66dd08 100755 --- a/contrib/cirrus/runner.sh +++ b/contrib/cirrus/runner.sh @@ -286,6 +286,23 @@ function _run_release() { msg "All OK" } + +function _run_gitlab() { + rootless_uid=$(id -u) + systemctl enable --now --user podman.socket + export DOCKER_HOST=unix:///run/user/${rootless_uid}/podman/podman.sock + export CONTAINER_HOST=$DOCKER_HOST + cd $GOPATH/src/gitlab.com/gitlab-org/gitlab-runner + set +e + go test -v ./executors/docker |& tee $GOSRC/gitlab-runner-podman.log + ret=$? + set -e + # This file is collected and parsed by Cirrus-CI so must be in $GOSRC + cat $GOSRC/gitlab-runner-podman.log | \ + go-junit-report > $GOSRC/gitlab-runner-podman.xml + return $ret +} + logformatter() { if [[ "$CI" == "true" ]]; then # Use similar format as human-friendly task name from .cirrus.yml diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index 41b155943..ef1f83024 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -243,6 +243,44 @@ case "$TEST_FLAVOR" in install_test_configs ;; + gitlab) + # This only runs on Ubuntu for now + if [[ "$OS_RELEASE_ID" != "ubuntu" ]]; then + die "This test only runs on Ubuntu due to sheer laziness" + fi + + # Ref: https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27270#note_499585550 + + remove_packaged_podman_files + make install PREFIX=/usr ETCDIR=/etc + + # Need to re-build lists (removed during image production) + ooe.sh apt-get -qq -y update + msg "Installing previously downloaded/cached packages" + # N/B: Tests check/expect `docker info` output, and this `!= podman info` + ooe.sh apt-get install --yes --no-download --ignore-missing containerd.io docker-ce docker-ce-cli + + msg "Disabling docker service and socket activation" + systemctl stop docker.service docker.socket + systemctl disable docker.service docker.socket + rm -rf /run/docker* + # Guarantee the docker daemon can't be started, even by accident + rm -vf $(type -P dockerd) + + msg "Obtaining necessary gitlab-runner testing bits" + slug="gitlab.com/gitlab-org/gitlab-runner" + helper_fqin="registry.gitlab.com/gitlab-org/gitlab-runner/gitlab-runner-helper:x86_64-latest-pwsh" + ssh="ssh $ROOTLESS_USER@localhost -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o CheckHostIP=no env GOPATH=$GOPATH" + showrun $ssh go get -u github.com/jstemmer/go-junit-report + showrun $ssh git clone https://$slug $GOPATH/src/$slug + showrun $ssh make -C $GOPATH/src/$slug development_setup + showrun $ssh bash -c "'cd $GOPATH/src/$slug && GOPATH=$GOPATH go get .'" + + showrun $ssh podman pull $helper_fqin + # Tests expect image with this exact name + showrun $ssh podman tag $helper_fqin \ + docker.io/gitlab/gitlab-runner-helper:x86_64-latest-pwsh + ;; swagger) ;& # use next item consistency) make clean ;; release) ;; diff --git a/contrib/msi/podman.wxs b/contrib/msi/podman.wxs index 451dd565d..4136e2cc4 100644 --- a/contrib/msi/podman.wxs +++ b/contrib/msi/podman.wxs @@ -11,19 +11,19 @@ <Product Name="Podman $(var.VERSION)" Id="*" UpgradeCode="696BAB5D-CA1F-4B05-B123-320F245B8D6D" Version="$(var.VERSION)" Language="1033" Manufacturer="Red Hat Inc."> - <Package Id="*" Keywords="Installer" Description="Red Hat's Podman $(var.VERSION) Installer" Comments="Apache 2.0 License" Manufacturer="Red Hat Inc." InstallScope="perMachine" InstallerVersion="100" Compressed="yes"/> + <Package Id="*" Keywords="Installer" Description="Red Hat's Podman $(var.VERSION) Installer" Comments="Apache 2.0 License" Manufacturer="Red Hat Inc." InstallScope="perMachine" InstallerVersion="200" Compressed="yes"/> <Media Id="1" Cabinet="Podman.cab" EmbedCab="yes"/> <Property Id="DiskPrompt" Value="Red Hat's Podman $(var.VERSION) Installation"/> <Directory Id="TARGETDIR" Name="SourceDir"> - <Directory Id="ProgramFilesFolder" Name="PFiles"> + <Directory Id="ProgramFiles64Folder" Name="PFiles"> <Directory Id="RedHatPFiles" Name="RedHat"> <Directory Id="INSTALLDIR" Name="Podman"> - <Component Id="INSTALLDIR_Component" Guid="14B310C4-9B5D-4DA5-ADF9-B9D008E4CD82"> + <Component Id="INSTALLDIR_Component" Guid="14B310C4-9B5D-4DA5-ADF9-B9D008E4CD82" Win64="Yes"> <CreateFolder/> </Component> - <Component Id="MainExecutable" Guid="73752F94-6589-4C7B-ABED-39D655A19714"> + <Component Id="MainExecutable" Guid="73752F94-6589-4C7B-ABED-39D655A19714" Win64="Yes"> <File Id="520C6E17-77A2-4F41-9611-30FA763A0702" Name="podman.exe" Source="bin/windows/podman.exe" KeyPath="yes"/> </Component> </Directory> diff --git a/docs/dckrman.sh b/docs/dckrman.sh index c69524a7e..18fb364bf 100755 --- a/docs/dckrman.sh +++ b/docs/dckrman.sh @@ -4,3 +4,4 @@ for i in $@; do filename=$(echo $i | sed 's/podman/docker/g') echo .so man1/$b > $filename done +echo .so man5/containerfile.5 > $(dirname $1)/dockerfile.5 diff --git a/docs/source/markdown/podman-image-prune.1.md b/docs/source/markdown/podman-image-prune.1.md index bd08d18fc..493332ec0 100644 --- a/docs/source/markdown/podman-image-prune.1.md +++ b/docs/source/markdown/podman-image-prune.1.md @@ -17,6 +17,10 @@ The image prune command does not prune cache images that only use layers that ar Remove dangling images and images that have no associated containers. +#### **--external** + +Remove images even when they are used by external containers (e.g., build containers). + #### **--filter**=*filters* Provide filter values. @@ -12,7 +12,7 @@ require ( github.com/containernetworking/cni v1.0.1 github.com/containernetworking/plugins v1.0.1 github.com/containers/buildah v1.23.0 - github.com/containers/common v0.44.1-0.20210921143342-f2f10e650c73 + github.com/containers/common v0.46.1-0.20210928081721-32e20295f1c6 github.com/containers/conmon v2.0.20+incompatible github.com/containers/image/v5 v5.16.0 github.com/containers/ocicrypt v1.1.2 @@ -62,7 +62,6 @@ require ( github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 github.com/uber/jaeger-client-go v2.29.1+incompatible github.com/vbauerster/mpb/v6 v6.0.4 - github.com/vbauerster/mpb/v7 v7.1.4 // indirect github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 go.etcd.io/bbolt v1.3.6 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 @@ -250,8 +250,8 @@ github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNB github.com/containers/buildah v1.23.0 h1:qGIeSNOczUHzvnaaOS29HSMiYAjw6JgIXYksAyvqnLs= github.com/containers/buildah v1.23.0/go.mod h1:K0iMKgy/MffkkgELBXhSXwTy2HTT6hM0X8qruDR1FwU= github.com/containers/common v0.44.0/go.mod h1:7sdP4vmI5Bm6FPFxb3lvAh1Iktb6tiO1MzjUzhxdoGo= -github.com/containers/common v0.44.1-0.20210921143342-f2f10e650c73 h1:+qKOyTHbuFo3GPsrUksphfHxYMIJQmPgwpDdQnARGAI= -github.com/containers/common v0.44.1-0.20210921143342-f2f10e650c73/go.mod h1:zxv7KjdYddSGoWuLUVp6eSb++Ow1zmSMB2jwxuNB4cU= +github.com/containers/common v0.46.1-0.20210928081721-32e20295f1c6 h1:DojkCc4a9f3WB25Fk0GDap1/OkKU9UmDLvPJyqw3TBc= +github.com/containers/common v0.46.1-0.20210928081721-32e20295f1c6/go.mod h1:L4+sJlqi+R7frlbiWBW0baPra/cH8u5ZYwbxkukw3Lk= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.16.0 h1:WQcNSzb7+ngS2cfynx0vUwhk+scpgiKlldVcsF8GPbI= diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 612908ac2..1242a8d6b 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -1756,6 +1756,23 @@ func (s *BoltState) SafeRewriteContainerConfig(ctr *Container, oldName, newName if err := allCtrsBkt.Put([]byte(ctr.ID()), []byte(newName)); err != nil { return errors.Wrapf(err, "error renaming container %s in all containers bucket in DB", ctr.ID()) } + if ctr.config.Pod != "" { + podsBkt, err := getPodBucket(tx) + if err != nil { + return err + } + podBkt := podsBkt.Bucket([]byte(ctr.config.Pod)) + if podBkt == nil { + return errors.Wrapf(define.ErrInternal, "bucket for pod %s does not exist", ctr.config.Pod) + } + podCtrBkt := podBkt.Bucket(containersBkt) + if podCtrBkt == nil { + return errors.Wrapf(define.ErrInternal, "pod %s does not have a containers bucket", ctr.config.Pod) + } + if err := podCtrBkt.Put([]byte(ctr.ID()), []byte(newName)); err != nil { + return errors.Wrapf(err, "error renaming container %s in pod %s members bucket", ctr.ID(), ctr.config.Pod) + } + } } } diff --git a/libpod/container.go b/libpod/container.go index 5c56ff036..4d15c04c5 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -774,9 +774,9 @@ func (c *Container) ExecSessions() ([]string, error) { return ids, nil } -// ExecSession retrieves detailed information on a single active exec session in -// a container -func (c *Container) ExecSession(id string) (*ExecSession, error) { +// execSessionNoCopy returns the associated exec session to id. +// Note that the session is not a deep copy. +func (c *Container) execSessionNoCopy(id string) (*ExecSession, error) { if !c.batched { c.lock.Lock() defer c.lock.Unlock() @@ -791,6 +791,17 @@ func (c *Container) ExecSession(id string) (*ExecSession, error) { return nil, errors.Wrapf(define.ErrNoSuchExecSession, "no exec session with ID %s found in container %s", id, c.ID()) } + return session, nil +} + +// ExecSession retrieves detailed information on a single active exec session in +// a container +func (c *Container) ExecSession(id string) (*ExecSession, error) { + session, err := c.execSessionNoCopy(id) + if err != nil { + return nil, err + } + returnSession := new(ExecSession) if err := JSONDeepCopy(session, returnSession); err != nil { return nil, errors.Wrapf(err, "error copying contents of container %s exec session %s", c.ID(), session.ID()) @@ -1095,7 +1106,7 @@ func (c *Container) AutoRemove() bool { if spec.Annotations == nil { return false } - return c.Spec().Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue + return spec.Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue } // Timezone returns the timezone configured inside the container. diff --git a/libpod/container_copy_linux.go b/libpod/container_copy_linux.go index a35824289..7d4dd0d46 100644 --- a/libpod/container_copy_linux.go +++ b/libpod/container_copy_linux.go @@ -174,7 +174,7 @@ func (c *Container) copyToArchive(ctx context.Context, path string, writer io.Wr // getContainerUser returns the specs.User and ID mappings of the container. func getContainerUser(container *Container, mountPoint string) (specs.User, error) { - userspec := container.Config().User + userspec := container.config.User uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec) u := specs.User{ diff --git a/libpod/container_exec.go b/libpod/container_exec.go index 1cb45a118..f99fb7d3f 100644 --- a/libpod/container_exec.go +++ b/libpod/container_exec.go @@ -747,7 +747,7 @@ func (c *Container) Exec(config *ExecConfig, streams *define.AttachStreams, resi return -1, err } - session, err := c.ExecSession(sessionID) + session, err := c.execSessionNoCopy(sessionID) if err != nil { if errors.Cause(err) == define.ErrNoSuchExecSession { // TODO: If a proper Context is ever plumbed in here, we diff --git a/libpod/container_internal.go b/libpod/container_internal.go index cb691dfd8..3f9738411 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -923,12 +923,11 @@ func (c *Container) checkDependenciesRunning() ([]string, error) { } // Check the status - conf := depCtr.Config() state, err := depCtr.State() if err != nil { return nil, errors.Wrapf(err, "error retrieving state of dependency %s of container %s", dep, c.ID()) } - if state != define.ContainerStateRunning && !conf.IsInfra { + if state != define.ContainerStateRunning && !depCtr.config.IsInfra { notRunning = append(notRunning, dep) } depCtrs[dep] = depCtr @@ -1003,7 +1002,7 @@ func (c *Container) cniHosts() string { for _, status := range c.getNetworkStatus() { for _, netInt := range status.Interfaces { for _, netAddress := range netInt.Networks { - hosts += fmt.Sprintf("%s\t%s %s\n", netAddress.Subnet.IP.String(), c.Hostname(), c.Config().Name) + hosts += fmt.Sprintf("%s\t%s %s\n", netAddress.Subnet.IP.String(), c.Hostname(), c.config.Name) } } } @@ -2005,7 +2004,7 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (map[s } return nil, err } - ociHooks, err := manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0) + ociHooks, err := manager.Hooks(config, c.config.Spec.Annotations, len(c.config.UserVolumes) > 0) if err != nil { return nil, err } @@ -2022,7 +2021,7 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (map[s return nil, err } - allHooks, err = manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0) + allHooks, err = manager.Hooks(config, c.config.Spec.Annotations, len(c.config.UserVolumes) > 0) if err != nil { return nil, err } @@ -2106,7 +2105,7 @@ func (c *Container) canWithPrevious() error { // JSON files for later export func (c *Container) prepareCheckpointExport() error { // save live config - if _, err := metadata.WriteJSONFile(c.Config(), c.bundlePath(), metadata.ConfigDumpFile); err != nil { + if _, err := metadata.WriteJSONFile(c.config, c.bundlePath(), metadata.ConfigDumpFile); err != nil { return err } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index dd6f3878a..867ecc2ad 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -1310,7 +1310,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti if err == nil && options.Name == "" && (!options.IgnoreStaticIP || !options.IgnoreStaticMAC) { // The file with the network.status does exist. Let's restore the // container with the same networks settings as during checkpointing. - aliases, err := c.runtime.state.GetAllNetworkAliases(c) + aliases, err := c.GetAllNetworkAliases() if err != nil { return err } diff --git a/libpod/container_path_resolution.go b/libpod/container_path_resolution.go index ec7306ca1..bb2ef1a73 100644 --- a/libpod/container_path_resolution.go +++ b/libpod/container_path_resolution.go @@ -112,7 +112,7 @@ func (c *Container) resolvePath(mountPoint string, containerPath string) (string func findVolume(c *Container, containerPath string) (*Volume, error) { runtime := c.Runtime() cleanedContainerPath := filepath.Clean(containerPath) - for _, vol := range c.Config().NamedVolumes { + for _, vol := range c.config.NamedVolumes { if cleanedContainerPath == filepath.Clean(vol.Dest) { return runtime.GetVolume(vol.Name) } @@ -124,7 +124,7 @@ func findVolume(c *Container, containerPath string) (*Volume, error) { // Volume's destination. func isPathOnVolume(c *Container, containerPath string) bool { cleanedContainerPath := filepath.Clean(containerPath) - for _, vol := range c.Config().NamedVolumes { + for _, vol := range c.config.NamedVolumes { if cleanedContainerPath == filepath.Clean(vol.Dest) { return true } @@ -141,7 +141,7 @@ func isPathOnVolume(c *Container, containerPath string) bool { // path of a Mount. Returns a matching Mount or nil. func findBindMount(c *Container, containerPath string) *specs.Mount { cleanedPath := filepath.Clean(containerPath) - for _, m := range c.Config().Spec.Mounts { + for _, m := range c.config.Spec.Mounts { if m.Type != "bind" { continue } @@ -157,7 +157,7 @@ func findBindMount(c *Container, containerPath string) *specs.Mount { // Mount's destination. func isPathOnBindMount(c *Container, containerPath string) bool { cleanedContainerPath := filepath.Clean(containerPath) - for _, m := range c.Config().Spec.Mounts { + for _, m := range c.config.Spec.Mounts { if cleanedContainerPath == filepath.Clean(m.Destination) { return true } diff --git a/libpod/kube.go b/libpod/kube.go index d94108cf2..57d99f3ef 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -90,7 +90,7 @@ func (p *Pod) GenerateForKube(ctx context.Context) (*v1.Pod, []v1.ServicePort, e // so set it at here for _, ctr := range allContainers { if !ctr.IsInfra() { - switch ctr.Config().RestartPolicy { + switch ctr.config.RestartPolicy { case define.RestartPolicyAlways: pod.Spec.RestartPolicy = v1.RestartPolicyAlways case define.RestartPolicyOnFailure: @@ -253,7 +253,9 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po // We add the original port declarations from the libpod infra container // to the first kubernetes container description because otherwise we loose // the original container/port bindings. - if first && len(ports) > 0 { + // Add the port configuration to the first regular container or the first + // init container if only init containers have been created in the pod. + if first && len(ports) > 0 && (!isInit || len(containers) == 2) { ctr.Ports = ports first = false } @@ -424,7 +426,7 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, [] // NOTE: a privileged container mounts all of /dev/*. if !c.Privileged() && len(c.config.Spec.Linux.Devices) > 0 { // TODO Enable when we can support devices and their names - kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.Spec().Linux.Devices) + kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.config.Spec.Linux.Devices) return kubeContainer, kubeVolumes, nil, errors.Wrapf(define.ErrNotImplemented, "linux devices") } diff --git a/libpod/network/cni/config.go b/libpod/network/cni/config.go index 670ee0c65..3df155637 100644 --- a/libpod/network/cni/config.go +++ b/libpod/network/cni/config.go @@ -170,7 +170,11 @@ func (n *cniNetwork) NetworkRemove(nameOrID string) error { file := network.filename delete(n.networks, network.libpodNet.Name) - return os.Remove(file) + // make sure to not error for ErrNotExist + if err := os.Remove(file); err != nil && !errors.Is(err, os.ErrNotExist) { + return err + } + return nil } // NetworkList will return all known Networks. Optionally you can diff --git a/libpod/network/cni/config_test.go b/libpod/network/cni/config_test.go index a0a0ea1af..288cf4626 100644 --- a/libpod/network/cni/config_test.go +++ b/libpod/network/cni/config_test.go @@ -1021,6 +1021,27 @@ var _ = Describe("Config", func() { Expect(err.Error()).To(ContainSubstring("subnet 10.10.0.0/24 is already used on the host or by another config")) }) + It("remove network should not error when config file does not exists on disk", func() { + name := "mynet" + network := types.Network{Name: name} + _, err := libpodNet.NetworkCreate(network) + Expect(err).To(BeNil()) + + path := filepath.Join(cniConfDir, name+".conflist") + Expect(path).To(BeARegularFile()) + + err = os.Remove(path) + Expect(err).To(BeNil()) + Expect(path).ToNot(BeARegularFile()) + + err = libpodNet.NetworkRemove(name) + Expect(err).To(BeNil()) + + nets, err := libpodNet.NetworkList() + Expect(err).To(BeNil()) + Expect(nets).To(HaveLen(1)) + Expect(nets).ToNot(ContainElement(HaveNetworkName(name))) + }) }) Context("network load valid existing ones", func() { diff --git a/libpod/network/cni/run.go b/libpod/network/cni/run.go index 0f91a407c..bd873f89b 100644 --- a/libpod/network/cni/run.go +++ b/libpod/network/cni/run.go @@ -186,9 +186,6 @@ outer: } return errors.Errorf("requested static ip %s not in any subnet on network %s", ip.String(), network.libpodNet.Name) } - if len(netOpts.Aliases) > 0 && !network.libpodNet.DNSEnabled { - return errors.New("cannot set aliases on a network without dns enabled") - } return nil } diff --git a/libpod/network/cni/run_test.go b/libpod/network/cni/run_test.go index 0a2c090e1..965203c2a 100644 --- a/libpod/network/cni/run_test.go +++ b/libpod/network/cni/run_test.go @@ -966,6 +966,26 @@ var _ = Describe("run CNI", func() { }) }) + It("setup with aliases but dns disabled should work", func() { + runTest(func() { + defNet := types.DefaultNetworkName + intName := "eth0" + setupOpts := types.SetupOptions{ + NetworkOptions: types.NetworkOptions{ + ContainerID: stringid.GenerateNonCryptoID(), + Networks: map[string]types.PerNetworkOptions{ + defNet: { + InterfaceName: intName, + Aliases: []string{"somealias"}, + }, + }, + }, + } + _, err := libpodNet.Setup(netNSContainer.Path(), setupOpts) + Expect(err).ToNot(HaveOccurred()) + }) + }) + }) Context("invalid network setup test", func() { @@ -1052,27 +1072,6 @@ var _ = Describe("run CNI", func() { }) }) - It("setup with aliases but dns disabled", func() { - runTest(func() { - defNet := types.DefaultNetworkName - intName := "eth0" - setupOpts := types.SetupOptions{ - NetworkOptions: types.NetworkOptions{ - ContainerID: stringid.GenerateNonCryptoID(), - Networks: map[string]types.PerNetworkOptions{ - defNet: { - InterfaceName: intName, - Aliases: []string{"somealias"}, - }, - }, - }, - } - _, err := libpodNet.Setup(netNSContainer.Path(), setupOpts) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("cannot set aliases on a network without dns enabled")) - }) - }) - It("setup without networks", func() { runTest(func() { setupOpts := types.SetupOptions{ diff --git a/libpod/network/types/network.go b/libpod/network/types/network.go index 68a32d499..2fe4f3da2 100644 --- a/libpod/network/types/network.go +++ b/libpod/network/types/network.go @@ -151,7 +151,9 @@ type PerNetworkOptions struct { // StaticIPv4 for this container. Optional. StaticIPs []net.IP `json:"static_ips,omitempty"` // Aliases contains a list of names which the dns server should resolve - // to this container. Can only be set when DNSEnabled is true on the Network. + // to this container. Should only be set when DNSEnabled is true on the Network. + // If aliases are set but there is no dns support for this network the + // network interface implementation should ignore this and NOT error. // Optional. Aliases []string `json:"aliases,omitempty"` // StaticMac for this container. Optional. diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index ec9d98b56..e792a410c 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -48,6 +48,41 @@ const ( persistentCNIDir = "/var/lib/cni" ) +// GetAllNetworkAliases returns all configured aliases for this container. +// It also adds the container short ID as alias to match docker. +func (c *Container) GetAllNetworkAliases() (map[string][]string, error) { + allAliases, err := c.runtime.state.GetAllNetworkAliases(c) + if err != nil { + return nil, err + } + + // get the all attached networks, we cannot use GetAllNetworkAliases() + // since it returns nil if there are no aliases + nets, _, err := c.networks() + if err != nil { + return nil, err + } + + // add container short ID as alias to match docker + for _, net := range nets { + allAliases[net] = append(allAliases[net], c.config.ID[:12]) + } + return allAliases, nil +} + +// GetNetworkAliases returns configured aliases for this network. +// It also adds the container short ID as alias to match docker. +func (c *Container) GetNetworkAliases(netName string) ([]string, error) { + aliases, err := c.runtime.state.GetNetworkAliases(c, netName) + if err != nil { + return nil, err + } + + // add container short ID as alias to match docker + aliases = append(aliases, c.config.ID[:12]) + return aliases, nil +} + func (c *Container) getNetworkOptions() (types.NetworkOptions, error) { opts := types.NetworkOptions{ ContainerID: c.config.ID, @@ -61,7 +96,7 @@ func (c *Container) getNetworkOptions() (types.NetworkOptions, error) { if err != nil { return opts, err } - aliases, err := c.runtime.state.GetAllNetworkAliases(c) + aliases, err := c.GetAllNetworkAliases() if err != nil { return opts, err } @@ -872,7 +907,7 @@ func (r *Runtime) reloadContainerNetwork(ctr *Container) (map[string]types.Statu } } - aliases, err := ctr.runtime.state.GetAllNetworkAliases(ctr) + aliases, err := ctr.GetAllNetworkAliases() if err != nil { return nil, err } @@ -975,6 +1010,11 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e for _, net := range networks { cniNet := new(define.InspectAdditionalNetwork) cniNet.NetworkID = net + aliases, err := c.GetNetworkAliases(net) + if err != nil { + return nil, err + } + cniNet.Aliases = aliases settings.Networks[net] = cniNet } } @@ -1009,7 +1049,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e return nil, err } - aliases, err := c.runtime.state.GetNetworkAliases(c, name) + aliases, err := c.GetNetworkAliases(name) if err != nil { return nil, err } @@ -1222,6 +1262,14 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e // get network status before we connect networkStatus := c.getNetworkStatus() + network, err := c.runtime.network.NetworkInspect(netName) + if err != nil { + return err + } + if !network.DNSEnabled && len(aliases) > 0 { + return errors.Wrapf(define.ErrInvalidArg, "cannot set network aliases for network %q because dns is disabled", netName) + } + if err := c.runtime.state.NetworkConnect(c, netName, aliases); err != nil { return err } @@ -1253,6 +1301,7 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e if !exists { return errors.Errorf("no network interface name for container %s on network %s", c.config.ID, netName) } + aliases = append(aliases, c.config.ID[:12]) opts.Networks = map[string]types.PerNetworkOptions{ netName: { Aliases: aliases, diff --git a/libpod/networking_slirp4netns.go b/libpod/networking_slirp4netns.go index cca55cb9b..46cda89a9 100644 --- a/libpod/networking_slirp4netns.go +++ b/libpod/networking_slirp4netns.go @@ -222,7 +222,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error { defer errorhandling.CloseQuiet(syncR) defer errorhandling.CloseQuiet(syncW) - havePortMapping := len(ctr.Config().PortMappings) > 0 + havePortMapping := len(ctr.config.PortMappings) > 0 logPath := filepath.Join(ctr.runtime.config.Engine.TmpDir, fmt.Sprintf("slirp4netns-%s.log", ctr.config.ID)) ctrNetworkSlipOpts := []string{} diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index b7b5d09cd..71a7b29fa 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -1150,7 +1150,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co if ctr.config.NetMode.IsSlirp4netns() || rootless.IsRootless() { if ctr.config.PostConfigureNetNS { - havePortMapping := len(ctr.Config().PortMappings) > 0 + havePortMapping := len(ctr.config.PortMappings) > 0 if havePortMapping { ctr.rootlessPortSyncR, ctr.rootlessPortSyncW, err = os.Pipe() if err != nil { diff --git a/libpod/pod.go b/libpod/pod.go index e4516b354..c0b0a974b 100644 --- a/libpod/pod.go +++ b/libpod/pod.go @@ -164,8 +164,7 @@ func (p *Pod) PidMode() string { if err != nil { return "" } - conf := infra.Config() - ctrSpec := conf.Spec + ctrSpec := infra.config.Spec if ctrSpec != nil && ctrSpec.Linux != nil { for _, ns := range ctrSpec.Linux.Namespaces { if ns.Type == specs.PIDNamespace { @@ -186,8 +185,7 @@ func (p *Pod) UserNSMode() string { if err != nil { return "" } - conf := infra.Config() - ctrSpec := conf.Spec + ctrSpec := infra.config.Spec if ctrSpec != nil && ctrSpec.Linux != nil { for _, ns := range ctrSpec.Linux.Namespaces { if ns.Type == specs.UserNamespace { diff --git a/libpod/pod_api.go b/libpod/pod_api.go index 3ee4cd839..971309f77 100644 --- a/libpod/pod_api.go +++ b/libpod/pod_api.go @@ -34,7 +34,7 @@ func (p *Pod) startInitContainers(ctx context.Context) error { } // If the container is a once init container, we need to remove it // after it runs - if initCon.Config().InitContainerType == define.OneShotInitContainer { + if initCon.config.InitContainerType == define.OneShotInitContainer { icLock := initCon.lock icLock.Lock() if err := p.runtime.removeContainer(ctx, initCon, false, false, true); err != nil { @@ -590,16 +590,16 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) { return nil, err } infraConfig = new(define.InspectPodInfraConfig) - infraConfig.HostNetwork = !infra.Config().ContainerNetworkConfig.UseImageHosts - infraConfig.StaticIP = infra.Config().ContainerNetworkConfig.StaticIP - infraConfig.NoManageResolvConf = infra.Config().UseImageResolvConf - infraConfig.NoManageHosts = infra.Config().UseImageHosts + infraConfig.HostNetwork = !infra.config.ContainerNetworkConfig.UseImageHosts + infraConfig.StaticIP = infra.config.ContainerNetworkConfig.StaticIP + infraConfig.NoManageResolvConf = infra.config.UseImageResolvConf + infraConfig.NoManageHosts = infra.config.UseImageHosts infraConfig.CPUPeriod = p.CPUPeriod() infraConfig.CPUQuota = p.CPUQuota() infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus infraConfig.PidNS = p.PidMode() infraConfig.UserNS = p.UserNSMode() - namedVolumes, mounts := infra.sortUserVolumes(infra.Config().Spec) + namedVolumes, mounts := infra.sortUserVolumes(infra.config.Spec) inspectMounts, err = infra.GetInspectMounts(namedVolumes, infra.config.ImageVolumes, mounts) if err != nil { return nil, err @@ -611,30 +611,30 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) { return nil, err } - if len(infra.Config().ContainerNetworkConfig.DNSServer) > 0 { - infraConfig.DNSServer = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSServer)) - for _, entry := range infra.Config().ContainerNetworkConfig.DNSServer { + if len(infra.config.ContainerNetworkConfig.DNSServer) > 0 { + infraConfig.DNSServer = make([]string, 0, len(infra.config.ContainerNetworkConfig.DNSServer)) + for _, entry := range infra.config.ContainerNetworkConfig.DNSServer { infraConfig.DNSServer = append(infraConfig.DNSServer, entry.String()) } } - if len(infra.Config().ContainerNetworkConfig.DNSSearch) > 0 { - infraConfig.DNSSearch = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSSearch)) - infraConfig.DNSSearch = append(infraConfig.DNSSearch, infra.Config().ContainerNetworkConfig.DNSSearch...) + if len(infra.config.ContainerNetworkConfig.DNSSearch) > 0 { + infraConfig.DNSSearch = make([]string, 0, len(infra.config.ContainerNetworkConfig.DNSSearch)) + infraConfig.DNSSearch = append(infraConfig.DNSSearch, infra.config.ContainerNetworkConfig.DNSSearch...) } - if len(infra.Config().ContainerNetworkConfig.DNSOption) > 0 { - infraConfig.DNSOption = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSOption)) - infraConfig.DNSOption = append(infraConfig.DNSOption, infra.Config().ContainerNetworkConfig.DNSOption...) + if len(infra.config.ContainerNetworkConfig.DNSOption) > 0 { + infraConfig.DNSOption = make([]string, 0, len(infra.config.ContainerNetworkConfig.DNSOption)) + infraConfig.DNSOption = append(infraConfig.DNSOption, infra.config.ContainerNetworkConfig.DNSOption...) } - if len(infra.Config().HostAdd) > 0 { - infraConfig.HostAdd = make([]string, 0, len(infra.Config().HostAdd)) - infraConfig.HostAdd = append(infraConfig.HostAdd, infra.Config().HostAdd...) + if len(infra.config.HostAdd) > 0 { + infraConfig.HostAdd = make([]string, 0, len(infra.config.HostAdd)) + infraConfig.HostAdd = append(infraConfig.HostAdd, infra.config.HostAdd...) } - if len(infra.Config().ContainerNetworkConfig.Networks) > 0 { - infraConfig.Networks = make([]string, 0, len(infra.Config().ContainerNetworkConfig.Networks)) - infraConfig.Networks = append(infraConfig.Networks, infra.Config().ContainerNetworkConfig.Networks...) + if len(infra.config.ContainerNetworkConfig.Networks) > 0 { + infraConfig.Networks = make([]string, 0, len(infra.config.ContainerNetworkConfig.Networks)) + infraConfig.Networks = append(infraConfig.Networks, infra.config.ContainerNetworkConfig.Networks...) } - infraConfig.NetworkOptions = infra.Config().ContainerNetworkConfig.NetworkOptions - infraConfig.PortBindings = makeInspectPortBindings(infra.Config().ContainerNetworkConfig.PortMappings, nil) + infraConfig.NetworkOptions = infra.config.ContainerNetworkConfig.NetworkOptions + infraConfig.PortBindings = makeInspectPortBindings(infra.config.ContainerNetworkConfig.PortMappings, nil) } inspectData := define.InspectPodData{ diff --git a/libpod/runtime.go b/libpod/runtime.go index 161d5a533..27885bf5c 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -706,19 +706,32 @@ func (r *Runtime) TmpDir() (string, error) { return r.config.Engine.TmpDir, nil } -// GetConfig returns a copy of the configuration used by the runtime -func (r *Runtime) GetConfig() (*config.Config, error) { +// GetConfig returns the configuration used by the runtime. +// Note that the returned value is not a copy and must hence +// only be used in a reading fashion. +func (r *Runtime) GetConfigNoCopy() (*config.Config, error) { r.lock.RLock() defer r.lock.RUnlock() if !r.valid { return nil, define.ErrRuntimeStopped } + return r.config, nil +} + +// GetConfig returns a copy of the configuration used by the runtime. +// Please use GetConfigNoCopy() in case you only want to read from +// but not write to the returned config. +func (r *Runtime) GetConfig() (*config.Config, error) { + rtConfig, err := r.GetConfigNoCopy() + if err != nil { + return nil, err + } config := new(config.Config) // Copy so the caller won't be able to modify the actual config - if err := JSONDeepCopy(r.config, config); err != nil { + if err := JSONDeepCopy(rtConfig, config); err != nil { return nil, errors.Wrapf(err, "error copying config") } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 3494fa8f2..00979a500 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -193,10 +193,7 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf ctr.config.LogPath = "" } - ctr.config.Spec = new(spec.Spec) - if err := JSONDeepCopy(rSpec, ctr.config.Spec); err != nil { - return nil, errors.Wrapf(err, "error copying runtime spec while creating container") - } + ctr.config.Spec = rSpec ctr.config.CreatedTime = time.Now() ctr.state.BindMounts = make(map[string]string) @@ -234,13 +231,6 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options .. } func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Container, retErr error) { - // Validate the container - if err := ctr.validate(); err != nil { - return nil, err - } - if ctr.config.IsInfra { - ctr.config.StopTimeout = 10 - } // normalize the networks to names // ocicni only knows about cni names so we have to make // sure we do not use ids internally @@ -265,11 +255,26 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai if err != nil { return nil, err } + network, err := r.network.NetworkInspect(netName) + if err != nil { + return nil, err + } + if !network.DNSEnabled { + return nil, errors.Wrapf(define.ErrInvalidArg, "cannot set network aliases for network %q because dns is disabled", netName) + } netAliases[netName] = aliases } ctr.config.NetworkAliases = netAliases } + // Validate the container + if err := ctr.validate(); err != nil { + return nil, err + } + if ctr.config.IsInfra { + ctr.config.StopTimeout = 10 + } + // Inhibit shutdown until creation succeeds shutdown.Inhibit() defer shutdown.Uninhibit() diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index 66cf7a4d5..1915a5c4d 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -48,6 +48,27 @@ func (r *Runtime) RemoveContainersForImageCallback(ctx context.Context) libimage } } +// IsExternalContainerCallback returns a callback that be used in `libimage` to +// figure out whether a given container is an external one. A container is +// considered external if it is not present in libpod's database. +func (r *Runtime) IsExternalContainerCallback(_ context.Context) libimage.IsExternalContainerFunc { + // NOTE: pruning external containers is subject to race conditions + // (e.g., when a container gets removed). To address this and similar + // races, pruning had to happen inside c/storage. Containers has to be + // labelled with "podman/libpod" along with callbacks similar to + // libimage. + return func(idOrName string) (bool, error) { + _, err := r.LookupContainer(idOrName) + if err == nil { + return false, nil + } + if errors.Is(err, define.ErrNoSuchCtr) { + return true, nil + } + return false, nil + } +} + // newBuildEvent creates a new event based on completion of a built image func (r *Runtime) newImageBuildCompleteEvent(idOrName string) { e := events.NewEvent(events.Build) diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index 0023479ea..1c6cc917c 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -150,7 +150,8 @@ func PruneImages(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { - All bool `schema:"all"` + All bool `schema:"all"` + External bool `schema:"external"` }{ // override any golang type defaults } @@ -190,8 +191,9 @@ func PruneImages(w http.ResponseWriter, r *http.Request) { imageEngine := abi.ImageEngine{Libpod: runtime} pruneOptions := entities.ImagePruneOptions{ - All: query.All, - Filter: libpodFilters, + All: query.All, + External: query.External, + Filter: libpodFilters, } imagePruneReports, err := imageEngine.Prune(r.Context(), pruneOptions) if err != nil { diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 5e0de7def..aa573eaa6 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -1050,6 +1050,12 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // description: | // Remove all images not in use by containers, not just dangling ones // - in: query + // name: external + // default: false + // type: boolean + // description: | + // Remove images even when they are used by external containers (e.g, by build containers) + // - in: query // name: filters // type: string // description: | diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go index 4127ad2f0..e2c46e481 100644 --- a/pkg/bindings/connection.go +++ b/pkg/bindings/connection.go @@ -112,12 +112,12 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, identity string) return nil, errors.Errorf("unable to create connection. %q is not a supported schema", _url.Scheme) } if err != nil { - return nil, errors.Wrapf(err, "failed to create %sClient", _url.Scheme) + return nil, errors.Wrapf(err, "unable to connect to Podman. failed to create %sClient", _url.Scheme) } ctx = context.WithValue(ctx, clientKey, &connection) if err := pingNewConnection(ctx); err != nil { - return nil, errors.Wrap(err, "cannot connect to the Podman socket, please verify the connection to the Linux system, or use `podman machine` to create/start a Linux VM.") + return nil, errors.Wrap(err, "unable to connect to Podman socket") } return ctx, nil } diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index ded97d8d6..8cf4532d0 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -230,6 +230,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO params.Add("platform", platform) } } + if contextDir, err := filepath.EvalSymlinks(options.ContextDirectory); err == nil { + options.ContextDirectory = contextDir + } params.Set("pullpolicy", options.PullPolicy.String()) diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go index 6ff9f18ec..dc6bd91c3 100644 --- a/pkg/bindings/images/types.go +++ b/pkg/bindings/images/types.go @@ -74,6 +74,8 @@ type ExportOptions struct { type PruneOptions struct { // Prune all images All *bool + // Prune images even when they're used by external containers + External *bool // Filters to apply when pruning images Filters map[string][]string } diff --git a/pkg/bindings/images/types_prune_options.go b/pkg/bindings/images/types_prune_options.go index 77bef32e3..c9772045e 100644 --- a/pkg/bindings/images/types_prune_options.go +++ b/pkg/bindings/images/types_prune_options.go @@ -32,6 +32,21 @@ func (o *PruneOptions) GetAll() bool { return *o.All } +// WithExternal set field External to given value +func (o *PruneOptions) WithExternal(value bool) *PruneOptions { + o.External = &value + return o +} + +// GetExternal returns value of field External +func (o *PruneOptions) GetExternal() bool { + if o.External == nil { + var z bool + return z + } + return *o.External +} + // WithFilters set field Filters to given value func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions { o.Filters = value diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 80d570764..2822b1ad7 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -251,8 +251,9 @@ type ImageListOptions struct { } type ImagePruneOptions struct { - All bool `json:"all" schema:"all"` - Filter []string `json:"filter" schema:"filter"` + All bool `json:"all" schema:"all"` + External bool `json:"external" schema:"external"` + Filter []string `json:"filter" schema:"filter"` } type ImageTagOptions struct{} diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 02af214a6..8e7e2d411 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -169,6 +169,10 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin logrus.Debugf("Container %s is already stopped", c.ID()) case options.All && errors.Cause(err) == define.ErrCtrStateInvalid: logrus.Debugf("Container %s is not running, could not stop", c.ID()) + // container never created in OCI runtime + // docker parity: do nothing just return container id + case errors.Cause(err) == define.ErrCtrStateInvalid: + logrus.Debugf("Container %s is either not created on runtime or is in a invalid state", c.ID()) default: return err } diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 98d668434..c06059205 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -41,13 +41,21 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) { pruneOptions := &libimage.RemoveImagesOptions{ - Filters: append(opts.Filter, "containers=false", "readonly=false"), - WithSize: true, + RemoveContainerFunc: ir.Libpod.RemoveContainersForImageCallback(ctx), + IsExternalContainerFunc: ir.Libpod.IsExternalContainerCallback(ctx), + ExternalContainers: opts.External, + Filters: append(opts.Filter, "readonly=false"), + WithSize: true, } if !opts.All { pruneOptions.Filters = append(pruneOptions.Filters, "dangling=true") } + if opts.External { + pruneOptions.Filters = append(pruneOptions.Filters, "containers=external") + } else { + pruneOptions.Filters = append(pruneOptions.Filters, "containers=false") + } var pruneReports []*reports.PruneReport diff --git a/pkg/domain/infra/abi/secrets.go b/pkg/domain/infra/abi/secrets.go index 2bf8eaae3..34c230e75 100644 --- a/pkg/domain/infra/abi/secrets.go +++ b/pkg/domain/infra/abi/secrets.go @@ -21,7 +21,7 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader // set defaults from config for the case they are not set by an upper layer // (-> i.e. tests that talk directly to the api) - cfg, err := ic.Libpod.GetConfig() + cfg, err := ic.Libpod.GetConfigNoCopy() if err != nil { return nil, err } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 282770613..d41a20348 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -95,7 +95,7 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption f := strings.Split(filter, "=") filters[f[0]] = f[1:] } - options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters) + options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters).WithExternal(opts.External) reports, err := images.Prune(ir.ClientCtx, options) if err != nil { return nil, err diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go index 89b556b14..e211f5ea6 100644 --- a/pkg/machine/ignition.go +++ b/pkg/machine/ignition.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "net/url" ) /* @@ -80,6 +81,7 @@ func NewIgnitionFile(ign DynamicIgnition) error { // so a listening host knows it can being interacting with it ready := `[Unit] Requires=dev-virtio\\x2dports-%s.device +After=remove-moby.service OnFailure=emergency.target OnFailureJobMode=isolate [Service] @@ -89,6 +91,23 @@ ExecStart=/bin/sh -c '/usr/bin/echo Ready >/dev/%s' [Install] RequiredBy=multi-user.target ` + deMoby := `[Unit] +Description=Remove moby-engine +# Run once for the machine +After=systemd-machine-id-commit.service +Before=zincati.service +ConditionPathExists=!/var/lib/%N.stamp + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/rpm-ostree override remove moby-engine +ExecStart=/usr/bin/rpm-ostree ex apply-live --allow-replacement +ExecStartPost=/bin/touch /var/lib/%N.stamp + +[Install] +WantedBy=multi-user.target + ` _ = ready ignSystemd := Systemd{ Units: []Unit{ @@ -101,6 +120,21 @@ RequiredBy=multi-user.target Name: "ready.service", Contents: strToPtr(fmt.Sprintf(ready, "vport1p1", "vport1p1")), }, + { + Enabled: boolToPtr(false), + Name: "docker.service", + Mask: boolToPtr(true), + }, + { + Enabled: boolToPtr(false), + Name: "docker.socket", + Mask: boolToPtr(true), + }, + { + Enabled: boolToPtr(true), + Name: "remove-moby.service", + Contents: &deMoby, + }, }} ignConfig := Config{ Ignition: ignVersion, @@ -161,6 +195,22 @@ func getFiles(usrName string) []File { var ( files []File ) + + lingerExample := `[Unit] +Description=A systemd user unit demo +After=network-online.target +Wants=network-online.target podman.socket +[Service] +ExecStart=/usr/bin/sleep infinity +` + containers := `[containers] +netns="bridge" +rootless_networking="cni" +` + rootContainers := `[engine] +machine_enabled=true +` + // Add a fake systemd service to get the user socket rolling files = append(files, File{ Node: Node{ @@ -171,7 +221,7 @@ func getFiles(usrName string) []File { FileEmbedded1: FileEmbedded1{ Append: nil, Contents: Resource{ - Source: strToPtr("data:,%5BUnit%5D%0ADescription%3DA%20systemd%20user%20unit%20demo%0AAfter%3Dnetwork-online.target%0AWants%3Dnetwork-online.target%20podman.socket%0A%5BService%5D%0AExecStart%3D%2Fusr%2Fbin%2Fsleep%20infinity%0A"), + Source: encodeDataURLPtr(lingerExample), }, Mode: intToPtr(0744), }, @@ -188,7 +238,7 @@ func getFiles(usrName string) []File { FileEmbedded1: FileEmbedded1{ Append: nil, Contents: Resource{ - Source: strToPtr("data:,%5Bcontainers%5D%0D%0Anetns%3D%22bridge%22%0D%0Arootless_networking%3D%22cni%22"), + Source: encodeDataURLPtr(containers), }, Mode: intToPtr(0744), }, @@ -213,7 +263,7 @@ func getFiles(usrName string) []File { FileEmbedded1: FileEmbedded1{ Append: nil, Contents: Resource{ - Source: strToPtr("data:,%5Bengine%5D%0Amachine_enabled%3Dtrue%0A"), + Source: encodeDataURLPtr(rootContainers), }, Mode: intToPtr(0644), }, @@ -233,7 +283,22 @@ func getFiles(usrName string) []File { FileEmbedded1: FileEmbedded1{ Append: nil, Contents: Resource{ - Source: strToPtr("data:,unqualified-search-registries%3D%5B%22docker.io%22%5D"), + Source: encodeDataURLPtr("unqualified-search-registries=[\"docker.io\"]\n"), + }, + Mode: intToPtr(0644), + }, + }) + + files = append(files, File{ + Node: Node{ + Path: "/etc/tmpfiles.d/podman-docker.conf", + }, + FileEmbedded1: FileEmbedded1{ + Append: nil, + // Create a symlink from the docker socket to the podman socket. + // Taken from https://github.com/containers/podman/blob/main/contrib/systemd/system/podman-docker.conf + Contents: Resource{ + Source: encodeDataURLPtr("L+ /run/docker.sock - - - - /run/podman/podman.sock\n"), }, Mode: intToPtr(0644), }, @@ -253,5 +318,20 @@ func getLinks(usrName string) []Link { Hard: boolToPtr(false), Target: "/home/" + usrName + "/.config/systemd/user/linger-example.service", }, + }, { + Node: Node{ + Group: getNodeGrp("root"), + Path: "/usr/local/bin/docker", + Overwrite: boolToPtr(true), + User: getNodeUsr("root"), + }, + LinkEmbedded1: LinkEmbedded1{ + Hard: boolToPtr(false), + Target: "/usr/bin/podman", + }, }} } + +func encodeDataURLPtr(contents string) *string { + return strToPtr(fmt.Sprintf("data:,%s", url.PathEscape(contents))) +} diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index ae26807a9..71b882510 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -54,7 +54,7 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat } } - rtc, err := r.GetConfig() + rtc, err := r.GetConfigNoCopy() if err != nil { return nil, err } diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index fefa9b4a9..6100e7a5b 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -23,7 +23,7 @@ import ( // Returns the created, container and any warnings resulting from creating the // container, or an error. func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator) (*spec.Spec, *specgen.SpecGenerator, []libpod.CtrCreateOption, error) { - rtc, err := rt.GetConfig() + rtc, err := rt.GetConfigNoCopy() if err != nil { return nil, nil, nil, err } @@ -498,6 +498,7 @@ func CreateExitCommandArgs(storageConfig types.StoreOptions, config *config.Conf "--log-level", logrus.GetLevel().String(), "--cgroup-manager", config.Engine.CgroupManager, "--tmpdir", config.Engine.TmpDir, + "--cni-config-dir", config.Network.NetworkConfigDir, } if config.Engine.OCIRuntime != "" { command = append(command, []string{"--runtime", config.Engine.OCIRuntime}...) diff --git a/test/compose/test-compose b/test/compose/test-compose index 70db6dd55..beaf276fd 100755 --- a/test/compose/test-compose +++ b/test/compose/test-compose @@ -247,6 +247,7 @@ function podman() { --storage-driver=vfs \ --root $WORKDIR/root \ --runroot $WORKDIR/runroot \ + --cni-config-dir $WORKDIR/cni \ "$@") echo -n "$output" >>$WORKDIR/output.log } diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go index 217efdeec..5f7c55d3f 100644 --- a/test/e2e/network_connect_disconnect_test.go +++ b/test/e2e/network_connect_disconnect_test.go @@ -52,7 +52,6 @@ var _ = Describe("Podman network connect and disconnect", func() { }) It("network disconnect with net mode slirp4netns should result in error", func() { - SkipIfRootless("network connect and disconnect are only rootful") netName := "slirp" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", netName}) session.WaitWithDefaultTimeout() @@ -118,7 +117,6 @@ var _ = Describe("Podman network connect and disconnect", func() { }) It("network connect with net mode slirp4netns should result in error", func() { - SkipIfRootless("network connect and disconnect are only rootful") netName := "slirp" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", netName}) session.WaitWithDefaultTimeout() @@ -146,6 +144,13 @@ var _ = Describe("Podman network connect and disconnect", func() { ctr := podmanTest.Podman([]string{"create", "--name", "test", "--network", netName, ALPINE, "top"}) ctr.WaitWithDefaultTimeout() Expect(ctr).Should(Exit(0)) + cid := ctr.OutputToString() + + // network alias container short id is always added and shown in inspect + inspect := podmanTest.Podman([]string{"container", "inspect", "test", "--format", "{{(index .NetworkSettings.Networks \"" + netName + "\").Aliases}}"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(Equal("[" + cid[0:12] + "]")) con := podmanTest.Podman([]string{"network", "connect", netName, "test"}) con.WaitWithDefaultTimeout() @@ -153,7 +158,6 @@ var _ = Describe("Podman network connect and disconnect", func() { }) It("podman network connect", func() { - SkipIfRemote("This requires a pending PR to be merged before it will work") netName := "aliasTest" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", netName}) session.WaitWithDefaultTimeout() @@ -163,6 +167,7 @@ var _ = Describe("Podman network connect and disconnect", func() { ctr := podmanTest.Podman([]string{"run", "-dt", "--name", "test", "--network", netName, ALPINE, "top"}) ctr.WaitWithDefaultTimeout() Expect(ctr).Should(Exit(0)) + cid := ctr.OutputToString() exec := podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"}) exec.WaitWithDefaultTimeout() @@ -184,6 +189,12 @@ var _ = Describe("Podman network connect and disconnect", func() { Expect(inspect).Should(Exit(0)) Expect(inspect.OutputToString()).To(Equal("2")) + // network alias container short id is always added and shown in inspect + inspect = podmanTest.Podman([]string{"container", "inspect", "test", "--format", "{{(index .NetworkSettings.Networks \"" + newNetName + "\").Aliases}}"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(Equal("[" + cid[0:12] + "]")) + exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth1"}) exec.WaitWithDefaultTimeout() Expect(exec).Should(Exit(0)) @@ -193,7 +204,6 @@ var _ = Describe("Podman network connect and disconnect", func() { rm.WaitWithDefaultTimeout() Expect(rm).Should(Exit(0)) Expect(rm.ErrorToString()).To(Equal("")) - }) It("podman network connect when not running", func() { diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 7e56b8a25..8e47fac75 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -603,6 +603,11 @@ var _ = Describe("Podman network", func() { }) It("podman network prune --filter", func() { + // set custom cni directory to prevent flakes + podmanTest.CNIConfigDir = tempdir + if IsRemote() { + podmanTest.RestartRemoteService() + } net1 := "macvlan" + stringid.GenerateNonCryptoID() + "net1" nc := podmanTest.Podman([]string{"network", "create", net1}) @@ -613,11 +618,10 @@ var _ = Describe("Podman network", func() { list := podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}}"}) list.WaitWithDefaultTimeout() Expect(list).Should(Exit(0)) + Expect(list.OutputToStringArray()).Should(HaveLen(2)) - Expect(StringInSlice(net1, list.OutputToStringArray())).To(BeTrue()) - if !isRootless() { - Expect(StringInSlice("podman", list.OutputToStringArray())).To(BeTrue()) - } + Expect(list.OutputToStringArray()).Should(ContainElement(net1)) + Expect(list.OutputToStringArray()).Should(ContainElement("podman")) // -f needed only to skip y/n question prune := podmanTest.Podman([]string{"network", "prune", "-f", "--filter", "until=50"}) @@ -627,11 +631,10 @@ var _ = Describe("Podman network", func() { listAgain := podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}}"}) listAgain.WaitWithDefaultTimeout() Expect(listAgain).Should(Exit(0)) + Expect(listAgain.OutputToStringArray()).Should(HaveLen(2)) - Expect(StringInSlice(net1, listAgain.OutputToStringArray())).To(BeTrue()) - if !isRootless() { - Expect(StringInSlice("podman", list.OutputToStringArray())).To(BeTrue()) - } + Expect(listAgain.OutputToStringArray()).Should(ContainElement(net1)) + Expect(listAgain.OutputToStringArray()).Should(ContainElement("podman")) // -f needed only to skip y/n question prune = podmanTest.Podman([]string{"network", "prune", "-f", "--filter", "until=5000000000000"}) @@ -641,14 +644,18 @@ var _ = Describe("Podman network", func() { listAgain = podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}}"}) listAgain.WaitWithDefaultTimeout() Expect(listAgain).Should(Exit(0)) + Expect(listAgain.OutputToStringArray()).Should(HaveLen(1)) - Expect(StringInSlice(net1, listAgain.OutputToStringArray())).To(BeFalse()) - if !isRootless() { - Expect(StringInSlice("podman", list.OutputToStringArray())).To(BeTrue()) - } + Expect(listAgain.OutputToStringArray()).ShouldNot(ContainElement(net1)) + Expect(listAgain.OutputToStringArray()).Should(ContainElement("podman")) }) It("podman network prune", func() { + // set custom cni directory to prevent flakes + podmanTest.CNIConfigDir = tempdir + if IsRemote() { + podmanTest.RestartRemoteService() + } // Create two networks // Check they are there // Run a container on one of them @@ -669,13 +676,11 @@ var _ = Describe("Podman network", func() { list := podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}}"}) list.WaitWithDefaultTimeout() - Expect(list).Should(Exit(0)) + Expect(list.OutputToStringArray()).Should(HaveLen(3)) - Expect(StringInSlice(net1, list.OutputToStringArray())).To(BeTrue()) - Expect(StringInSlice(net2, list.OutputToStringArray())).To(BeTrue()) - if !isRootless() { - Expect(StringInSlice("podman", list.OutputToStringArray())).To(BeTrue()) - } + Expect(list.OutputToStringArray()).Should(ContainElement(net1)) + Expect(list.OutputToStringArray()).Should(ContainElement(net2)) + Expect(list.OutputToStringArray()).Should(ContainElement("podman")) session := podmanTest.Podman([]string{"run", "-dt", "--net", net2, ALPINE, "top"}) session.WaitWithDefaultTimeout() @@ -688,13 +693,10 @@ var _ = Describe("Podman network", func() { listAgain := podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}}"}) listAgain.WaitWithDefaultTimeout() Expect(listAgain).Should(Exit(0)) + Expect(listAgain.OutputToStringArray()).Should(HaveLen(2)) - Expect(StringInSlice(net1, listAgain.OutputToStringArray())).To(BeFalse()) - Expect(StringInSlice(net2, listAgain.OutputToStringArray())).To(BeTrue()) - // Make sure default network 'podman' still exists - if !isRootless() { - Expect(StringInSlice("podman", list.OutputToStringArray())).To(BeTrue()) - } - + Expect(listAgain.OutputToStringArray()).ShouldNot(ContainElement(net1)) + Expect(listAgain.OutputToStringArray()).Should(ContainElement(net2)) + Expect(listAgain.OutputToStringArray()).Should(ContainElement("podman")) }) }) diff --git a/test/e2e/rename_test.go b/test/e2e/rename_test.go index 0bd1792c9..e5e69c25c 100644 --- a/test/e2e/rename_test.go +++ b/test/e2e/rename_test.go @@ -111,4 +111,29 @@ var _ = Describe("podman rename", func() { Expect(ps).Should(Exit(0)) Expect(ps.OutputToString()).To(ContainSubstring(newName)) }) + + It("Rename a container that is part of a pod", func() { + podName := "testPod" + infraName := "infra1" + pod := podmanTest.Podman([]string{"pod", "create", "--name", podName, "--infra-name", infraName}) + pod.WaitWithDefaultTimeout() + Expect(pod).Should(Exit(0)) + + infraName2 := "infra2" + rename := podmanTest.Podman([]string{"rename", infraName, infraName2}) + rename.WaitWithDefaultTimeout() + Expect(rename).Should(Exit(0)) + + remove := podmanTest.Podman([]string{"pod", "rm", "-f", podName}) + remove.WaitWithDefaultTimeout() + Expect(remove).Should(Exit(0)) + + create := podmanTest.Podman([]string{"create", "--name", infraName2, ALPINE, "top"}) + create.WaitWithDefaultTimeout() + Expect(create).Should(Exit(0)) + + create2 := podmanTest.Podman([]string{"create", "--name", infraName, ALPINE, "top"}) + create2.WaitWithDefaultTimeout() + Expect(create2).Should(Exit(0)) + }) }) diff --git a/test/e2e/stop_test.go b/test/e2e/stop_test.go index a984bf6d0..7f178d719 100644 --- a/test/e2e/stop_test.go +++ b/test/e2e/stop_test.go @@ -234,6 +234,17 @@ var _ = Describe("Podman stop", func() { Expect(strings.TrimSpace(finalCtrs.OutputToString())).To(Equal("")) }) + It("podman stop should return silent success on stopping configured containers", func() { + // following container is not created on OCI runtime + // so we return success and assume that is is stopped + session2 := podmanTest.Podman([]string{"create", "--name", "stopctr", ALPINE, "/bin/sh"}) + session2.WaitWithDefaultTimeout() + Expect(session2).Should(Exit(0)) + session3 := podmanTest.Podman([]string{"stop", "stopctr"}) + session3.WaitWithDefaultTimeout() + Expect(session3).Should(Exit(0)) + }) + It("podman stop --cidfile", func() { tmpDir, err := ioutil.TempDir("", "") diff --git a/test/system/035-logs.bats b/test/system/035-logs.bats index a04d2ac74..76ce12b81 100644 --- a/test/system/035-logs.bats +++ b/test/system/035-logs.bats @@ -135,31 +135,38 @@ function _log_test_until() { s_after="after_$(random_string)_${driver}" before=$(date --iso-8601=seconds) - sleep 5 + sleep 1 run_podman run --log-driver=$driver -d --name test $IMAGE sh -c \ "echo $s_before; trap 'echo $s_after; exit' SIGTERM; while :; do sleep 1; done" # sleep a second to make sure the date is after the first echo sleep 1 run_podman stop test - # sleep for 20 seconds to get the proper after time - sleep 20 + run_podman wait test - run_podman logs test - is "$output" \ - "$s_before + # Sigh. Stupid journald has a lag. Wait a few seconds for it to catch up. + retries=20 + s_both="$s_before $s_after" + while [[ $retries -gt 0 ]]; do + run_podman logs test + if [[ "$output" = "$s_both" ]]; then + break + fi + retries=$((retries - 1)) + sleep 0.1 + done + if [[ $retries -eq 0 ]]; then + die "Timed out waiting for before&after in podman logs: $output" + fi run_podman logs --until $before test - is "$output" \ - "" + is "$output" "" "podman logs --until before" - after=$(date --iso-8601=seconds) + after=$(date --date='+1 second' --iso-8601=seconds) run_podman logs --until $after test - is "$output" \ - "$s_before -$s_after" + is "$output" "$s_both" "podman logs --until after" run_podman rm -f test } diff --git a/test/system/040-ps.bats b/test/system/040-ps.bats index 182d75547..63f57efdc 100644 --- a/test/system/040-ps.bats +++ b/test/system/040-ps.bats @@ -90,26 +90,48 @@ load helpers is "${#lines[@]}" "1" "setup check: no storage containers at start of test" # Force a buildah timeout; this leaves a buildah container behind + local t0=$SECONDS PODMAN_TIMEOUT=5 run_podman 124 build -t thiswillneverexist - <<EOF FROM $IMAGE +RUN touch /intermediate.image.to.be.pruned RUN sleep 30 EOF + local t1=$SECONDS + local delta_t=$((t1 - t0)) + if [[ $delta_t -gt 10 ]]; then + # FIXME FIXME FIXME: when buildah issue 3544 gets fixed and vendored, + # change 'echo' to 'die' + echo "podman build did not get killed within 10 seconds (actual time: $delta_t seconds)" + fi run_podman ps -a - is "${#lines[@]}" "1" "podman ps -a does not see buildah container" + is "${#lines[@]}" "1" "podman ps -a does not see buildah containers" run_podman ps --external -a - is "${#lines[@]}" "2" "podman ps -a --external sees buildah container" + is "${#lines[@]}" "3" "podman ps -a --external sees buildah containers" is "${lines[1]}" \ "[0-9a-f]\{12\} \+$IMAGE *buildah .* seconds ago .* storage .* ${PODMAN_TEST_IMAGE_NAME}-working-container" \ "podman ps --external" - cid="${lines[1]:0:12}" - # 'rm -a' should be a NOP run_podman rm -a run_podman ps --external -a - is "${#lines[@]}" "2" "podman ps -a --external sees buildah container" + is "${#lines[@]}" "3" "podman ps -a --external sees buildah containers" + + # Cannot prune intermediate image as it's being used by a buildah + # container. + run_podman image prune -f + is "$output" "" "No image is pruned" + + # --external for removing buildah containers. + run_podman image prune -f --external + is "${#lines[@]}" "1" "Image used by build container is pruned" + + # One buildah container has been removed. + run_podman ps --external -a + is "${#lines[@]}" "2" "podman ps -a --external sees buildah containers" + + cid="${lines[1]:0:12}" # We can't rm it without -f, but podman should issue a helpful message run_podman 2 rm "$cid" diff --git a/test/system/060-mount.bats b/test/system/060-mount.bats index 63a93e13b..ba37ea5e1 100644 --- a/test/system/060-mount.bats +++ b/test/system/060-mount.bats @@ -125,6 +125,7 @@ load helpers run_podman exec $cid find /image-mount/etc/ # Clean up + run_podman stop -t 0 $cid run_podman rm -f $cid } @@ -147,6 +148,7 @@ load helpers run_podman inspect --format "{{(index .Mounts 0).RW}}" $cid is "$output" "true" "inspect data includes image mount source" + run_podman stop -t 0 $cid run_podman rm -f $cid } diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats index 39f439e7b..38c38d671 100644 --- a/test/system/065-cp.bats +++ b/test/system/065-cp.bats @@ -256,6 +256,7 @@ load helpers " # From RUNNING container + local -a destcontainers=() while read id src dest dest_fullname description; do # dest may be "''" for empty table cells if [[ $dest == "''" ]];then @@ -265,26 +266,25 @@ load helpers # To RUNNING container run_podman run -d $IMAGE sleep infinity destcontainer="$output" + destcontainers+=($destcontainer) run_podman cp cpcontainer:$src $destcontainer:"/$dest" run_podman exec $destcontainer cat "/$dest_fullname" is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)" - run_podman kill $destcontainer - run_podman rm -f $destcontainer # To CREATED container run_podman create $IMAGE sleep infinity destcontainer="$output" + destcontainers+=($destcontainer) run_podman cp cpcontainer:$src $destcontainer:"/$dest" run_podman start $destcontainer run_podman exec $destcontainer cat "/$dest_fullname" is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)" - run_podman kill $destcontainer - run_podman rm -f $destcontainer done < <(parse_table "$tests") - run_podman kill cpcontainer - run_podman rm -f cpcontainer + run_podman kill cpcontainer ${destcontainers[@]} + run_podman rm -f cpcontainer ${destcontainers[@]} # From CREATED container + destcontainers=() run_podman create --name cpcontainer --workdir=/srv $cpimage while read id src dest dest_fullname description; do # dest may be "''" for empty table cells @@ -295,23 +295,21 @@ load helpers # To RUNNING container run_podman run -d $IMAGE sleep infinity destcontainer="$output" + destcontainers+=($destcontainer) run_podman cp cpcontainer:$src $destcontainer:"/$dest" run_podman exec $destcontainer cat "/$dest_fullname" is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)" - run_podman kill $destcontainer - run_podman rm -f $destcontainer - # To CREATED container run_podman create $IMAGE sleep infinity destcontainer="$output" + destcontainers+=($destcontainer) run_podman cp cpcontainer:$src $destcontainer:"/$dest" run_podman start $destcontainer run_podman exec $destcontainer cat "/$dest_fullname" is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)" - run_podman kill $destcontainer - run_podman rm -f $destcontainer done < <(parse_table "$tests") - run_podman rm -f cpcontainer + run_podman kill ${destcontainers[@]} + run_podman rm -f cpcontainer ${destcontainers[@]} run_podman rmi -f $cpimage } @@ -496,6 +494,7 @@ load helpers " # From RUNNING container + local -a destcontainers=() while read src dest dest_fullname description; do if [[ $src == "''" ]];then unset src @@ -510,28 +509,27 @@ load helpers # To RUNNING container run_podman run -d $IMAGE sleep infinity destcontainer="$output" + destcontainers+=($destcontainer) run_podman cp cpcontainer:$src $destcontainer:"/$dest" run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1" is "$output" "${randomcontent[0]} ${randomcontent[1]}" "$description" - run_podman kill $destcontainer - run_podman rm -f $destcontainer # To CREATED container run_podman create $IMAGE sleep infinity destcontainer="$output" + destcontainers+=($destcontainer) run_podman cp cpcontainer:$src $destcontainer:"/$dest" run_podman start $destcontainer run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1" is "$output" "${randomcontent[0]} ${randomcontent[1]}" "$description" - run_podman kill $destcontainer - run_podman rm -f $destcontainer done < <(parse_table "$tests") - run_podman kill cpcontainer - run_podman rm -f cpcontainer + run_podman kill cpcontainer ${destcontainers[@]} + run_podman rm -f cpcontainer ${destcontainers[@]} # From CREATED container + destcontainers=() run_podman create --name cpcontainer --workdir=/srv $cpimage while read src dest dest_fullname description; do if [[ $src == "''" ]];then @@ -547,26 +545,25 @@ ${randomcontent[1]}" "$description" # To RUNNING container run_podman run -d $IMAGE sleep infinity destcontainer="$output" + destcontainers+=($destcontainer) run_podman cp cpcontainer:$src $destcontainer:"/$dest" run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1" is "$output" "${randomcontent[0]} ${randomcontent[1]}" "$description" - run_podman kill $destcontainer - run_podman rm -f $destcontainer # To CREATED container run_podman create $IMAGE sleep infinity destcontainer="$output" + destcontainers+=($destcontainer) run_podman start $destcontainer run_podman cp cpcontainer:$src $destcontainer:"/$dest" run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1" is "$output" "${randomcontent[0]} ${randomcontent[1]}" "$description" - run_podman kill $destcontainer - run_podman rm -f $destcontainer done < <(parse_table "$tests") - run_podman rm -f cpcontainer + run_podman kill ${destcontainers[@]} + run_podman rm -f cpcontainer ${destcontainers[@]} run_podman rmi -f $cpimage } diff --git a/test/system/070-build.bats b/test/system/070-build.bats index 0e1396fc6..4e89e299a 100644 --- a/test/system/070-build.bats +++ b/test/system/070-build.bats @@ -956,6 +956,15 @@ EOF run_podman build -t build_test $tmpdir } +@test "podman build build context is a symlink to a directory" { + tmpdir=$PODMAN_TMPDIR/build-test + mkdir -p $tmpdir/target + ln -s target $tmpdir/link + echo FROM $IMAGE > $tmpdir/link/Dockerfile + echo RUN echo hello >> $tmpdir/link/Dockerfile + run_podman build -t build_test $tmpdir/link +} + function teardown() { # A timeout or other error in 'build' can leave behind stale images # that podman can't even see and which will cascade into subsequent diff --git a/test/system/080-pause.bats b/test/system/080-pause.bats index 1eb47dcfb..2314324a9 100644 --- a/test/system/080-pause.bats +++ b/test/system/080-pause.bats @@ -48,6 +48,7 @@ load helpers # would imply that the container never paused. is "$max_delta" "[3456]" "delta t between paused and restarted" + run_podman stop -t 0 $cname run_podman rm -f $cname # Pause/unpause on nonexistent name or id - these should all fail @@ -73,6 +74,7 @@ load helpers is "$output" "$cid" "podman unpause output" run_podman ps --format '{{.ID}} {{.Names}} {{.Status}}' is "$output" "${cid:0:12} $cname Up.*" "podman ps on resumed container" + run_podman stop -t 0 $cname run_podman rm -f $cname run_podman rm -f notrunning } diff --git a/test/system/120-load.bats b/test/system/120-load.bats index f2f9bf4d4..8be9ed5c5 100644 --- a/test/system/120-load.bats +++ b/test/system/120-load.bats @@ -32,7 +32,7 @@ verify_iid_and_name() { echo "I am an invalid file and should cause a podman-load error" > $invalid run_podman 125 load -i $invalid # podman and podman-remote emit different messages; this is a common string - is "$output" ".*payload does not match any of the supported image formats .*" \ + is "$output" ".*payload does not match any of the supported image formats:.*" \ "load -i INVALID fails with expected diagnostic" } @@ -129,7 +129,7 @@ verify_iid_and_name() { @test "podman load - redirect corrupt payload" { run_podman 125 load <<< "Danger, Will Robinson!! This is a corrupt tarball!" is "$output" \ - ".*payload does not match any of the supported image formats .*" \ + ".*payload does not match any of the supported image formats:.*" \ "Diagnostic from 'podman load' unknown/corrupt payload" } diff --git a/test/system/220-healthcheck.bats b/test/system/220-healthcheck.bats index e5a0e7e88..28fe8eb92 100644 --- a/test/system/220-healthcheck.bats +++ b/test/system/220-healthcheck.bats @@ -108,6 +108,7 @@ Log[-1].Output | is "$output" "unhealthy" "output from 'podman healthcheck run'" # Clean up + run_podman stop -t 0 healthcheck_c run_podman rm -f healthcheck_c run_podman rmi healthcheck_i } diff --git a/test/system/270-socket-activation.bats b/test/system/270-socket-activation.bats index 031ba161b..dd439d3ae 100644 --- a/test/system/270-socket-activation.bats +++ b/test/system/270-socket-activation.bats @@ -69,26 +69,36 @@ function teardown() { @test "podman system service - socket activation - no container" { run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping - is "$output" "OK" "podman service responses normally" + is "$output" "OK" "podman service responds normally" } -@test "podman system service - socket activation - exist container " { - run_podman run $IMAGE sleep 90 +@test "podman system service - socket activation - existing container" { + run_podman run -d $IMAGE sleep 90 + cid="$output" + run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping - is "$output" "OK" "podman service responses normally" + is "$output" "OK" "podman service responds normally" + + run_podman stop -t 0 $cid + run_podman rm -f $cid } -@test "podman system service - socket activation - kill rootless pause " { +@test "podman system service - socket activation - kill rootless pause" { if ! is_rootless; then skip "root podman no need pause process" fi - run_podman run $IMAGE sleep 90 + run_podman run -d $IMAGE sleep 90 + cid="$output" + local pause_pid="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid" if [ -f $pause_pid ]; then kill -9 $(cat $pause_pid) 2> /dev/null fi run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping - is "$output" "OK" "podman service responses normally" + is "$output" "OK" "podman service responds normally" + + run_podman stop -t 0 $cid + run_podman rm -f $cid } # vim: filetype=sh diff --git a/test/system/330-corrupt-images.bats b/test/system/330-corrupt-images.bats index eeffff3ec..86da06cb0 100644 --- a/test/system/330-corrupt-images.bats +++ b/test/system/330-corrupt-images.bats @@ -78,7 +78,7 @@ function _corrupt_image_test() { # Run the requested command. Confirm it succeeds, with suitable warnings run_podman $* - is "$output" ".*error determining parent of image.*ignoring the error" \ + is "$output" ".*Failed to determine parent of image.*ignoring the error" \ "$* with missing $what_to_rm" run_podman images -a --noheading diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index ef00d0366..548f2d764 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -415,6 +415,10 @@ load helpers run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").MacAddress}}" mac="$output" + # check network alias for container short id + run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname\").Aliases}}" + is "$output" "\[${cid:0:12}\]" "short container id in network aliases" + run_podman network disconnect $netname $cid # check that we cannot curl (timeout after 3 sec) @@ -443,6 +447,10 @@ load helpers # connect a second network run_podman network connect $netname2 $cid + # check network2 alias for container short id + run_podman inspect $cid --format "{{(index .NetworkSettings.Networks \"$netname2\").Aliases}}" + is "$output" "\[${cid:0:12}\]" "short container id in network aliases" + # curl should work run curl --max-time 3 -s $SERVER/index.txt is "$output" "$random_1" "curl 127.0.0.1:/index.txt should work" diff --git a/test/system/700-play.bats b/test/system/700-play.bats index 2b05cdd84..0785bffdf 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -69,11 +69,15 @@ RELABEL="system_u:object_r:container_file_t:s0" TESTDIR=$PODMAN_TMPDIR/testdir mkdir -p $TESTDIR echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml + run_podman play kube - < $PODMAN_TMPDIR/test.yaml if [ -e /usr/sbin/selinuxenabled -a /usr/sbin/selinuxenabled ]; then run ls -Zd $TESTDIR is "$output" ${RELABEL} "selinux relabel should have happened" fi + + run_podman stop -a -t 0 + run_podman pod stop test_pod run_podman pod rm -f test_pod } @@ -86,6 +90,9 @@ RELABEL="system_u:object_r:container_file_t:s0" run ls -Zd $TESTDIR is "$output" ${RELABEL} "selinux relabel should have happened" fi + + run_podman stop -a -t 0 + run_podman pod stop test_pod run_podman pod rm -f test_pod } @@ -102,12 +109,19 @@ RELABEL="system_u:object_r:container_file_t:s0" infraID="$output" run_podman container inspect --format "{{.HostConfig.NetworkMode}}" $infraID is "$output" "slirp4netns" "network mode slirp4netns is set for the container" + + run_podman stop -a -t 0 + run_podman pod stop test_pod run_podman pod rm -f test_pod + run_podman play kube --network none $PODMAN_TMPDIR/test.yaml run_podman pod inspect --format {{.InfraContainerID}} "${lines[1]}" infraID="$output" run_podman container inspect --format "{{.HostConfig.NetworkMode}}" $infraID is "$output" "none" "network mode none is set for the container" + + run_podman stop -a -t 0 + run_podman pod stop test_pod run_podman pod rm -f test_pod } @@ -149,6 +163,9 @@ _EOF run_podman play kube --start=false $PODMAN_TMPDIR/test.yaml run_podman inspect --format "{{ .Config.User }}" test_pod-test is "$output" bin "expect container within pod to run as the bin user" + + run_podman stop -a -t 0 + run_podman pod stop test_pod run_podman pod rm -f test_pod run_podman rmi -f userimage:latest } diff --git a/vendor/github.com/containers/common/libimage/copier.go b/vendor/github.com/containers/common/libimage/copier.go index 42d3690b9..636b97bfd 100644 --- a/vendor/github.com/containers/common/libimage/copier.go +++ b/vendor/github.com/containers/common/libimage/copier.go @@ -304,7 +304,7 @@ func (r *Runtime) newCopier(options *CopyOptions) (*copier, error) { defaultContainerConfig, err := config.Default() if err != nil { - logrus.Warnf("failed to get container config for copy options: %v", err) + logrus.Warnf("Failed to get container config for copy options: %v", err) } else { c.imageCopyOptions.MaxParallelDownloads = defaultContainerConfig.Engine.ImageParallelCopies } diff --git a/vendor/github.com/containers/common/libimage/filters.go b/vendor/github.com/containers/common/libimage/filters.go index 0cc5cc311..833f940cc 100644 --- a/vendor/github.com/containers/common/libimage/filters.go +++ b/vendor/github.com/containers/common/libimage/filters.go @@ -47,11 +47,11 @@ func filterImages(images []*Image, filters []filterFunc) ([]*Image, error) { // compileImageFilters creates `filterFunc`s for the specified filters. The // required format is `key=value` with the following supported keys: // after, since, before, containers, dangling, id, label, readonly, reference, intermediate -func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([]filterFunc, error) { - logrus.Tracef("Parsing image filters %s", filters) +func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOptions) ([]filterFunc, error) { + logrus.Tracef("Parsing image filters %s", options.Filters) filterFuncs := []filterFunc{} - for _, filter := range filters { + for _, filter := range options.Filters { var key, value string split := strings.SplitN(filter, "=", 2) if len(split) != 2 { @@ -77,11 +77,16 @@ func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([] filterFuncs = append(filterFuncs, filterBefore(img.Created())) case "containers": - containers, err := strconv.ParseBool(value) - if err != nil { - return nil, errors.Wrapf(err, "non-boolean value %q for dangling filter", value) + switch value { + case "false", "true": + case "external": + if options.IsExternalContainerFunc == nil { + return nil, fmt.Errorf("libimage error: external containers filter without callback") + } + default: + return nil, fmt.Errorf("unsupported value %q for containers filter", value) } - filterFuncs = append(filterFuncs, filterContainers(containers)) + filterFuncs = append(filterFuncs, filterContainers(value, options.IsExternalContainerFunc)) case "dangling": dangling, err := strconv.ParseBool(value) @@ -190,13 +195,28 @@ func filterReadOnly(value bool) filterFunc { } // filterContainers creates a container filter for matching the specified value. -func filterContainers(value bool) filterFunc { +func filterContainers(value string, fn IsExternalContainerFunc) filterFunc { return func(img *Image) (bool, error) { ctrs, err := img.Containers() if err != nil { return false, err } - return (len(ctrs) > 0) == value, nil + if value != "external" { + boolValue := value == "true" + return (len(ctrs) > 0) == boolValue, nil + } + + // Check whether all associated containers are external ones. + for _, c := range ctrs { + isExternal, err := fn(c) + if err != nil { + return false, fmt.Errorf("checking if %s is an external container in filter: %w", c, err) + } + if !isExternal { + return isExternal, nil + } + } + return true, nil } } diff --git a/vendor/github.com/containers/common/libimage/image.go b/vendor/github.com/containers/common/libimage/image.go index 8456d5280..00a2d620e 100644 --- a/vendor/github.com/containers/common/libimage/image.go +++ b/vendor/github.com/containers/common/libimage/image.go @@ -2,6 +2,7 @@ package libimage import ( "context" + "fmt" "path/filepath" "sort" "strings" @@ -51,7 +52,7 @@ func (i *Image) reload() error { logrus.Tracef("Reloading image %s", i.ID()) img, err := i.runtime.store.Image(i.ID()) if err != nil { - return errors.Wrap(err, "error reloading image") + return errors.Wrap(err, "reloading image") } i.storageImage = img i.cached.imageSource = nil @@ -232,11 +233,15 @@ func (i *Image) Containers() ([]string, error) { } // removeContainers removes all containers using the image. -func (i *Image) removeContainers(fn RemoveContainerFunc) error { - // Execute the custom removal func if specified. - if fn != nil { +func (i *Image) removeContainers(options *RemoveImagesOptions) error { + if !options.Force && !options.ExternalContainers { + // Nothing to do. + return nil + } + + if options.Force && options.RemoveContainerFunc != nil { logrus.Debugf("Removing containers of image %s with custom removal function", i.ID()) - if err := fn(i.ID()); err != nil { + if err := options.RemoveContainerFunc(i.ID()); err != nil { return err } } @@ -246,6 +251,19 @@ func (i *Image) removeContainers(fn RemoveContainerFunc) error { return err } + if !options.Force && options.ExternalContainers { + // All containers must be external ones. + for _, cID := range containers { + isExternal, err := options.IsExternalContainerFunc(cID) + if err != nil { + return fmt.Errorf("checking if %s is an external container: %w", cID, err) + } + if !isExternal { + return fmt.Errorf("cannot remove container %s: not an external container", cID) + } + } + } + logrus.Debugf("Removing containers of image %s from the local containers storage", i.ID()) var multiE error for _, cID := range containers { @@ -392,11 +410,9 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma return processedIDs, nil } - // Perform the actual removal. First, remove containers if needed. - if options.Force { - if err := i.removeContainers(options.RemoveContainerFunc); err != nil { - return processedIDs, err - } + // Perform the container removal, if needed. + if err := i.removeContainers(options); err != nil { + return processedIDs, err } // Podman/Docker compat: we only report an image as removed if it has @@ -406,7 +422,7 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma if err != nil { // We must be tolerant toward corrupted images. // See containers/podman commit fd9dd7065d44. - logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err) + logrus.Warnf("Failed to determine if an image is a parent: %v, ignoring the error", err) hasChildren = false } @@ -416,7 +432,7 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma if err != nil { // We must be tolerant toward corrupted images. // See containers/podman commit fd9dd7065d44. - logrus.Warnf("error determining parent of image: %v, ignoring the error", err) + logrus.Warnf("Failed to determine parent of image: %v, ignoring the error", err) parent = nil } @@ -440,7 +456,7 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma if err != nil { // See Podman commit fd9dd7065d44: we need to // be tolerant toward corrupted images. - logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err) + logrus.Warnf("Failed to determine if an image is a parent: %v, ignoring the error", err) danglingParent = false } if !danglingParent { @@ -462,7 +478,7 @@ func (i *Image) Tag(name string) error { ref, err := NormalizeName(name) if err != nil { - return errors.Wrapf(err, "error normalizing name %q", name) + return errors.Wrapf(err, "normalizing name %q", name) } if _, isDigested := ref.(reference.Digested); isDigested { @@ -499,7 +515,7 @@ func (i *Image) Untag(name string) error { ref, err := NormalizeName(name) if err != nil { - return errors.Wrapf(err, "error normalizing name %q", name) + return errors.Wrapf(err, "normalizing name %q", name) } // FIXME: this is breaking Podman CI but must be re-enabled once @@ -885,12 +901,12 @@ func getImageID(ctx context.Context, src types.ImageReference, sys *types.System } defer func() { if err := newImg.Close(); err != nil { - logrus.Errorf("failed to close image: %q", err) + logrus.Errorf("Failed to close image: %q", err) } }() imageDigest := newImg.ConfigInfo().Digest if err = imageDigest.Validate(); err != nil { - return "", errors.Wrapf(err, "error getting config info") + return "", errors.Wrapf(err, "getting config info") } return "@" + imageDigest.Encoded(), nil } diff --git a/vendor/github.com/containers/common/libimage/load.go b/vendor/github.com/containers/common/libimage/load.go index 33dc1a22f..f2b57c43a 100644 --- a/vendor/github.com/containers/common/libimage/load.go +++ b/vendor/github.com/containers/common/libimage/load.go @@ -2,7 +2,7 @@ package libimage import ( "context" - "errors" + "fmt" "os" "time" @@ -28,66 +28,69 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ( defer r.writeEvent(&Event{ID: "", Name: path, Time: time.Now(), Type: EventTypeImageLoad}) } - var ( - loadedImages []string - loadError error - ) - if options == nil { options = &LoadOptions{} } - for _, f := range []func() ([]string, error){ + var loadErrors []error + + for _, f := range []func() ([]string, string, error){ // OCI - func() ([]string, error) { + func() ([]string, string, error) { logrus.Debugf("-> Attempting to load %q as an OCI directory", path) ref, err := ociTransport.NewReference(path, "") if err != nil { - return nil, err + return nil, ociTransport.Transport.Name(), err } - return r.copyFromDefault(ctx, ref, &options.CopyOptions) + images, err := r.copyFromDefault(ctx, ref, &options.CopyOptions) + return images, ociTransport.Transport.Name(), err }, // OCI-ARCHIVE - func() ([]string, error) { + func() ([]string, string, error) { logrus.Debugf("-> Attempting to load %q as an OCI archive", path) ref, err := ociArchiveTransport.NewReference(path, "") if err != nil { - return nil, err + return nil, ociArchiveTransport.Transport.Name(), err } - return r.copyFromDefault(ctx, ref, &options.CopyOptions) + images, err := r.copyFromDefault(ctx, ref, &options.CopyOptions) + return images, ociArchiveTransport.Transport.Name(), err }, // DIR - func() ([]string, error) { + func() ([]string, string, error) { logrus.Debugf("-> Attempting to load %q as a Docker dir", path) ref, err := dirTransport.NewReference(path) if err != nil { - return nil, err + return nil, dirTransport.Transport.Name(), err } - return r.copyFromDefault(ctx, ref, &options.CopyOptions) + images, err := r.copyFromDefault(ctx, ref, &options.CopyOptions) + return images, dirTransport.Transport.Name(), err }, // DOCKER-ARCHIVE - func() ([]string, error) { + func() ([]string, string, error) { logrus.Debugf("-> Attempting to load %q as a Docker archive", path) ref, err := dockerArchiveTransport.ParseReference(path) if err != nil { - return nil, err + return nil, dockerArchiveTransport.Transport.Name(), err } - return r.loadMultiImageDockerArchive(ctx, ref, &options.CopyOptions) - }, - - // Give a decent error message if nothing above worked. - func() ([]string, error) { - return nil, errors.New("payload does not match any of the supported image formats (oci, oci-archive, dir, docker-archive)") + images, err := r.loadMultiImageDockerArchive(ctx, ref, &options.CopyOptions) + return images, dockerArchiveTransport.Transport.Name(), err }, } { - loadedImages, loadError = f() - if loadError == nil { - return loadedImages, loadError + loadedImages, transportName, err := f() + if err == nil { + return loadedImages, nil } - logrus.Debugf("Error loading %s: %v", path, loadError) + logrus.Debugf("Error loading %s (%s): %v", path, transportName, err) + loadErrors = append(loadErrors, fmt.Errorf("%s: %v", transportName, err)) + } + + // Give a decent error message if nothing above worked. + loadError := fmt.Errorf("payload does not match any of the supported image formats:") + for _, err := range loadErrors { + loadError = fmt.Errorf("%v\n * %v", loadError, err) } return nil, loadError diff --git a/vendor/github.com/containers/common/libimage/manifests/manifests.go b/vendor/github.com/containers/common/libimage/manifests/manifests.go index 81b5343c0..8d1abfba9 100644 --- a/vendor/github.com/containers/common/libimage/manifests/manifests.go +++ b/vendor/github.com/containers/common/libimage/manifests/manifests.go @@ -125,19 +125,19 @@ func (l *list) SaveToImage(store storage.Store, imageID string, names []string, if err != nil { if created { if _, err2 := store.DeleteImage(img.ID, true); err2 != nil { - logrus.Errorf("error deleting image %q after failing to save manifest for it", img.ID) + logrus.Errorf("Deleting image %q after failing to save manifest for it", img.ID) } } - return "", errors.Wrapf(err, "error saving manifest list to image %q", imageID) + return "", errors.Wrapf(err, "saving manifest list to image %q", imageID) } err = store.SetImageBigData(imageID, instancesData, instancesBytes, nil) if err != nil { if created { if _, err2 := store.DeleteImage(img.ID, true); err2 != nil { - logrus.Errorf("error deleting image %q after failing to save instance locations for it", img.ID) + logrus.Errorf("Deleting image %q after failing to save instance locations for it", img.ID) } } - return "", errors.Wrapf(err, "error saving instance list to image %q", imageID) + return "", errors.Wrapf(err, "saving instance list to image %q", imageID) } return imageID, nil } @@ -200,7 +200,7 @@ func (l *list) Push(ctx context.Context, dest types.ImageReference, options Push } defer func() { if err2 := policyContext.Destroy(); err2 != nil { - logrus.Errorf("error destroying signature policy context: %v", err2) + logrus.Errorf("Destroying signature policy context: %v", err2) } }() diff --git a/vendor/github.com/containers/common/libimage/runtime.go b/vendor/github.com/containers/common/libimage/runtime.go index 42461014d..dabadbec0 100644 --- a/vendor/github.com/containers/common/libimage/runtime.go +++ b/vendor/github.com/containers/common/libimage/runtime.go @@ -2,6 +2,7 @@ package libimage import ( "context" + "fmt" "os" "strings" @@ -306,7 +307,7 @@ func (r *Runtime) lookupImageInLocalStorage(name, candidate string, options *Loo if errors.Cause(err) == os.ErrNotExist { // We must be tolerant toward corrupted images. // See containers/podman commit fd9dd7065d44. - logrus.Warnf("error determining if an image is a manifest list: %v, ignoring the error", err) + logrus.Warnf("Failed to determine if an image is a manifest list: %v, ignoring the error", err) return image, nil } return nil, err @@ -484,10 +485,16 @@ func (r *Runtime) imageReferenceMatchesContext(ref types.ImageReference, options return true, nil } +// IsExternalContainerFunc allows for checking whether the specified container +// is an external one. The definition of an external container can be set by +// callers. +type IsExternalContainerFunc func(containerID string) (bool, error) + // ListImagesOptions allow for customizing listing images. type ListImagesOptions struct { // Filters to filter the listed images. Supported filters are // * after,before,since=image + // * containers=true,false,external // * dangling=true,false // * intermediate=true,false (useful for pruning images) // * id=id @@ -495,6 +502,11 @@ type ListImagesOptions struct { // * readonly=true,false // * reference=name[:tag] (wildcards allowed) Filters []string + // IsExternalContainerFunc allows for checking whether the specified + // container is an external one (when containers=external filter is + // used). The definition of an external container can be set by + // callers. + IsExternalContainerFunc IsExternalContainerFunc } // ListImages lists images in the local container storage. If names are @@ -525,7 +537,7 @@ func (r *Runtime) ListImages(ctx context.Context, names []string, options *ListI var filters []filterFunc if len(options.Filters) > 0 { - compiledFilters, err := r.compileImageFilters(ctx, options.Filters) + compiledFilters, err := r.compileImageFilters(ctx, options) if err != nil { return nil, err } @@ -550,8 +562,17 @@ type RemoveImagesOptions struct { // containers using a specific image. By default, all containers in // the local containers storage will be removed (if Force is set). RemoveContainerFunc RemoveContainerFunc + // IsExternalContainerFunc allows for checking whether the specified + // container is an external one (when containers=external filter is + // used). The definition of an external container can be set by + // callers. + IsExternalContainerFunc IsExternalContainerFunc + // Remove external containers even when Force is false. Requires + // IsExternalContainerFunc to be specified. + ExternalContainers bool // Filters to filter the removed images. Supported filters are // * after,before,since=image + // * containers=true,false,external // * dangling=true,false // * intermediate=true,false (useful for pruning images) // * id=id @@ -581,6 +602,10 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem options = &RemoveImagesOptions{} } + if options.ExternalContainers && options.IsExternalContainerFunc == nil { + return nil, []error{fmt.Errorf("libimage error: cannot remove external containers without callback")} + } + // The logic here may require some explanation. Image removal is // surprisingly complex since it is recursive (intermediate parents are // removed) and since multiple items in `names` may resolve to the @@ -635,7 +660,11 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem } default: - filteredImages, err := r.ListImages(ctx, nil, &ListImagesOptions{Filters: options.Filters}) + options := &ListImagesOptions{ + IsExternalContainerFunc: options.IsExternalContainerFunc, + Filters: options.Filters, + } + filteredImages, err := r.ListImages(ctx, nil, options) if err != nil { appendError(err) return nil, rmErrors diff --git a/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go b/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go index 4f11e4ed2..735d19493 100644 --- a/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go +++ b/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go @@ -97,22 +97,22 @@ func InstallDefault(name string) error { } if err := cmd.Start(); err != nil { if pipeErr := pipe.Close(); pipeErr != nil { - logrus.Errorf("unable to close AppArmor pipe: %q", pipeErr) + logrus.Errorf("Unable to close AppArmor pipe: %q", pipeErr) } return errors.Wrapf(err, "start %s command", apparmorParserPath) } if err := p.generateDefault(apparmorParserPath, pipe); err != nil { if pipeErr := pipe.Close(); pipeErr != nil { - logrus.Errorf("unable to close AppArmor pipe: %q", pipeErr) + logrus.Errorf("Unable to close AppArmor pipe: %q", pipeErr) } if cmdErr := cmd.Wait(); cmdErr != nil { - logrus.Errorf("unable to wait for AppArmor command: %q", cmdErr) + logrus.Errorf("Unable to wait for AppArmor command: %q", cmdErr) } return errors.Wrap(err, "generate default profile into pipe") } if pipeErr := pipe.Close(); pipeErr != nil { - logrus.Errorf("unable to close AppArmor pipe: %q", pipeErr) + logrus.Errorf("Unable to close AppArmor pipe: %q", pipeErr) } return errors.Wrap(cmd.Wait(), "wait for AppArmor command") @@ -252,7 +252,7 @@ func CheckProfileAndLoadDefault(name string) (string, error) { if name != "" { return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name) } else { - logrus.Debug("skipping loading default AppArmor profile (rootless mode)") + logrus.Debug("Skipping loading default AppArmor profile (rootless mode)") return "", nil } } @@ -292,7 +292,7 @@ func CheckProfileAndLoadDefault(name string) (string, error) { if err != nil { return "", errors.Wrapf(err, "install profile %s", name) } - logrus.Infof("successfully loaded AppAmor profile %q", name) + logrus.Infof("Successfully loaded AppAmor profile %q", name) } else { logrus.Infof("AppAmor profile %q is already loaded", name) } diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go index c1f63577a..3b4c7fa04 100644 --- a/vendor/github.com/containers/common/pkg/config/config.go +++ b/vendor/github.com/containers/common/pkg/config/config.go @@ -54,6 +54,8 @@ type Config struct { Containers ContainersConfig `toml:"containers"` // Engine specifies how the container engine based on Engine will run Engine EngineConfig `toml:"engine"` + // Machine specifies configurations of podman machine VMs + Machine MachineConfig `toml:"machine"` // Network section defines the configuration of CNI Plugins Network NetworkConfig `toml:"network"` // Secret section defines configurations for the secret management @@ -281,9 +283,6 @@ type EngineConfig struct { // MachineEnabled indicates if Podman is running in a podman-machine VM MachineEnabled bool `toml:"machine_enabled,omitempty"` - // MachineImage is the image used when creating a podman-machine VM - MachineImage string `toml:"machine_image,omitempty"` - // MultiImageArchive - if true, the container engine allows for storing // archives (e.g., of the docker-archive transport) with multiple // images. By default, Podman creates single-image archives. @@ -490,6 +489,18 @@ type SecretConfig struct { Opts map[string]string `toml:"opts,omitempty"` } +// MachineConfig represents the "machine" TOML config table +type MachineConfig struct { + // Number of CPU's a machine is created with. + CPUs uint64 `toml:"cpus,omitempty"` + // DiskSize is the size of the disk in GB created when init-ing a podman-machine VM + DiskSize uint64 `toml:"disk_size,omitempty"` + // MachineImage is the image used when init-ing a podman-machine VM + Image string `toml:"image,omitempty"` + // Memory in MB a machine is created with. + Memory uint64 `toml:"memory,omitempty"` +} + // Destination represents destination for remote service type Destination struct { // URI, required. Example: ssh://root@example.com:22/run/podman/podman.sock diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf index 7c72ec79f..1d3c003e3 100644 --- a/vendor/github.com/containers/common/pkg/config/containers.conf +++ b/vendor/github.com/containers/common/pkg/config/containers.conf @@ -396,10 +396,6 @@ default_sysctls = [ # #machine_enabled = false -# The image used when creating a podman-machine VM. -# -#machine_image = "testing" - # MultiImageArchive - if true, the container engine allows for storing archives # (e.g., of the docker-archive transport) with multiple images. By default, # Podman creates single-image archives. @@ -559,8 +555,25 @@ default_sysctls = [ [engine.volume_plugins] #testplugin = "/run/podman/plugins/test.sock" -# The [engine.volume_plugins] table MUST be the last entry in this file. +[machine] +# Number of CPU's a machine is created with. +# +#cpus=1 + +# The size of the disk in GB created when init-ing a podman-machine VM. +# +#disk_size=10 + +# The image used when creating a podman-machine VM. +# +#image = "testing" + +# Memory in MB a machine is created with. +# +#memory=2048 + +# The [machine] table MUST be the last entry in this file. # (Unless another table is added) # TOML does not provide a way to end a table other than a further table being -# defined, so every key hereafter will be part of [volume_plugins] and not the +# defined, so every key hereafter will be part of [machine] and not the # main config. diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go index 34d17d72c..e72e1b3e4 100644 --- a/vendor/github.com/containers/common/pkg/config/default.go +++ b/vendor/github.com/containers/common/pkg/config/default.go @@ -208,6 +208,7 @@ func DefaultConfig() (*Config, error) { }, Engine: *defaultEngineConfig, Secrets: defaultSecretConfig(), + Machine: defaultMachineConfig(), }, nil } @@ -219,6 +220,16 @@ func defaultSecretConfig() SecretConfig { } } +// defaultMachineConfig returns the default machine configuration. +func defaultMachineConfig() MachineConfig { + return MachineConfig{ + CPUs: 1, + DiskSize: 10, + Image: "testing", + Memory: 2048, + } +} + // defaultConfigFromMemory returns a default engine configuration. Note that the // config is different for root and rootless. It also parses the storage.conf. func defaultConfigFromMemory() (*EngineConfig, error) { @@ -345,8 +356,6 @@ func defaultConfigFromMemory() (*EngineConfig, error) { // constants. c.LockType = "shm" c.MachineEnabled = false - c.MachineImage = "testing" - c.ChownCopiedFiles = true return c, nil @@ -566,9 +575,3 @@ func (c *Config) MachineEnabled() bool { func (c *Config) RootlessNetworking() string { return c.Containers.RootlessNetworking } - -// MachineImage returns the image to be -// used when creating a podman-machine VM -func (c *Config) MachineImage() string { - return c.Engine.MachineImage -} diff --git a/vendor/github.com/containers/common/pkg/retry/retry.go b/vendor/github.com/containers/common/pkg/retry/retry.go index 8eb2da975..43e3a6688 100644 --- a/vendor/github.com/containers/common/pkg/retry/retry.go +++ b/vendor/github.com/containers/common/pkg/retry/retry.go @@ -30,7 +30,7 @@ func RetryIfNecessary(ctx context.Context, operation func() error, retryOptions if retryOptions.Delay != 0 { delay = retryOptions.Delay } - logrus.Warnf("failed, retrying in %s ... (%d/%d). Error: %v", delay, attempt+1, retryOptions.MaxRetry, err) + logrus.Warnf("Failed, retrying in %s ... (%d/%d). Error: %v", delay, attempt+1, retryOptions.MaxRetry, err) select { case <-time.After(delay): break diff --git a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go index 4b7253b31..6c9321e73 100644 --- a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go +++ b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go @@ -114,13 +114,13 @@ func getMounts(filePath string) []string { file, err := os.Open(filePath) if err != nil { // This is expected on most systems - logrus.Debugf("file %q not found, skipping...", filePath) + logrus.Debugf("File %q not found, skipping...", filePath) return nil } defer file.Close() scanner := bufio.NewScanner(file) if err = scanner.Err(); err != nil { - logrus.Errorf("error reading file %q, %v skipping...", filePath, err) + logrus.Errorf("Reading file %q, %v skipping...", filePath, err) return nil } var mounts []string @@ -128,7 +128,7 @@ func getMounts(filePath string) []string { if strings.HasPrefix(strings.TrimSpace(scanner.Text()), "/") { mounts = append(mounts, scanner.Text()) } else { - logrus.Debugf("skipping unrecognized mount in %v: %q", + logrus.Debugf("Skipping unrecognized mount in %v: %q", filePath, scanner.Text()) } } @@ -176,7 +176,7 @@ func MountsWithUIDGID(mountLabel, containerWorkingDir, mountFile, mountPoint str if _, err := os.Stat(file); err == nil { mounts, err := addSubscriptionsFromMountsFile(file, mountLabel, containerWorkingDir, uid, gid) if err != nil { - logrus.Warnf("error mounting subscriptions, skipping entry in %s: %v", file, err) + logrus.Warnf("Failed to mount subscriptions, skipping entry in %s: %v", file, err) } subscriptionMounts = mounts break @@ -192,7 +192,7 @@ func MountsWithUIDGID(mountLabel, containerWorkingDir, mountFile, mountPoint str switch { case err == nil: if err := addFIPSModeSubscription(&subscriptionMounts, containerWorkingDir, mountPoint, mountLabel, uid, gid); err != nil { - logrus.Errorf("error adding FIPS mode subscription to container: %v", err) + logrus.Errorf("Adding FIPS mode subscription to container: %v", err) } case os.IsNotExist(err): logrus.Debug("/etc/system-fips does not exist on host, not mounting FIPS mode subscription") diff --git a/vendor/github.com/containers/common/pkg/supplemented/supplemented.go b/vendor/github.com/containers/common/pkg/supplemented/supplemented.go index a36c3eda4..196176a1c 100644 --- a/vendor/github.com/containers/common/pkg/supplemented/supplemented.go +++ b/vendor/github.com/containers/common/pkg/supplemented/supplemented.go @@ -83,12 +83,12 @@ func (s *supplementedImageReference) NewImageSource(ctx context.Context, sys *ty if iss != nil { // The composite source has been created. Use its Close method. if err2 := iss.Close(); err2 != nil { - logrus.Errorf("error opening image: %v", err2) + logrus.Errorf("Opening image: %v", err2) } } else if top != nil { // The composite source has not been created, but the top was already opened. Close it. if err2 := top.Close(); err2 != nil { - logrus.Errorf("error opening image: %v", err2) + logrus.Errorf("Closing image: %v", err2) } } } diff --git a/vendor/github.com/containers/common/pkg/sysinfo/sysinfo_linux.go b/vendor/github.com/containers/common/pkg/sysinfo/sysinfo_linux.go index 1935d71f1..6420ba274 100644 --- a/vendor/github.com/containers/common/pkg/sysinfo/sysinfo_linux.go +++ b/vendor/github.com/containers/common/pkg/sysinfo/sysinfo_linux.go @@ -237,7 +237,7 @@ func checkCgroupPids(cgMounts map[string]string, quiet bool) cgroupPids { _, ok := cgMounts["pids"] if !ok { if !quiet { - logrus.Warn("unable to find pids cgroup in mounts") + logrus.Warn("Unable to find pids cgroup in mounts") } return cgroupPids{} } diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index ba4dda5e6..b6ceabce5 100644 --- a/vendor/github.com/containers/common/version/version.go +++ b/vendor/github.com/containers/common/version/version.go @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "0.44.1-dev" +const Version = "0.46.1-dev" diff --git a/vendor/modules.txt b/vendor/modules.txt index 661619f98..1fb03d302 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -97,7 +97,7 @@ github.com/containers/buildah/pkg/rusage github.com/containers/buildah/pkg/sshagent github.com/containers/buildah/pkg/util github.com/containers/buildah/util -# github.com/containers/common v0.44.1-0.20210921143342-f2f10e650c73 +# github.com/containers/common v0.46.1-0.20210928081721-32e20295f1c6 github.com/containers/common/libimage github.com/containers/common/libimage/manifests github.com/containers/common/pkg/apparmor |