diff options
315 files changed, 5182 insertions, 1931 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: @@ -23,6 +23,7 @@ export GOPROXY=https://proxy.golang.org GO ?= go +GO_LDFLAGS:= $(shell if $(GO) version|grep -q gccgo ; then echo "-gccgoflags"; else echo "-ldflags"; fi) GOCMD = CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) $(GO) COVERAGE_PATH ?= .coverage DESTDIR ?= @@ -244,11 +245,11 @@ gofmt: ## Verify the source code gofmt .PHONY: test/checkseccomp/checkseccomp test/checkseccomp/checkseccomp: .gopathok $(wildcard test/checkseccomp/*.go) - $(GOCMD) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ ./test/checkseccomp + $(GOCMD) build $(BUILDFLAGS) $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ ./test/checkseccomp .PHONY: test/testvol/testvol test/testvol/testvol: .gopathok $(wildcard test/testvol/*.go) - $(GOCMD) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -o $@ ./test/testvol + $(GOCMD) build $(BUILDFLAGS) $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' -o $@ ./test/testvol .PHONY: volume-plugin-test-image volume-plugin-test-img: @@ -256,7 +257,7 @@ volume-plugin-test-img: .PHONY: test/goecho/goecho test/goecho/goecho: .gopathok $(wildcard test/goecho/*.go) - $(GOCMD) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -o $@ ./test/goecho + $(GOCMD) build $(BUILDFLAGS) $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' -o $@ ./test/goecho test/version/version: .gopathok version/version.go $(GO) build -o $@ ./test/version/ @@ -299,7 +300,7 @@ ifeq (,$(findstring systemd,$(BUILDTAGS))) endif $(GOCMD) build \ $(BUILDFLAGS) \ - -ldflags '$(LDFLAGS_PODMAN)' \ + $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' \ -tags "$(BUILDTAGS)" \ -o $@ ./cmd/podman @@ -310,14 +311,14 @@ $(SRCBINDIR): $(SRCBINDIR)/podman$(BINSFX): $(SRCBINDIR) .gopathok $(SOURCES) go.mod go.sum $(GOCMD) build \ $(BUILDFLAGS) \ - -ldflags '$(LDFLAGS_PODMAN)' \ + $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' \ -tags "${REMOTETAGS}" \ -o $@ ./cmd/podman $(SRCBINDIR)/podman-remote-static: $(SRCBINDIR) .gopathok $(SOURCES) go.mod go.sum $(GOCMD) build \ $(BUILDFLAGS) \ - -ldflags '$(LDFLAGS_PODMAN_STATIC)' \ + $(GO_LDFLAGS) '$(LDFLAGS_PODMAN_STATIC)' \ -tags "${REMOTETAGS}" \ -o $@ ./cmd/podman @@ -372,7 +373,7 @@ bin/podman.cross.%: .gopathok CGO_ENABLED=0 \ $(GO) build \ $(BUILDFLAGS) \ - -ldflags '$(LDFLAGS_PODMAN)' \ + $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' \ -tags '$(BUILDTAGS_CROSS)' \ -o "$@" ./cmd/podman @@ -411,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 @@ -431,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 @@ -671,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 @@ -758,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 @@ -808,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 @@ -5,7 +5,7 @@ Podman (the POD MANager) is a tool for managing containers and images, volumes mounted into those containers, and pods made from groups of containers. Podman is based on libpod, a library for container lifecycle management that is also contained in this repository. The libpod library provides APIs for managing containers, pods, container images, and volumes. -* [Latest Version: 3.3.1](https://github.com/containers/podman/releases/latest) +* [Latest Version: 3.4.0](https://github.com/containers/podman/releases/latest) * Latest Remote client for Windows * Latest Remote client for macOS * Latest Static Remote client for Linux diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b9b94dbb3..ef48df291 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,102 @@ # Release Notes +## 3.4.0 +### Features +- Pods now support init containers! Init containers are containers which run before the rest of the pod starts. There are two types of init containers: "always", which always run before the pod is started, and "once", which only run the first time the pod starts and are subsequently removed. They can be added using the `podman create` command's `--init-ctr` option. +- Support for init containers has also been added to `podman play kube` and `podman generate kube` - init containers contained in Kubernetes YAML will be created as Podman init containers, and YAML generated by Podman will include any init containers created. +- The `podman play kube` command now supports building images. If the `--build` option is given and a directory with the name of the specified image exists in the current working directory and contains a valid Containerfile or Dockerfile, the image will be built and used for the container. +- The `podman play kube` command now supports a new option, `--teardown`, which removes any pods and containers created by the given Kubernetes YAML. +- The `podman generate kube` command now generates annotations for SELinux mount options on volume (`:z` and `:Z`) that are respected by the `podman play kube` command. +- A new command has been added, `podman pod logs`, to return logs for all containers in a pod at the same time. +- Two new commands have been added, `podman volume export` (to export a volume to a tar file) and `podman volume import`) (to populate a volume from a given tar file). +- The `podman auto-update` command now supports simple rollbacks. If a container fails to start after an automatic update, it will be rolled back to the previous image and restarted again. +- Pods now share their user namespace by default, and the `podman pod create` command now supports the `--userns` option. This allows rootless pods to be created with the `--userns=keep-id` option. +- The `podman pod ps` command now supports a new filter with its `--filter` option, `until`, which returns pods created before a given timestamp. +- The `podman image scp` command has been added. This command allows images to be transferred between different hosts. +- The `podman stats` command supports a new option, `--interval`, to specify the amount of time before the information is refreshed. +- The `podman inspect` command now includes ports exposed (but not published) by containers (e.g. ports from `--expose` when `--publish-all` is not specified). +- The `podman inspect` command now has a new boolean value, `Checkpointed`, which indicates that a container was stopped as a result of a `podman container checkpoint` operation. +- Volumes created by `podman volume create` now support setting quotas when run atop XFS. The `size` and `inode` options allow the maximum size and maximum number of inodes consumed by a volume to be limited. +- The `podman info` command now outputs information on what log drivers, network drivers, and volume plugins are available for use ([#11265](https://github.com/containers/podman/issues/11265)). +- The `podman info` command now outputs the current log driver in use, and the variant and codename of the distribution in use. +- The parameters of the VM created by `podman machine init` (amount of disk space, memory, CPUs) can now be set in `containers.conf`. +- The `podman machine ls` command now shows additional information (CPUs, memory, disk size) about VMs managed by `podman machine`. +- The `podman ps` command now includes healthcheck status in container state for containers that have healthchecks ([#11527](https://github.com/containers/podman/issues/11527)). + +### Changes +- The `podman build` command has a new alias, `podman buildx`, to improve compatibility with Docker. We have already added support for many `docker buildx` flags to `podman build` and aim to continue to do so. +- Cases where Podman is run without a user session or a writable temporary files directory will now produce better error messages. +- The default log driver has been changed from `file` to `journald`. The `file` driver did not properly support log rotation, so this should lead to a better experience. If journald is not available on the system, Podman will automatically revert to the `file`. +- Podman no longer depends on `ip` for removing networks ([#11403](https://github.com/containers/podman/issues/11403)). +- The deprecated `--macvlan` flag to `podman network create` now warns when it is used. It will be removed entirely in the Podman 4.0 release. +- The `podman machine start` command now prints a message when the VM is successfully started. +- The `podman stats` command can now be used on containers that are paused. +- The `podman unshare` command will now return the exit code of the command that was run in the user namespace (assuming the command was successfully run). +- Successful healthchecks will no longer add a `healthy` line to the system log to reduce log spam. +- As a temporary workaround for a lack of shortname prompts in the Podman remote client, VMs created by `podman machine` now default to only using the `docker.io` registry. + +### Bugfixes +- Fixed a bug where whitespace in the definition of sysctls (particularly default sysctls specified in `containers.conf`) would cause them to be parsed incorrectly. +- Fixed a bug where the Windows remote client improperly validated volume paths ([#10900](https://github.com/containers/podman/issues/10900)). +- Fixed a bug where the first line of logs from a container run with the `journald` log driver could be skipped. +- Fixed a bug where images created by `podman commit` did not include ports exposed by the container. +- Fixed a bug where the `podman auto-update` command would ignore the `io.containers.autoupdate.authfile` label when pulling images ([#11171](https://github.com/containers/podman/issues/11171)). +- Fixed a bug where the `--workdir` option to `podman create` and `podman run` could not be set to a directory where a volume was mounted ([#11352](https://github.com/containers/podman/issues/11352)). +- Fixed a bug where systemd socket-activation did not properly work with systemd-managed Podman containers ([#10443](https://github.com/containers/podman/issues/10443)). +- Fixed a bug where environment variable secrets added to a container were not available to exec sessions launched in the container. +- Fixed a bug where rootless containers could fail to start the `rootlessport` port-forwarding service when `XDG_RUNTIME_DIR` was set to a long path. +- Fixed a bug where arguments to the `--systemd` option to `podman create` and `podman run` were case-sensitive ([#11387](https://github.com/containers/podman/issues/11387)). +- Fixed a bug where the `podman manifest rm` command would also remove images referenced by the manifest, not just the manifest itself ([#11344](https://github.com/containers/podman/issues/11344)). +- Fixed a bug where the Podman remote client on OS X would not function properly if the `TMPDIR` environment variable was not set ([#11418](https://github.com/containers/podman/issues/11418)). +- Fixed a bug where the `/etc/hosts` file was not guaranteed to contain an entry for `localhost` (this is still not guaranteed if `--net=host` is used; such containers will exactly match the host's `/etc/hosts`) ([#11411](https://github.com/containers/podman/issues/11411)). +- Fixed a bug where the `podman machine start` command could print warnings about unsupported CPU features ([#11421](https://github.com/containers/podman/issues/11421)). +- Fixed a bug where the `podman info` command could segfault when accessing cgroup information. +- Fixed a bug where the `podman logs -f` command could hang when a container exited ([#11461](https://github.com/containers/podman/issues/11461)). +- Fixed a bug where the `podman generate systemd` command could not be used on containers that specified a restart policy ([#11438](https://github.com/containers/podman/issues/11438)). +- Fixed a bug where the remote Podman client's `podman build` command would fail to build containers if the UID and GID on the client were higher than 65536 ([#11474](https://github.com/containers/podman/issues/11474)). +- Fixed a bug where the remote Podman client's `podman build` command would fail to build containers if the context directory was a symlink ([#11732](https://github.com/containers/podman/issues/11732)). +- Fixed a bug where the `--network` flag to `podman play kube` was not properly parsed when a non-bridge network configuration was specified. +- Fixed a bug where the `podman inspect` command could error when the container being inspected was removed as it was being inspected ([#11392](https://github.com/containers/podman/issues/11392)). +- Fixed a bug where the `podman play kube` command ignored the default pod infra image specified in `containers.conf`. +- Fixed a bug where the `--format` option to `podman inspect` was nonfunctional under some circumstances ([#8785](https://github.com/containers/podman/issues/8785)). +- Fixed a bug where the remote Podman client's `podman run` and `podman exec` commands could skip a byte of output every 8192 bytes ([#11496](https://github.com/containers/podman/issues/11496)). +- Fixed a bug where the `podman stats` command would print nonsensical results if the container restarted while it was running ([#11469](https://github.com/containers/podman/issues/11469)). +- Fixed a bug where the remote Podman client would error when STDOUT was redirected on a Windows client ([#11444](https://github.com/containers/podman/issues/11444)). +- Fixed a bug where the `podman run` command could return 0 when the application in the container exited with 125 ([#11540](https://github.com/containers/podman/issues/11540)). +- Fixed a bug where containers with `--restart=always` set using the rootlessport port-forwarding service could not be restarted automatically. +- Fixed a bug where the `--cgroups=split` option to `podman create` and `podman run` was silently discarded if the container was part of a pod. +- Fixed a bug where the `podman container runlabel` command could fail if the image name given included a tag. +- Fixed a bug where Podman could add an extra `127.0.0.1` entry to `/etc/hosts` under some circumstances ([#11596](https://github.com/containers/podman/issues/11596)). +- Fixed a bug where the remote Podman client's `podman untag` command did not properly handle tags including a digest ([#11557](https://github.com/containers/podman/issues/11557)). +- Fixed a bug where the `--format` option to `podman ps` did not properly support the `table` argument for tabular output. +- Fixed a bug where the `--filter` option to `podman ps` did not properly handle filtering by healthcheck status ([#11687](https://github.com/containers/podman/issues/11687)). +- Fixed a bug where the `podman run` and `podman start --attach` commands could race when retrieving the exit code of a container that had already been removed resulting in an error (e.g. by an external `podman rm -f`) ([#11633](https://github.com/containers/podman/issues/11633)). +- Fixed a bug where the `podman generate kube` command would add default environment variables to generated YAML. +- Fixed a bug where the `podman generate kube` command would add the default CMD from the image to generated YAML ([#11672](https://github.com/containers/podman/issues/11672)). +- Fixed a bug where the `podman rm --storage` command could fail to remove containers under some circumstances ([#11207](https://github.com/containers/podman/issues/11207)). +- Fixed a bug where the `podman machine ssh` command could fail when run on Linux ([#11731](https://github.com/containers/podman/issues/11731)). +- Fixed a bug where the `podman stop` command would error when used on a container that was already stopped ([#11740](https://github.com/containers/podman/issues/11740)). +- Fixed a bug where renaming a container in a pod using the `podman rename` command, then removing the pod using `podman pod rm`, could cause Podman to believe the new name of the container was permanently in use, despite the container being removed ([#11750](https://github.com/containers/podman/issues/11750)). + +### API +- The Libpod Pull endpoint for Images now has a new query parameter, `quiet`, which (when set to true) suppresses image pull progress reports ([#10612](https://github.com/containers/podman/issues/10612)). +- The Compat Events endpoint now includes several deprecated fields from the Docker v1.21 API for improved compatibility with older clients. +- The Compat List and Inspect endpoints for Images now prefix image IDs with `sha256:` for improved Docker compatibility ([#11623](https://github.com/containers/podman/issues/11623)). +- The Compat Create endpoint for Containers now properly sets defaults for healthcheck-related fields ([#11225](https://github.com/containers/podman/issues/11225)). +- The Compat Create endpoint for Containers now supports volume options provided by the `Mounts` field ([#10831](https://github.com/containers/podman/issues/10831)). +- The Compat List endpoint for Secrets now supports a new query parameter, `filter`, which allows returned results to be filtered. +- The Compat Auth endpoint now returns the correct response code (500 instead of 400) when logging into a registry fails. +- The Version endpoint now includes information about the OCI runtime and Conmon in use ([#11227](https://github.com/containers/podman/issues/11227)). +- Fixed a bug where the X-Registry-Config header was not properly handled, leading to errors when pulling images ([#11235](https://github.com/containers/podman/issues/11235)). +- Fixed a bug where invalid query parameters could cause a null pointer dereference when creating error messages. +- Logging of API requests and responses at trace level has been greatly improved, including the addition of an X-Reference-Id header to correlate requests and responses ([#10053](https://github.com/containers/podman/issues/10053)). + +### Misc +- Updated Buildah to v1.23.0 +- Updated the containers/storage library to v1.36.0 +- Updated the containers/image library to v5.16.0 +- Updated the containers/common library to v0.44.0 + ## 3.3.1 ### Bugfixes - Fixed a bug where unit files created by `podman generate systemd` could not cleanup shut down containers when stopped by `systemctl stop` ([#11304](https://github.com/containers/podman/issues/11304)). diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index 2ea5fa10f..ea453a331 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -194,21 +194,14 @@ func getImages(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellComp } else { // suggested "registry.fedoraproject.org/f29/httpd:latest" as // - "registry.fedoraproject.org/f29/httpd:latest" - // - "registry.fedoraproject.org/f29/httpd" // - "f29/httpd:latest" - // - "f29/httpd" // - "httpd:latest" - // - "httpd" paths := strings.Split(repo, "/") for i := range paths { suggestionWithTag := strings.Join(paths[i:], "/") if strings.HasPrefix(suggestionWithTag, toComplete) { suggestions = append(suggestions, suggestionWithTag) } - suggestionWithoutTag := strings.SplitN(strings.SplitN(suggestionWithTag, ":", 2)[0], "@", 2)[0] - if strings.HasPrefix(suggestionWithoutTag, toComplete) { - suggestions = append(suggestions, suggestionWithoutTag) - } } } } @@ -778,10 +771,13 @@ func AutocompleteImageVolume(cmd *cobra.Command, args []string, toComplete strin } // AutocompleteLogDriver - Autocomplete log-driver options. -// -> "journald", "none", "k8s-file" +// -> "journald", "none", "k8s-file", "passthrough" func AutocompleteLogDriver(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { // don't show json-file logDrivers := []string{define.JournaldLogging, define.NoLogging, define.KubernetesLogging} + if !registry.IsRemote() { + logDrivers = append(logDrivers, define.PassthroughLogging) + } return logDrivers, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 63d5477e4..e714b6785 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -413,7 +413,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, pidsLimitFlagName := "pids-limit" createFlags.Int64( pidsLimitFlagName, pidsLimit(), - "Tune container pids limit (set 0 for unlimited, -1 for server defaults)", + "Tune container pids limit (set -1 for unlimited)", ) _ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone) diff --git a/cmd/podman/containers/cleanup.go b/cmd/podman/containers/cleanup.go index 98706c575..a3d339358 100644 --- a/cmd/podman/containers/cleanup.go +++ b/cmd/podman/containers/cleanup.go @@ -80,7 +80,7 @@ func cleanup(cmd *cobra.Command, args []string) error { // is via syslog. // As such, we need to logrus.Errorf our errors to ensure they // are properly printed if --syslog is set. - logrus.Errorf("Error running container cleanup: %v", err) + logrus.Errorf("Running container cleanup: %v", err) return err } for _, r := range responses { @@ -89,15 +89,15 @@ func cleanup(cmd *cobra.Command, args []string) error { continue } if r.RmErr != nil { - logrus.Errorf("Error removing container: %v", r.RmErr) + logrus.Errorf("Removing container: %v", r.RmErr) errs = append(errs, r.RmErr) } if r.RmiErr != nil { - logrus.Errorf("Error removing image: %v", r.RmiErr) + logrus.Errorf("Removing image: %v", r.RmiErr) errs = append(errs, r.RmiErr) } if r.CleanErr != nil { - logrus.Errorf("Error cleaning up container: %v", r.CleanErr) + logrus.Errorf("Cleaning up container: %v", r.CleanErr) errs = append(errs, r.CleanErr) } } diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index 8b27de53e..bfeeb7ebe 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -19,6 +19,7 @@ import ( "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgenutil" "github.com/containers/podman/v3/pkg/util" + "github.com/mattn/go-isatty" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -161,7 +162,9 @@ func create(cmd *cobra.Command, args []string) error { } } - fmt.Println(report.Id) + if cliVals.LogDriver != define.PassthroughLogging { + fmt.Println(report.Id) + } return nil } @@ -188,6 +191,14 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra vals.UserNS = "private" } } + if cliVals.LogDriver == define.PassthroughLogging { + if isatty.IsTerminal(0) || isatty.IsTerminal(1) || isatty.IsTerminal(2) { + return vals, errors.New("the '--log-driver passthrough' option cannot be used on a TTY") + } + if registry.IsRemote() { + return vals, errors.New("the '--log-driver passthrough' option is not supported in remote mode") + } + } if !isInfra { if c.Flag("shm-size").Changed { @@ -224,6 +235,10 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra if c.Flags().Changed("pids-limit") { val := c.Flag("pids-limit").Value.String() + // Convert -1 to 0, so that -1 maps to unlimited pids limit + if val == "-1" { + val = "0" + } pidsLimit, err := strconv.ParseInt(val, 10, 32) if err != nil { return vals, err diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go index afb8edd91..9687cd5bd 100644 --- a/cmd/podman/containers/ps.go +++ b/cmd/podman/containers/ps.go @@ -375,6 +375,10 @@ func (l psReporter) State() string { // Status is a synonym for State() func (l psReporter) Status() string { + hc := l.ListContainer.Status + if hc != "" { + return l.State() + " (" + hc + ")" + } return l.State() } diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go index d14961829..071708b76 100644 --- a/cmd/podman/containers/run.go +++ b/cmd/podman/containers/run.go @@ -158,8 +158,13 @@ func run(cmd *cobra.Command, args []string) error { runOpts.InputStream = nil } + passthrough := cliVals.LogDriver == define.PassthroughLogging + // If attach is set, clear stdin/stdout/stderr and only attach requested if cmd.Flag("attach").Changed { + if passthrough { + return errors.Wrapf(define.ErrInvalidArg, "cannot specify --attach with --log-driver=passthrough") + } runOpts.OutputStream = nil runOpts.ErrorStream = nil if !cliVals.Interactive { @@ -179,6 +184,7 @@ func run(cmd *cobra.Command, args []string) error { } } } + cliVals.PreserveFDs = runOpts.PreserveFDs s := specgen.NewSpecGenerator(imageName, cliVals.RootFS) if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil { @@ -200,7 +206,7 @@ func run(cmd *cobra.Command, args []string) error { return err } - if runOpts.Detach { + if runOpts.Detach && !passthrough { fmt.Println(report.Id) return nil } 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/build.go b/cmd/podman/images/build.go index 642da0c83..4c563ed27 100644 --- a/cmd/podman/images/build.go +++ b/cmd/podman/images/build.go @@ -131,7 +131,7 @@ func buildFlags(cmd *cobra.Command) { // --pull flag flag := budFlags.Lookup("pull") if err := flag.Value.Set("true"); err != nil { - logrus.Errorf("unable to set --pull to true: %v", err) + logrus.Errorf("Unable to set --pull to true: %v", err) } flag.DefValue = "true" flag.Usage = "Always attempt to pull the image (errors are fatal)" @@ -148,13 +148,13 @@ func buildFlags(cmd *cobra.Command) { useLayersVal := useLayers() buildOpts.Layers = useLayersVal == "true" if err := flag.Value.Set(useLayersVal); err != nil { - logrus.Errorf("unable to set --layers to %v: %v", useLayersVal, err) + logrus.Errorf("Unable to set --layers to %v: %v", useLayersVal, err) } flag.DefValue = useLayersVal // --force-rm flag flag = layerFlags.Lookup("force-rm") if err := flag.Value.Set("true"); err != nil { - logrus.Errorf("unable to set --force-rm to true: %v", err) + logrus.Errorf("Unable to set --force-rm to true: %v", err) } flag.DefValue = "true" flags.AddFlagSet(&layerFlags) @@ -162,7 +162,7 @@ func buildFlags(cmd *cobra.Command) { // FromAndBud flags fromAndBudFlags, err := buildahCLI.GetFromAndBudFlags(&buildOpts.FromAndBudResults, &buildOpts.UserNSResults, &buildOpts.NameSpaceResults) if err != nil { - logrus.Errorf("error setting up build flags: %v", err) + logrus.Errorf("Setting up build flags: %v", err) os.Exit(1) } // --http-proxy flag @@ -171,7 +171,7 @@ func buildFlags(cmd *cobra.Command) { flag = fromAndBudFlags.Lookup("http-proxy") buildOpts.HTTPProxy = false if err := flag.Value.Set("false"); err != nil { - logrus.Errorf("unable to set --https-proxy to %v: %v", false, err) + logrus.Errorf("Unable to set --https-proxy to %v: %v", false, err) } flag.DefValue = "false" } @@ -184,7 +184,7 @@ func buildFlags(cmd *cobra.Command) { flag = flags.Lookup("isolation") buildOpts.Isolation = buildahDefine.OCI if err := flag.Value.Set(buildahDefine.OCI); err != nil { - logrus.Errorf("unable to set --isolation to %v: %v", buildahDefine.OCI, err) + logrus.Errorf("Unable to set --isolation to %v: %v", buildahDefine.OCI, err) } flag.DefValue = buildahDefine.OCI _ = flags.MarkHidden("disable-content-trust") @@ -228,7 +228,7 @@ func build(cmd *cobra.Command, args []string) error { // Delete it later. defer func() { if err = os.RemoveAll(tempDir); err != nil { - logrus.Errorf("error removing temporary directory %q: %v", contextDir, err) + logrus.Errorf("Removing temporary directory %q: %v", contextDir, err) } }() contextDir = filepath.Join(tempDir, subDir) diff --git a/cmd/podman/images/prune.go b/cmd/podman/images/prune.go index 8a484495a..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" @@ -80,7 +81,7 @@ func prune(cmd *cobra.Command, args []string) error { func createPruneWarningMessage(pruneOpts entities.ImagePruneOptions) string { question := "Are you sure you want to continue? [y/N] " if pruneOpts.All { - return "WARNING! This will remove all images without at least one container associated to them.\n" + question + return "WARNING! This command removes all images without at least one container associated with them.\n" + question } - return "WARNING! This will remove all dangling images.\n" + question + return "WARNING! This command removes all dangling images.\n" + question } diff --git a/cmd/podman/images/save.go b/cmd/podman/images/save.go index 19dadb2ad..4f45cb912 100644 --- a/cmd/podman/images/save.go +++ b/cmd/podman/images/save.go @@ -84,6 +84,8 @@ func saveFlags(cmd *cobra.Command) { flags.BoolVar(&saveOpts.Compress, "compress", false, "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)") + flags.BoolVar(&saveOpts.OciAcceptUncompressedLayers, "uncompressed", false, "Accept uncompressed layers when copying OCI images") + formatFlagName := "format" flags.StringVar(&saveOpts.Format, formatFlagName, define.V2s2Archive, "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-archive, docker-dir (directory with v2s2 manifest type)") _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteImageSaveFormat) diff --git a/cmd/podman/images/utils_linux.go b/cmd/podman/images/utils_linux.go index 5521abab4..f7c159415 100644 --- a/cmd/podman/images/utils_linux.go +++ b/cmd/podman/images/utils_linux.go @@ -24,7 +24,7 @@ func setupPipe() (string, func() <-chan error, error) { err = unix.Mkfifo(pipePath, 0600) if err != nil { if e := os.RemoveAll(pipeDir); e != nil { - logrus.Errorf("error removing named pipe: %q", e) + logrus.Errorf("Removing named pipe: %q", e) } return "", nil, errors.Wrapf(err, "error creating named pipe") } @@ -40,7 +40,7 @@ func setupPipe() (string, func() <-chan error, error) { }() return pipePath, func() <-chan error { if e := os.RemoveAll(pipeDir); e != nil { - logrus.Errorf("error removing named pipe: %q", e) + logrus.Errorf("Removing named pipe: %q", e) } return errc }, nil diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go index 4c7fa33a4..64b586388 100644 --- a/cmd/podman/inspect/inspect.go +++ b/cmd/podman/inspect/inspect.go @@ -220,7 +220,7 @@ func (i *inspector) inspect(namesOrIDs []string) error { err = printTmpl(tmpType, row, data) } if err != nil { - logrus.Errorf("Error printing inspect output: %v", err) + logrus.Errorf("Printing inspect output: %v", err) } if len(errs) > 0 { 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/machine/list.go b/cmd/podman/machine/list.go index d4360bb9b..95b7d860f 100644 --- a/cmd/podman/machine/list.go +++ b/cmd/podman/machine/list.go @@ -3,13 +3,16 @@ package machine import ( + "encoding/json" "os" "sort" + "strconv" "time" "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/config" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v3/cmd/podman/common" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/pkg/machine" @@ -40,10 +43,15 @@ type listFlagType struct { } type machineReporter struct { - Name string - Created string - LastUp string - VMType string + Name string + Default bool + Created string + Running bool + LastUp string + VMType string + CPUs uint64 + Memory string + DiskSize string } func init() { @@ -54,8 +62,8 @@ func init() { flags := lsCmd.Flags() formatFlagName := "format" - flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\n", "Format volume output using Go template") - _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, completion.AutocompleteNone) + flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n", "Format volume output using JSON or a Go template") + _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(machineReporter{})) flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers") } @@ -75,6 +83,21 @@ func list(cmd *cobra.Command, args []string) error { sort.Slice(listResponse, func(i, j int) bool { return listResponse[i].Running }) + + if report.IsJSON(listFlag.format) { + machineReporter, err := toMachineFormat(listResponse) + if err != nil { + return err + } + + b, err := json.Marshal(machineReporter) + if err != nil { + return err + } + os.Stdout.Write(b) + return nil + } + machineReporter, err := toHumanFormat(listResponse) if err != nil { return err @@ -85,8 +108,11 @@ func list(cmd *cobra.Command, args []string) error { func outputTemplate(cmd *cobra.Command, responses []*machineReporter) error { headers := report.Headers(machineReporter{}, map[string]string{ - "LastUp": "LAST UP", - "VmType": "VM TYPE", + "LastUp": "LAST UP", + "VmType": "VM TYPE", + "CPUs": "CPUS", + "Memory": "MEMORY", + "DiskSize": "DISK SIZE", }) row := report.NormalizeFormat(listFlag.format) @@ -115,6 +141,42 @@ func outputTemplate(cmd *cobra.Command, responses []*machineReporter) error { return tmpl.Execute(w, responses) } +func strTime(t time.Time) string { + iso, err := t.MarshalText() + if err != nil { + return "" + } + return string(iso) +} + +func strUint(u uint64) string { + return strconv.FormatUint(u, 10) +} + +func toMachineFormat(vms []*machine.ListResponse) ([]*machineReporter, error) { + cfg, err := config.ReadCustomConfig() + if err != nil { + return nil, err + } + + machineResponses := make([]*machineReporter, 0, len(vms)) + for _, vm := range vms { + response := new(machineReporter) + response.Default = vm.Name == cfg.Engine.ActiveService + response.Name = vm.Name + response.Running = vm.Running + response.LastUp = strTime(vm.LastUp) + response.Created = strTime(vm.CreatedAt) + response.VMType = vm.VMType + response.CPUs = vm.CPUs + response.Memory = strUint(vm.Memory * units.MiB) + response.DiskSize = strUint(vm.DiskSize * units.GiB) + + machineResponses = append(machineResponses, response) + } + return machineResponses, nil +} + func toHumanFormat(vms []*machine.ListResponse) ([]*machineReporter, error) { cfg, err := config.ReadCustomConfig() if err != nil { @@ -136,6 +198,9 @@ func toHumanFormat(vms []*machine.ListResponse) ([]*machineReporter, error) { } response.Created = units.HumanDuration(time.Since(vm.CreatedAt)) + " ago" response.VMType = vm.VMType + response.CPUs = vm.CPUs + response.Memory = units.HumanSize(float64(vm.Memory) * units.MiB) + response.DiskSize = units.HumanSize(float64(vm.DiskSize) * units.GiB) humanResponses = append(humanResponses, response) } 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/registry/config.go b/cmd/podman/registry/config.go index 50e488b02..b512ba341 100644 --- a/cmd/podman/registry/config.go +++ b/cmd/podman/registry/config.go @@ -89,12 +89,7 @@ func newPodmanConfig() { // use for the containers.conf configuration file. func setXdgDirs() error { if !rootless.IsRootless() { - // unset XDG_RUNTIME_DIR for root - // Sometimes XDG_RUNTIME_DIR is set to /run/user/0 sometimes it is unset, - // the inconsistency is causing issues for the dnsname plugin. - // It is already set to an empty string for conmon so lets do the same - // for podman. see #10806 and #10745 - return os.Unsetenv("XDG_RUNTIME_DIR") + return nil } // Setup XDG_RUNTIME_DIR diff --git a/cmd/podman/root.go b/cmd/podman/root.go index 02e6dcd27..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()) @@ -175,7 +180,7 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { // Hard code TMPDIR functions to use /var/tmp, if user did not override if _, ok := os.LookupEnv("TMPDIR"); !ok { if tmpdir, err := cfg.ImageCopyTmpDir(); err != nil { - logrus.Warnf("failed to retrieve default tmp dir: %s", err.Error()) + logrus.Warnf("Failed to retrieve default tmp dir: %s", err.Error()) } else { os.Setenv("TMPDIR", tmpdir) } @@ -313,7 +318,7 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { pFlags := cmd.PersistentFlags() if registry.IsRemote() { if err := lFlags.MarkHidden("remote"); err != nil { - logrus.Warnf("unable to mark --remote flag as hidden: %s", err.Error()) + logrus.Warnf("Unable to mark --remote flag as hidden: %s", err.Error()) } opts.Remote = true } else { @@ -387,7 +392,7 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { "trace", } { if err := pFlags.MarkHidden(f); err != nil { - logrus.Warnf("unable to mark %s flag as hidden: %s", f, err.Error()) + logrus.Warnf("Unable to mark %s flag as hidden: %s", f, err.Error()) } } } diff --git a/cmd/podman/system/prune.go b/cmd/podman/system/prune.go index e09e2d5e5..5565ea2f9 100644 --- a/cmd/podman/system/prune.go +++ b/cmd/podman/system/prune.go @@ -113,15 +113,15 @@ func prune(cmd *cobra.Command, args []string) error { func createPruneWarningMessage(pruneOpts entities.SystemPruneOptions) string { if pruneOpts.All { - return `WARNING! This will remove: + return `WARNING! This command removes: - all stopped containers - all networks not used by at least one container%s - - all images without at least one container associated to them + - all images without at least one container associated with them - all build cache %s` } - return `WARNING! This will remove: + return `WARNING! This command removes: - all stopped containers - all networks not used by at least one container%s - all dangling images diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go index d6fe8837b..99a6b1e1e 100644 --- a/cmd/podman/system/service.go +++ b/cmd/podman/system/service.go @@ -74,7 +74,7 @@ func service(cmd *cobra.Command, args []string) error { if err != nil { return err } - logrus.Infof("using API endpoint: '%s'", apiURI) + logrus.Infof("Using API endpoint: '%s'", apiURI) // Clean up any old existing unix domain socket if len(apiURI) > 0 { uri, err := url.Parse(apiURI) @@ -120,7 +120,7 @@ func resolveAPIURI(_url []string) (string, error) { case len(_url) > 0 && _url[0] != "": return _url[0], nil case systemd.SocketActivated(): - logrus.Info("using systemd socket activation to determine API endpoint") + logrus.Info("Using systemd socket activation to determine API endpoint") return "", nil case rootless.IsRootless(): xdg, err := util.GetRuntimeDir() 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..1f594000f 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 docker and containerd" + # N/B: Tests check/expect `docker info` output, and this `!= podman info` + ooe.sh apt-get install --yes 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/contrib/podmanimage/README.md b/contrib/podmanimage/README.md index b7be328c7..2452d7293 100644 --- a/contrib/podmanimage/README.md +++ b/contrib/podmanimage/README.md @@ -66,3 +66,7 @@ exit the fuse kernel module has not been loaded on your host system. Use the command `modprobe fuse` to load the module and then run the container image. To enable this automatically at boot time, you can add a configuration file to `/etc/modules.load.d`. See `man modules-load.d` for more details. + +### Blog Post with Details + +Dan Walsh wrote a blog post on the [Enable Sysadmin](https://www.redhat.com/sysadmin/) site titled [How to use Podman inside of a container](https://www.redhat.com/sysadmin/podman-inside-container). In it, he details how to use these images as a rootful and as a rootless user. Please refer to this blog for more detailed information. 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-build.1.md b/docs/source/markdown/podman-build.1.md index 98c8251b4..15d936d17 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -64,8 +64,10 @@ discarded when writing images in Docker formats. #### **--arch**=*arch* -Set the ARCH of the image to the provided value instead of the architecture of -the host. +Set the architecture of the image to be built, and that of the base image to be +pulled, if the build uses one, to the provided value instead of using the +architecture of the build host. (Examples: arm, arm64, 386, amd64, ppc64le, +s390x) #### **--authfile**=*path* @@ -321,7 +323,8 @@ Pass through HTTP Proxy environment variables. #### **--iidfile**=*ImageIDfile* -Write the image ID to the file. +Write the built image's ID to the file. When `--platform` is specified more +than once, attempting to use this option will trigger an error. #### **--ignorefile** @@ -389,6 +392,7 @@ Name of the manifest list to which the image will be added. Creates the manifest if it does not exist. This option is useful for building multi architecture images. #### **--memory**, **-m**=*LIMIT* + Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) @@ -430,8 +434,9 @@ with a new set of cached layers. #### **--os**=*string* -Set the OS to the provided value instead of the current operating system of the -host. +Set the OS of the image to be built, and that of the base image to be pulled, +if the build uses one, instead of using the current operating system of the +build host. #### **--pid**=*pid* @@ -442,11 +447,28 @@ that the PID namespace in which `podman` itself is being run should be reused, or it can be the path to a PID namespace which is already in use by another process. -#### **--platform**="Linux" +#### **--platform**="OS/ARCH[/VARIANT][,...]" + +Set the OS/ARCH of the built image (and its base image, if your build uses one) +to the provided value instead of using the current operating system and +architecture of the host (for example `linux/arm`). If `--platform` is set, +then the values of the `--arch`, `--os`, and `--variant` options will be +overridden. + +The `--platform` flag can be specified more than once, or given a +comma-separated list of values as its argument. When more than one platform is +specified, the `--manifest` option should be used instead of the `--tag` +option. + +OS/ARCH pairs are those used by the Go Programming Language. In several cases +the ARCH value for a platform differs from one produced by other tools such as +the `arch` command. Valid OS and architecture name combinations are listed as +values for $GOOS and $GOARCH at https://golang.org/doc/install/source#environment, +and can also be found by running `go tool dist list`. -This option has no effect on the build. Other container engines use this option -to control the execution platform for the build (e.g., Windows, Linux) which is -not required for Buildah as it supports only Linux. +While `podman build` is happy to use base images and build images for any +platform that exists, `RUN` instructions will not be able to succeed without +the help of emulation provided by packages like `qemu-user-static`. #### **--pull** @@ -486,7 +508,6 @@ commands specified by the **RUN** instruction. Note: You can also override the default runtime by setting the BUILDAH\_RUNTIME environment variable. `export BUILDAH_RUNTIME=/usr/local/bin/runc` - #### **--secret**=**id=id,src=path** Pass secret information to be used in the Containerfile for building images @@ -497,7 +518,6 @@ To later use the secret, use the --mount flag in a `RUN` instruction within a `C `RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret` - #### **--security-opt**=*option* Security Options @@ -697,7 +717,9 @@ process. #### **--variant**="" -Set the architecture variant of the image to be pulled. +Set the architecture variant of the image to be built, and that of the base +image to be pulled, if the build uses one, to the provided value instead of +using the architecture variant of the build host. #### **--volume**, **-v**[=*[HOST-DIR:CONTAINER-DIR[:OPTIONS]]*] @@ -858,7 +880,7 @@ $ podman build --layers --force-rm -t imageName . $ podman build --no-cache --rm=false -t imageName . ``` -### Building an multi-architecture image using a --manifest option (Requires emulation software) +### Building a multi-architecture image using the --manifest option (requires emulation software) ``` $ podman build --arch arm --manifest myimage /tmp/mysrc @@ -866,6 +888,10 @@ $ podman build --arch arm --manifest myimage /tmp/mysrc $ podman build --arch amd64 --manifest myimage /tmp/mysrc $ podman build --arch s390x --manifest myimage /tmp/mysrc + +$ podman build --platform linux/s390x,linux/ppc64le,linux/amd64 --manifest myimage /tmp/mysrc + +$ podman build --platform linux/arm64 --platform linux/amd64 --manifest myimage /tmp/mysrc ``` ### Building an image using a URL, Git repo, or archive diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index c3e2bbfca..ee52bfd13 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -513,7 +513,11 @@ Not implemented #### **--log-driver**="*k8s-file*" -Logging driver for the container. Currently available options are *k8s-file*, *journald*, and *none*, with *json-file* aliased to *k8s-file* for scripting compatibility. +Logging driver for the container. Currently available options are *k8s-file*, *journald*, *none* and *passthrough*, with *json-file* aliased to *k8s-file* for scripting compatibility. + +The *passthrough* driver passes down the standard streams (stdin, stdout, stderr) to the +container. It is not allowed with the remote Podman client and on a tty, since it is +vulnerable to attacks via TIOCSTI. #### **--log-opt**=*name*=*value* @@ -595,6 +599,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared + type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared,U=true + type=volume,source=vol1,destination=/path/in/container,ro=true type=tmpfs,tmpfs-size=512M,destination=/path/in/container @@ -613,6 +619,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · ro, readonly: true or false (default). + . U, chown: true or false (default). Change recursively the owner and group of the source volume based on the UID and GID of the container. + Options specific to image: · rw, readwrite: true or false (default). @@ -627,6 +635,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and . relabel: shared, private. + . U, chown: true or false (default). Change recursively the owner and group of the source volume based on the UID and GID of the container. + Options specific to tmpfs: · ro, readonly: true or false (default). @@ -639,6 +649,7 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · notmpcopyup: Disable copying files from the image to the tmpfs. + . U, chown: true or false (default). Change recursively the owner and group of the source volume based on the UID and GID of the container. #### **--name**=*name* @@ -721,7 +732,7 @@ Default is to create a private PID namespace for the container #### **--pids-limit**=*limit* -Tune the container's pids limit. Set `0` to have unlimited pids for the container. (default "4096" on systems that support PIDS cgroups). +Tune the container's pids limit. Set `-1` to have unlimited pids for the container. (default "4096" on systems that support PIDS cgroups). #### **--platform**=*OS/ARCH* 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. diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md index 1236db602..f1fbd56ee 100644 --- a/docs/source/markdown/podman-machine-init.1.md +++ b/docs/source/markdown/podman-machine-init.1.md @@ -40,7 +40,7 @@ do these things manually or handle otherwise. #### **--image-path** Fully qualified path or URL to the VM image. -Can also be set to `testing` or `stable` to pull down default image. +Can also be set to `testing`, `next`, or `stable` to pull down default image. Defaults to `testing`. #### **--memory**, **-m**=*number* diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index a369ce5ea..5cc17f470 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -538,7 +538,12 @@ Not implemented. #### **--log-driver**="*driver*" -Logging driver for the container. Currently available options are **k8s-file**, **journald**, and **none**, with **json-file** aliased to **k8s-file** for scripting compatibility. +Logging driver for the container. Currently available options are **k8s-file**, **journald**, **none** and **passthrough**, with **json-file** aliased to **k8s-file** for scripting compatibility. + +The **passthrough** driver passes down the standard streams (stdin, stdout, stderr) to the +container. It is not allowed with the remote Podman client and on a tty, since it is +vulnerable to attacks via TIOCSTI. + #### **--log-opt**=*name*=*value* @@ -615,6 +620,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared + type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared,U=true + type=volume,source=vol1,destination=/path/in/container,ro=true type=tmpfs,tmpfs-size=512M,destination=/path/in/container @@ -633,6 +640,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · ro, readonly: true or false (default). + . U, chown: true or false (default). Change recursively the owner and group of the source volume based on the UID and GID of the container. + Options specific to image: · rw, readwrite: true or false (default). @@ -647,6 +656,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and . relabel: shared, private. + . U, chown: true or false (default). Change recursively the owner and group of the source volume based on the UID and GID of the container. + Options specific to tmpfs: · ro, readonly: true or false (default). @@ -659,6 +670,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · notmpcopyup: Disable copying files from the image to the tmpfs. + . U, chown: true or false (default). Change recursively the owner and group of the source volume based on the UID and GID of the container. + #### **--name**=*name* Assign a name to the container. @@ -743,7 +756,7 @@ The default is to create a private PID namespace for the container. #### **--pids-limit**=*limit* -Tune the container's pids limit. Set to **0** to have unlimited pids for the container. The default is **4096** on systems that support "pids" cgroup controller. +Tune the container's pids limit. Set to **-1** to have unlimited pids for the container. The default is **4096** on systems that support "pids" cgroup controller. #### **--platform**=*OS/ARCH* diff --git a/docs/source/markdown/podman-save.1.md b/docs/source/markdown/podman-save.1.md index 1f1f60b22..842bc8b41 100644 --- a/docs/source/markdown/podman-save.1.md +++ b/docs/source/markdown/podman-save.1.md @@ -29,6 +29,10 @@ Note: `:` is a restricted character and cannot be part of the file name. Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type, compressed or uncompressed, as source) Note: This flag can only be set when using the **dir** transport i.e --format=oci-dir or --format=docker-dir +#### **--uncompressed** + +Accept uncompressed layers when copying OCI images. + #### **--output**, **-o**=*file* Write to a file, default is STDOUT @@ -6,18 +6,18 @@ require ( github.com/BurntSushi/toml v0.4.1 github.com/blang/semver v3.5.1+incompatible github.com/buger/goterm v0.0.0-20181115115552-c206103e1f37 - github.com/checkpoint-restore/checkpointctl v0.0.0-20210301084134-a2024f5584e7 + github.com/checkpoint-restore/checkpointctl v0.0.0-20210922093614-c31748bec9f2 github.com/checkpoint-restore/go-criu/v5 v5.1.0 github.com/container-orchestrated-devices/container-device-interface v0.0.0-20210325223243-f99e8b6c10b9 - github.com/containernetworking/cni v0.8.1 - github.com/containernetworking/plugins v0.9.1 + 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.20210920093543-bf187ada7d0e + 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 - github.com/containers/psgo v1.6.0 - github.com/containers/storage v1.36.0 + github.com/containers/psgo v1.7.1 + github.com/containers/storage v1.36.1-0.20210929132900-162a0bf730ce github.com/coreos/go-systemd/v22 v22.3.2 github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3 github.com/cyphar/filepath-securejoin v0.2.3 @@ -41,6 +41,7 @@ require ( github.com/hpcloud/tail v1.0.0 github.com/json-iterator/go v1.1.12 github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.14 github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 github.com/mrunalp/fileutils v0.5.0 github.com/onsi/ginkgo v1.16.4 @@ -61,13 +62,12 @@ 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.20201029203352-d40f9887b852 + 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 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b - k8s.io/api v0.22.1 - k8s.io/apimachinery v0.22.1 + k8s.io/api v0.22.2 + k8s.io/apimachinery v0.22.2 ) @@ -95,6 +95,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -121,6 +122,7 @@ github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR github.com/buger/goterm v0.0.0-20181115115552-c206103e1f37 h1:uxxtrnACqI9zK4ENDMf0WpXfUsHP5V8liuq5QdgDISU= github.com/buger/goterm v0.0.0-20181115115552-c206103e1f37/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= @@ -129,8 +131,8 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkpoint-restore/checkpointctl v0.0.0-20210301084134-a2024f5584e7 h1:ZmSAEFFtv3mepC4/Ze6E/hi6vGZlhRvywqp1l+w+qqw= -github.com/checkpoint-restore/checkpointctl v0.0.0-20210301084134-a2024f5584e7/go.mod h1:Kp3ezoDVdhfYxZUtgs4OL8sVvgOLz3txk0sbQD0opvw= +github.com/checkpoint-restore/checkpointctl v0.0.0-20210922093614-c31748bec9f2 h1:z7G4H5f1Z/n3di9qnGtKDm6jmP434HD7dIEh3YyLn9I= +github.com/checkpoint-restore/checkpointctl v0.0.0-20210922093614-c31748bec9f2/go.mod h1:yvaQuauIKzvfX/PIqINxWxoOYd35Dk/U2MS8onfkRHU= github.com/checkpoint-restore/go-criu/v4 v4.0.2/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= @@ -238,16 +240,18 @@ github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1Dv github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI= github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v1.0.1 h1:9OIL/sZmMYDBe+G8svzILAlulUpaDTUjeAbtH/JNLBo= +github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y= github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= -github.com/containernetworking/plugins v0.9.1 h1:FD1tADPls2EEi3flPc2OegIY1M9pUa9r2Quag7HMLV8= github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containernetworking/plugins v1.0.1 h1:wwCfYbTCj5FC0EJgyzyjTXmqysOiJE9r712Z+2KVZAk= +github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE= 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.20210920093543-bf187ada7d0e h1:p21+CJSeryr0Vb3dottjXRNYTaRND1QSPm36NogQ7cQ= -github.com/containers/common v0.44.1-0.20210920093543-bf187ada7d0e/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= @@ -259,17 +263,19 @@ github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgU github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= github.com/containers/ocicrypt v1.1.2 h1:Ez+GAMP/4GLix5Ywo/fL7O0nY771gsBIigiqUm1aXz0= github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= -github.com/containers/psgo v1.6.0 h1:jkl/5kndKmJ/bnSFq8in6xRDAzgW26GnNuTxoycNFvk= -github.com/containers/psgo v1.6.0/go.mod h1:ggVhB2KQi9qGZdqSlczqN0BwcJdotmpRru87S1anRO8= +github.com/containers/psgo v1.7.1 h1:2N6KADeFvBm1aI2iXxu6+/Xh7CCkdh8p8F3F/cpIU5I= +github.com/containers/psgo v1.7.1/go.mod h1:mWGpFzW73qWFA+blhF6l7GuKzbrACkYgr/ajiNQR+RM= github.com/containers/storage v1.23.5/go.mod h1:ha26Q6ngehFNhf3AWoXldvAvwI4jFe3ETQAf/CeZPyM= github.com/containers/storage v1.35.0/go.mod h1:qzYhasQP2/V9D9XdO+vRwkHBhsBO0oznMLzzRDQ8s20= -github.com/containers/storage v1.36.0 h1:OelxllCW19tnNngYuZw2ty/zLabVMG5rSs3KSwO1Lzc= github.com/containers/storage v1.36.0/go.mod h1:vbd3SKVQNHdmU5qQI6hTEcKPxnZkGqydG4f6uwrI5a8= +github.com/containers/storage v1.36.1-0.20210929132900-162a0bf730ce h1:6YOfANEWtL7+Q4RmnAfloGLIJNtt17MEHjvlHXz0vVY= +github.com/containers/storage v1.36.1-0.20210929132900-162a0bf730ce/go.mod h1:b7OGxODIyB3XpvCSWR91lllT9fv9DXeC8yfnaUocWJU= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -555,6 +561,7 @@ github.com/insomniacslk/dhcp v0.0.0-20210120172423-cc9239ac6294/go.mod h1:TKl4jN github.com/ishidawataru/sctp v0.0.0-20210226210310-f2269e66cdee h1:PAXLXk1heNZ5yokbMBpVLZQxo43wCZxRwl00mX+dd44= github.com/ishidawataru/sctp v0.0.0-20210226210310-f2269e66cdee/go.mod h1:co9pwDoBCm1kGxawmb4sPq0cSIOOWNPT4KnHotMP1Zg= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w= github.com/jinzhu/copier v0.3.2/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -584,8 +591,9 @@ github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5 h1:9O69jUPDcsT9fEm74W92rZL9FQY7rCdaXVneq+yyzl4= github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -617,8 +625,9 @@ github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= @@ -704,8 +713,8 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -714,7 +723,7 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -819,7 +828,9 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.2-0.20200616122406-847368b35ebf h1:b0+ZBD3rohnkQ4q5duD1+RyTXTg9yk+qTOPMSQtapO0= @@ -910,12 +921,14 @@ github.com/vbauerster/mpb/v7 v7.1.4 h1:XGWpWEB8aWnvqSlAMA7F7kdeUGqcTujuVFvYj9+59 github.com/vbauerster/mpb/v7 v7.1.4/go.mod h1:4zulrZfvshMOnd2APiHgWS9Yrw08AzZVRr9G11tkpcQ= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 h1:cPXZWzzG0NllBLdjWoD1nDfaqu98YMv+OneaKc8sPOA= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA852UkGH42H+Oee69djmxS3ANzl2b/JtT1YiA= +github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1445,13 +1458,13 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= -k8s.io/api v0.22.1 h1:ISu3tD/jRhYfSW8jI/Q1e+lRxkR7w9UwQEZ7FgslrwY= -k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= -k8s.io/apimachinery v0.22.1 h1:DTARnyzmdHMz7bFWFDDm22AM4pLWTQECMpRTFu2d2OM= -k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= +k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= @@ -19,6 +19,8 @@ $0 is a wrapper for invoking podman system tests. version of bats installed, runs with '--filter pattern' which runs only subtests that match 'pattern' + -T Passed on to bats, which will then show timing data + --help display usage message By default, tests ./bin/podman. To test a different podman, do: @@ -60,6 +62,8 @@ REMOTE= ROOT_ONLY= ROOTLESS_ONLY= +declare -a bats_opts=() + declare -a bats_filter=() for i;do @@ -69,6 +73,7 @@ for i;do --root) ROOT_ONLY=1 ;; --rootless) ROOTLESS_ONLY=1 ;; --remote) REMOTE=remote; echo "--remote is TBI"; exit 1;; + --ts|-T) bats_opts+=("-T") ;; */*.bats) TESTS=$i ;; *) if [[ $i =~ : ]]; then @@ -94,7 +99,7 @@ if [ -z "$ROOTLESS_ONLY" ]; then sudo --preserve-env=PODMAN \ --preserve-env=PODMAN_TEST_DEBUG \ --preserve-env=OCI_RUNTIME \ - bats "${bats_filter[@]}" $TESTS + bats "${bats_opts[@]}" "${bats_filter[@]}" $TESTS rc=$? fi @@ -102,7 +107,7 @@ fi echo "--------------------------------------------------" if [ -z "$ROOT_ONLY" ]; then echo "\$ bats ${bats_filter[@]} $TESTS" - bats "${bats_filter[@]}" $TESTS + bats "${bats_opts[@]}" "${bats_filter[@]}" $TESTS rc=$((rc | $?)) fi diff --git a/hack/podman-registry-go/registry.go b/hack/podman-registry-go/registry.go index e9ec61ffe..92e3008f3 100644 --- a/hack/podman-registry-go/registry.go +++ b/hack/podman-registry-go/registry.go @@ -61,7 +61,7 @@ func Start() (*Registry, error) { case portKey: registry.Port = val default: - logrus.Errorf("unexpected podman-registry output: %q", s) + logrus.Errorf("Unexpected podman-registry output: %q", s) } } diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 56b4bafd3..1242a8d6b 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -954,7 +954,7 @@ func (s *BoltState) AllContainers() ([]*Container, error) { // not worth erroring over. // If we do, a single bad container JSON // could render libpod unusable. - logrus.Errorf("Error retrieving container %s from the database: %v", string(id), err) + logrus.Errorf("Retrieving container %s from the database: %v", string(id), err) } } else { ctrs = append(ctrs, ctr) @@ -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) + } + } } } @@ -2556,7 +2573,7 @@ func (s *BoltState) AllVolumes() ([]*Volume, error) { if err := s.getVolumeFromDB(id, volume, volBucket); err != nil { if errors.Cause(err) != define.ErrNSMismatch { - logrus.Errorf("Error retrieving volume %s from the database: %v", string(id), err) + logrus.Errorf("Retrieving volume %s from the database: %v", string(id), err) } } else { volumes = append(volumes, volume) @@ -3352,7 +3369,7 @@ func (s *BoltState) AllPods() ([]*Pod, error) { if err := s.getPodFromDB(id, pod, podBucket); err != nil { if errors.Cause(err) != define.ErrNSMismatch { - logrus.Errorf("Error retrieving pod %s from the database: %v", string(id), err) + logrus.Errorf("Retrieving pod %s from the database: %v", string(id), err) } } else { pods = append(pods, pod) diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go index f63876c14..3e3c17a9e 100644 --- a/libpod/boltdb_state_internal.go +++ b/libpod/boltdb_state_internal.go @@ -259,7 +259,7 @@ func (s *BoltState) getDBCon() (*bolt.DB, error) { // of a defer statement only func (s *BoltState) deferredCloseDBCon(db *bolt.DB) { if err := s.closeDBCon(db); err != nil { - logrus.Errorf("failed to close libpod db: %q", err) + logrus.Errorf("Failed to close libpod db: %q", err) } } @@ -875,7 +875,7 @@ func (s *BoltState) removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error podCtrs := podDB.Bucket(containersBkt) if podCtrs == nil { // Malformed pod - logrus.Errorf("pod %s malformed in database, missing containers bucket!", pod.ID()) + logrus.Errorf("Pod %s malformed in database, missing containers bucket!", pod.ID()) } else { ctrInPod := podCtrs.Get(ctrID) if ctrInPod == nil { diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go index 72243dcc5..4fb3236a0 100644 --- a/libpod/boltdb_state_linux.go +++ b/libpod/boltdb_state_linux.go @@ -31,7 +31,7 @@ func replaceNetNS(netNSPath string, ctr *Container, newState *ContainerState) er return errors.Wrapf(err, "error joining network namespace of container %s", ctr.ID()) } - logrus.Errorf("error joining network namespace for container %s: %v", ctr.ID(), err) + logrus.Errorf("Joining network namespace for container %s: %v", ctr.ID(), err) ctr.state.NetNS = nil } } diff --git a/libpod/container.go b/libpod/container.go index 7d602326e..4d15c04c5 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -8,7 +8,7 @@ import ( "os" "time" - cnitypes "github.com/containernetworking/cni/pkg/types/current" + types040 "github.com/containernetworking/cni/pkg/types/040" "github.com/containers/common/pkg/secrets" "github.com/containers/image/v5/manifest" "github.com/containers/podman/v3/libpod/define" @@ -176,7 +176,7 @@ type ContainerState struct { // active. // These are DEPRECATED and will be removed in a future release. // This field is only used for backwarts compatibility. - NetworkStatusOld []*cnitypes.Result `json:"networkResults,omitempty"` + NetworkStatusOld []*types040.Result `json:"networkResults,omitempty"` // NetworkStatus contains the network Status for all networks // the container is attached to. Only populated if we created a network // namespace for the container, and the network namespace is currently @@ -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_api.go b/libpod/container_api.go index 637f5b686..50be0eea4 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -53,7 +53,7 @@ func (c *Container) Init(ctx context.Context, recursive bool) error { if err := c.prepare(); err != nil { if err2 := c.cleanup(ctx); err2 != nil { - logrus.Errorf("error cleaning up container %s: %v", c.ID(), err2) + logrus.Errorf("Cleaning up container %s: %v", c.ID(), err2) } return err } @@ -229,6 +229,10 @@ func (c *Container) Kill(signal uint) error { // This function returns when the attach finishes. It does not hold the lock for // the duration of its runtime, only using it at the beginning to verify state. func (c *Container) Attach(streams *define.AttachStreams, keys string, resize <-chan define.TerminalSize) error { + switch c.LogDriver() { + case define.PassthroughLogging: + return errors.Wrapf(define.ErrNoLogs, "this container is using the 'passthrough' log driver, cannot attach") + } if !c.batched { c.lock.Lock() if err := c.syncContainer(); err != nil { diff --git a/libpod/container_commit.go b/libpod/container_commit.go index 87e5d511c..6ae225cbc 100644 --- a/libpod/container_commit.go +++ b/libpod/container_commit.go @@ -51,7 +51,7 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai } defer func() { if err := c.unpause(); err != nil { - logrus.Errorf("error unpausing container %q: %v", c.ID(), err) + logrus.Errorf("Unpausing container %q: %v", c.ID(), err) } }() } 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 5d4bcb422..f99fb7d3f 100644 --- a/libpod/container_exec.go +++ b/libpod/container_exec.go @@ -415,7 +415,7 @@ func (c *Container) ExecHTTPStartAndAttach(sessionID string, r *http.Request, w session.ExitCode = define.ExecErrorCodeGeneric if err := c.save(); err != nil { - logrus.Errorf("Error saving container %s exec session %s after failure to prepare: %v", err, c.ID(), session.ID()) + logrus.Errorf("Saving container %s exec session %s after failure to prepare: %v", err, c.ID(), session.ID()) } return err @@ -440,7 +440,7 @@ func (c *Container) ExecHTTPStartAndAttach(sessionID string, r *http.Request, w session.ExitCode = define.TranslateExecErrorToExitCode(define.ExecErrorCodeGeneric, err) if err := c.save(); err != nil { - logrus.Errorf("Error saving container %s exec session %s after failure to start: %v", err, c.ID(), session.ID()) + logrus.Errorf("Saving container %s exec session %s after failure to start: %v", err, c.ID(), session.ID()) } return err @@ -549,7 +549,7 @@ func (c *Container) ExecStop(sessionID string, timeout *uint) error { if err := c.cleanupExecBundle(session.ID()); err != nil { if cleanupErr != nil { - logrus.Errorf("Error stopping container %s exec session %s: %v", c.ID(), session.ID(), cleanupErr) + logrus.Errorf("Stopping container %s exec session %s: %v", c.ID(), session.ID(), cleanupErr) } cleanupErr = err } @@ -695,7 +695,7 @@ func (c *Container) ExecResize(sessionID string, newSize define.TerminalSize) er session.State = define.ExecStateStopped if err := c.save(); err != nil { - logrus.Errorf("Error saving state of container %s: %v", c.ID(), err) + logrus.Errorf("Saving state of container %s: %v", c.ID(), err) } return errors.Wrapf(define.ErrExecSessionStateInvalid, "cannot resize container %s exec session %s as it has stopped", c.ID(), session.ID()) @@ -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 @@ -825,7 +825,7 @@ func (c *Container) createExecBundle(sessionID string) (retErr error) { defer func() { if retErr != nil { if err := os.RemoveAll(bundlePath); err != nil { - logrus.Warnf("error removing exec bundle after creation caused another error: %v", err) + logrus.Warnf("Error removing exec bundle after creation caused another error: %v", err) } } }() @@ -911,7 +911,7 @@ func (c *Container) getActiveExecSessions() ([]string, error) { alive, err := c.ociRuntime.ExecUpdateStatus(c, id) if err != nil { if lastErr != nil { - logrus.Errorf("Error checking container %s exec sessions: %v", c.ID(), lastErr) + logrus.Errorf("Checking container %s exec sessions: %v", c.ID(), lastErr) } lastErr = err continue @@ -926,7 +926,7 @@ func (c *Container) getActiveExecSessions() ([]string, error) { exitCode, err := c.readExecExitCode(session.ID()) if err != nil { if lastErr != nil { - logrus.Errorf("Error checking container %s exec sessions: %v", c.ID(), lastErr) + logrus.Errorf("Checking container %s exec sessions: %v", c.ID(), lastErr) } lastErr = err } @@ -940,7 +940,7 @@ func (c *Container) getActiveExecSessions() ([]string, error) { } if err := c.cleanupExecBundle(id); err != nil { if lastErr != nil { - logrus.Errorf("Error checking container %s exec sessions: %v", c.ID(), lastErr) + logrus.Errorf("Checking container %s exec sessions: %v", c.ID(), lastErr) } lastErr = err } @@ -951,7 +951,7 @@ func (c *Container) getActiveExecSessions() ([]string, error) { if needSave { if err := c.save(); err != nil { if lastErr != nil { - logrus.Errorf("Error reaping exec sessions for container %s: %v", c.ID(), lastErr) + logrus.Errorf("Reaping exec sessions for container %s: %v", c.ID(), lastErr) } lastErr = err } @@ -970,7 +970,7 @@ func (c *Container) removeAllExecSessions() error { for _, id := range knownSessions { if err := c.ociRuntime.ExecStopContainer(c, id, c.StopTimeout()); err != nil { if lastErr != nil { - logrus.Errorf("Error stopping container %s exec sessions: %v", c.ID(), lastErr) + logrus.Errorf("Stopping container %s exec sessions: %v", c.ID(), lastErr) } lastErr = err continue @@ -978,7 +978,7 @@ func (c *Container) removeAllExecSessions() error { if err := c.cleanupExecBundle(id); err != nil { if lastErr != nil { - logrus.Errorf("Error stopping container %s exec sessions: %v", c.ID(), lastErr) + logrus.Errorf("Stopping container %s exec sessions: %v", c.ID(), lastErr) } lastErr = err } @@ -987,7 +987,7 @@ func (c *Container) removeAllExecSessions() error { if err := c.runtime.state.RemoveContainerExecSessions(c); err != nil { if errors.Cause(err) != define.ErrCtrRemoved { if lastErr != nil { - logrus.Errorf("Error stopping container %s exec sessions: %v", c.ID(), lastErr) + logrus.Errorf("Stopping container %s exec sessions: %v", c.ID(), lastErr) } lastErr = err } @@ -997,7 +997,7 @@ func (c *Container) removeAllExecSessions() error { if err := c.save(); err != nil { if errors.Cause(err) != define.ErrCtrRemoved { if lastErr != nil { - logrus.Errorf("Error stopping container %s exec sessions: %v", c.ID(), lastErr) + logrus.Errorf("Stopping container %s exec sessions: %v", c.ID(), lastErr) } lastErr = err } diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index cd3821aa0..277c3b960 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -151,12 +151,12 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver if c.config.HealthCheckConfig != nil { // This container has a healthcheck defined in it; we need to add it's state - healthCheckState, err := c.GetHealthCheckLog() + healthCheckState, err := c.getHealthCheckLog() if err != nil { // An error here is not considered fatal; no health state will be displayed logrus.Error(err) } else { - data.State.Healthcheck = healthCheckState + data.State.Health = healthCheckState } } @@ -178,13 +178,13 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver if size { rootFsSize, err := c.rootFsSize() if err != nil { - logrus.Errorf("error getting rootfs size %q: %v", config.ID, err) + logrus.Errorf("Getting rootfs size %q: %v", config.ID, err) } data.SizeRootFs = rootFsSize rwSize, err := c.rwSize() if err != nil { - logrus.Errorf("error getting rw size %q: %v", config.ID, err) + logrus.Errorf("Getting rw size %q: %v", config.ID, err) } data.SizeRw = &rwSize } diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 9ac2cd5bd..3f9738411 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -176,7 +176,7 @@ func (c *Container) waitForExitFileAndSync() error { c.state.State = define.ContainerStateStopped if err2 := c.save(); err2 != nil { - logrus.Errorf("Error saving container %s state: %v", c.ID(), err2) + logrus.Errorf("Saving container %s state: %v", c.ID(), err2) } return err @@ -278,7 +278,7 @@ func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr err defer func() { if retErr != nil { if err := c.cleanup(ctx); err != nil { - logrus.Errorf("error cleaning up container %s: %v", c.ID(), err) + logrus.Errorf("Cleaning up container %s: %v", c.ID(), err) } } }() @@ -709,7 +709,7 @@ func (c *Container) export(path string) error { mountPoint = containerMount defer func() { if _, err := c.runtime.store.Unmount(c.ID(), false); err != nil { - logrus.Errorf("error unmounting container %q: %v", c.ID(), err) + logrus.Errorf("Unmounting container %q: %v", c.ID(), err) } }() } @@ -778,7 +778,7 @@ func (c *Container) prepareToStart(ctx context.Context, recursive bool) (retErr defer func() { if retErr != nil { if err := c.cleanup(ctx); err != nil { - logrus.Errorf("error cleaning up container %s: %v", c.ID(), err) + logrus.Errorf("Cleaning up container %s: %v", c.ID(), err) } } }() @@ -859,7 +859,7 @@ func (c *Container) startDependencies(ctx context.Context) error { } if len(ctrErrors) > 0 { - logrus.Errorf("error starting some container dependencies") + logrus.Errorf("Starting some container dependencies") for _, e := range ctrErrors { logrus.Errorf("%q", e) } @@ -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) } } } @@ -1047,7 +1046,7 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error { // upstream in any OCI runtime. // TODO: Remove once runc supports cgroupsv2 if strings.Contains(err.Error(), "this version of runc doesn't work on cgroups v2") { - logrus.Errorf("oci runtime %q does not support CGroups V2: use system migrate to mitigate", c.ociRuntime.Name()) + logrus.Errorf("Oci runtime %q does not support CGroups V2: use system migrate to mitigate", c.ociRuntime.Name()) } return err } @@ -1057,7 +1056,7 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error { // Remove any exec sessions leftover from a potential prior run. if len(c.state.ExecSessions) > 0 { if err := c.runtime.state.RemoveContainerExecSessions(c); err != nil { - logrus.Errorf("Error removing container %s exec sessions from DB: %v", c.ID(), err) + logrus.Errorf("Removing container %s exec sessions from DB: %v", c.ID(), err) } c.state.ExecSessions = make(map[string]*ExecSession) } @@ -1164,7 +1163,7 @@ func (c *Container) initAndStart(ctx context.Context) (retErr error) { defer func() { if retErr != nil { if err := c.cleanup(ctx); err != nil { - logrus.Errorf("error cleaning up container %s: %v", c.ID(), err) + logrus.Errorf("Cleaning up container %s: %v", c.ID(), err) } } }() @@ -1211,7 +1210,7 @@ func (c *Container) start() error { payload += daemon.SdNotifyReady } if sent, err := daemon.SdNotify(false, payload); err != nil { - logrus.Errorf("Error notifying systemd of Conmon PID: %s", err.Error()) + logrus.Errorf("Notifying systemd of Conmon PID: %s", err.Error()) } else if sent { logrus.Debugf("Notify sent successfully") } @@ -1290,7 +1289,7 @@ func (c *Container) stop(timeout uint) error { return stopErr default: if stopErr != nil { - logrus.Errorf("Error syncing container %s status: %v", c.ID(), err) + logrus.Errorf("Syncing container %s status: %v", c.ID(), err) return stopErr } return err @@ -1328,7 +1327,7 @@ func (c *Container) stop(timeout uint) error { c.state.FinishedTime = time.Now() c.state.State = define.ContainerStateStopped if err := c.save(); err != nil { - logrus.Errorf("Error saving container %s status: %v", c.ID(), err) + logrus.Errorf("Saving container %s status: %v", c.ID(), err) } return errors.Wrapf(define.ErrConmonDead, "container %s conmon process missing, cannot retrieve exit code", c.ID()) @@ -1432,7 +1431,7 @@ func (c *Container) restartWithTimeout(ctx context.Context, timeout uint) (retEr defer func() { if retErr != nil { if err := c.cleanup(ctx); err != nil { - logrus.Errorf("error cleaning up container %s: %v", c.ID(), err) + logrus.Errorf("Cleaning up container %s: %v", c.ID(), err) } } }() @@ -1483,7 +1482,7 @@ func (c *Container) mountStorage() (_ string, deferredErr error) { defer func() { if deferredErr != nil { if err := c.unmountSHM(c.config.ShmDir); err != nil { - logrus.Errorf("Error unmounting SHM for container %s after mount error: %v", c.ID(), err) + logrus.Errorf("Unmounting SHM for container %s after mount error: %v", c.ID(), err) } } }() @@ -1526,7 +1525,7 @@ func (c *Container) mountStorage() (_ string, deferredErr error) { defer func() { if deferredErr != nil { if err := c.unmount(false); err != nil { - logrus.Errorf("Error unmounting container %s after mount error: %v", c.ID(), err) + logrus.Errorf("Unmounting container %s after mount error: %v", c.ID(), err) } } }() @@ -1554,7 +1553,7 @@ func (c *Container) mountStorage() (_ string, deferredErr error) { } vol.lock.Lock() if err := vol.unmount(false); err != nil { - logrus.Errorf("Error unmounting volume %s after error mounting container %s: %v", vol.Name(), c.ID(), err) + logrus.Errorf("Unmounting volume %s after error mounting container %s: %v", vol.Name(), c.ID(), err) } vol.lock.Unlock() }() @@ -1669,7 +1668,7 @@ func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string) if err := copier.Put(volMount, "", copyOpts, reader); err != nil { err2 := <-errChan if err2 != nil { - logrus.Errorf("Error streaming contents of container %s directory for volume copy-up: %v", c.ID(), err2) + logrus.Errorf("Streaming contents of container %s directory for volume copy-up: %v", c.ID(), err2) } return nil, errors.Wrapf(err, "error copying up to volume %s", vol.Name()) } @@ -1705,7 +1704,7 @@ func (c *Container) cleanupStorage() error { for _, containerMount := range c.config.Mounts { if err := c.unmountSHM(containerMount); err != nil { if cleanupErr != nil { - logrus.Errorf("Error unmounting container %s: %v", c.ID(), cleanupErr) + logrus.Errorf("Unmounting container %s: %v", c.ID(), cleanupErr) } cleanupErr = err } @@ -1730,7 +1729,7 @@ func (c *Container) cleanupStorage() error { logrus.Errorf("Storage for container %s has been removed", c.ID()) } else { if cleanupErr != nil { - logrus.Errorf("Error cleaning up container %s storage: %v", c.ID(), cleanupErr) + logrus.Errorf("Cleaning up container %s storage: %v", c.ID(), cleanupErr) } cleanupErr = err } @@ -1741,7 +1740,7 @@ func (c *Container) cleanupStorage() error { vol, err := c.runtime.state.Volume(v.Name) if err != nil { if cleanupErr != nil { - logrus.Errorf("Error unmounting container %s: %v", c.ID(), cleanupErr) + logrus.Errorf("Unmounting container %s: %v", c.ID(), cleanupErr) } cleanupErr = errors.Wrapf(err, "error retrieving named volume %s for container %s", v.Name, c.ID()) @@ -1754,7 +1753,7 @@ func (c *Container) cleanupStorage() error { vol.lock.Lock() if err := vol.unmount(false); err != nil { if cleanupErr != nil { - logrus.Errorf("Error unmounting container %s: %v", c.ID(), cleanupErr) + logrus.Errorf("Unmounting container %s: %v", c.ID(), cleanupErr) } cleanupErr = errors.Wrapf(err, "error unmounting volume %s for container %s", vol.Name(), c.ID()) } @@ -1768,7 +1767,7 @@ func (c *Container) cleanupStorage() error { if c.valid { if err := c.save(); err != nil { if cleanupErr != nil { - logrus.Errorf("Error unmounting container %s: %v", c.ID(), cleanupErr) + logrus.Errorf("Unmounting container %s: %v", c.ID(), cleanupErr) } cleanupErr = err } @@ -1785,7 +1784,7 @@ func (c *Container) cleanup(ctx context.Context) error { // Remove healthcheck unit/timer file if it execs if c.config.HealthCheckConfig != nil { if err := c.removeTimer(); err != nil { - logrus.Errorf("Error removing timer for container %s healthcheck: %v", c.ID(), err) + logrus.Errorf("Removing timer for container %s healthcheck: %v", c.ID(), err) } } @@ -1800,7 +1799,7 @@ func (c *Container) cleanup(ctx context.Context) error { // exists. if err := c.cleanupRuntime(ctx); err != nil { if lastError != nil { - logrus.Errorf("Error removing container %s from OCI runtime: %v", c.ID(), err) + logrus.Errorf("Removing container %s from OCI runtime: %v", c.ID(), err) } else { lastError = err } @@ -1809,7 +1808,7 @@ func (c *Container) cleanup(ctx context.Context) error { // Unmount storage if err := c.cleanupStorage(); err != nil { if lastError != nil { - logrus.Errorf("Error unmounting container %s storage: %v", c.ID(), err) + logrus.Errorf("Unmounting container %s storage: %v", c.ID(), err) } else { lastError = errors.Wrapf(err, "error unmounting container %s storage", c.ID()) } @@ -1823,14 +1822,14 @@ func (c *Container) cleanup(ctx context.Context) error { lastError = err continue } - logrus.Errorf("error unmounting image volume %q:%q :%v", v.Source, v.Dest, err) + logrus.Errorf("Unmounting image volume %q:%q :%v", v.Source, v.Dest, err) } if err := img.Unmount(false); err != nil { if lastError == nil { lastError = err continue } - logrus.Errorf("error unmounting image volume %q:%q :%v", v.Source, v.Dest, err) + logrus.Errorf("Unmounting image volume %q:%q :%v", v.Source, v.Dest, err) } } @@ -1874,7 +1873,7 @@ func (c *Container) postDeleteHooks(ctx context.Context) error { var stderr, stdout bytes.Buffer hookErr, err := exec.Run(ctx, &hook, state, &stdout, &stderr, exec.DefaultPostKillTimeout) if err != nil { - logrus.Warnf("container %s: poststop hook %d: %v", c.ID(), i, err) + logrus.Warnf("Container %s: poststop hook %d: %v", c.ID(), i, err) if hookErr != err { logrus.Debugf("container %s: poststop hook %d (hook error): %v", c.ID(), i, hookErr) } @@ -2005,12 +2004,12 @@ 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 } if len(ociHooks) > 0 || config.Hooks != nil { - logrus.Warnf("implicit hook directories are deprecated; set --ociHooks-dir=%q explicitly to continue to load ociHooks from this directory", hDir) + logrus.Warnf("Implicit hook directories are deprecated; set --ociHooks-dir=%q explicitly to continue to load ociHooks from this directory", hDir) } for i, hook := range ociHooks { allHooks[i] = hook @@ -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 } @@ -2030,7 +2029,7 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (map[s hookErr, err := exec.RuntimeConfigFilter(ctx, allHooks["precreate"], config, exec.DefaultPostKillTimeout) if err != nil { - logrus.Warnf("container %s: precreate hook: %v", c.ID(), err) + logrus.Warnf("Container %s: precreate hook: %v", c.ID(), err) if hookErr != nil && hookErr != err { logrus.Debugf("container %s: precreate hook (hook error): %v", c.ID(), hookErr) } @@ -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 0a663200a..867ecc2ad 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -70,7 +70,7 @@ func (c *Container) unmountSHM(mount string) error { return errors.Wrapf(err, "error unmounting container %s SHM mount %s", c.ID(), mount) } // If it's just an EINVAL or ENOENT, debug logs only - logrus.Debugf("container %s failed to unmount %s : %v", c.ID(), mount, err) + logrus.Debugf("Container %s failed to unmount %s : %v", c.ID(), mount, err) } return nil } @@ -143,7 +143,7 @@ func (c *Container) prepare() error { } if mountStorageErr != nil { if createErr != nil { - logrus.Errorf("Error preparing container %s: %v", c.ID(), createErr) + logrus.Errorf("Preparing container %s: %v", c.ID(), createErr) } createErr = mountStorageErr } @@ -154,7 +154,7 @@ func (c *Container) prepare() error { if err := c.cleanupStorage(); err != nil { // createErr is guaranteed non-nil, so print // unconditionally - logrus.Errorf("Error preparing container %s: %v", c.ID(), createErr) + logrus.Errorf("Preparing container %s: %v", c.ID(), createErr) createErr = errors.Wrapf(err, "error unmounting storage for container %s after network create failure", c.ID()) } } @@ -163,7 +163,7 @@ func (c *Container) prepare() error { // isn't ready it will do nothing. if createErr != nil { if err := c.cleanupNetwork(); err != nil { - logrus.Errorf("Error preparing container %s: %v", c.ID(), createErr) + logrus.Errorf("Preparing container %s: %v", c.ID(), createErr) createErr = errors.Wrapf(err, "error cleaning up container %s network after setup failure", c.ID()) } } @@ -258,7 +258,7 @@ func (c *Container) cleanupNetwork() error { // Stop the container's network namespace (if it has one) if err := c.runtime.teardownNetNS(c); err != nil { - logrus.Errorf("unable to cleanup network for container %s: %q", c.ID(), err) + logrus.Errorf("Unable to cleanup network for container %s: %q", c.ID(), err) } c.state.NetNS = nil @@ -599,7 +599,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { if isGIDAvailable { g.AddProcessAdditionalGid(uint32(gid)) } else { - logrus.Warnf("additional gid=%d is not present in the user namespace, skip setting it", gid) + logrus.Warnf("Additional gid=%d is not present in the user namespace, skip setting it", gid) } } } @@ -640,7 +640,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { if err != nil { if os.IsNotExist(err) { // The kernel-provided files only exist if user namespaces are supported - logrus.Debugf("user or group ID mappings not available: %s", err) + logrus.Debugf("User or group ID mappings not available: %s", err) } else { return nil, err } @@ -781,7 +781,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } if rootPropagation != "" { - logrus.Debugf("set root propagation to %q", rootPropagation) + logrus.Debugf("Set root propagation to %q", rootPropagation) if err := g.SetLinuxRootPropagation(rootPropagation); err != nil { return nil, err } @@ -838,7 +838,7 @@ func (c *Container) mountNotifySocket(g generate.Generator) error { } notifyDir := filepath.Join(c.bundlePath(), "notify") - logrus.Debugf("checking notify %q dir", notifyDir) + logrus.Debugf("Checking notify %q dir", notifyDir) if err := os.MkdirAll(notifyDir, 0755); err != nil { if !os.IsExist(err) { return errors.Wrapf(err, "unable to create notify %q dir", notifyDir) @@ -847,7 +847,7 @@ func (c *Container) mountNotifySocket(g generate.Generator) error { if err := label.Relabel(notifyDir, c.MountLabel(), true); err != nil { return errors.Wrapf(err, "relabel failed %q", notifyDir) } - logrus.Debugf("add bindmount notify %q dir", notifyDir) + logrus.Debugf("Add bindmount notify %q dir", notifyDir) if _, ok := c.state.BindMounts["/run/notify"]; !ok { c.state.BindMounts["/run/notify"] = notifyDir } @@ -1199,7 +1199,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO for _, del := range cleanup { file := filepath.Join(c.bundlePath(), del) if err := os.Remove(file); err != nil { - logrus.Debugf("unable to remove file %s", file) + logrus.Debugf("Unable to remove file %s", file) } } } @@ -1299,7 +1299,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti var netStatus map[string]types.StatusBlock _, err := metadata.ReadJSONFile(&netStatus, c.bundlePath(), metadata.NetworkStatusFile) if err != nil { - logrus.Infof("failed to unmarshal network status, cannot restore the same ip/mac: %v", err) + logrus.Infof("Failed to unmarshal network status, cannot restore the same ip/mac: %v", err) } // If the restored container should get a new name, the IP address of // the container will not be restored. This assumes that if a new name is @@ -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 } @@ -1349,7 +1349,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti defer func() { if retErr != nil { if err := c.cleanup(ctx); err != nil { - logrus.Errorf("error cleaning up container %s: %v", c.ID(), err) + logrus.Errorf("Cleaning up container %s: %v", c.ID(), err) } } }() @@ -1903,11 +1903,11 @@ func (c *Container) generateResolvConf() (string, error) { for _, nsIP := range status.DNSServerIPs { networkNameServers = append(networkNameServers, nsIP.String()) } - logrus.Debugf("adding nameserver(s) from network status of '%q'", status.DNSServerIPs) + logrus.Debugf("Adding nameserver(s) from network status of '%q'", status.DNSServerIPs) } if status.DNSSearchDomains != nil { networkSearchDomains = append(networkSearchDomains, status.DNSSearchDomains...) - logrus.Debugf("adding search domain(s) from network status of '%q'", status.DNSSearchDomains) + logrus.Debugf("Adding search domain(s) from network status of '%q'", status.DNSSearchDomains) } } @@ -1956,7 +1956,7 @@ func (c *Container) generateResolvConf() (string, error) { if c.config.NetMode.IsSlirp4netns() { slirp4netnsDNS, err := GetSlirp4netnsDNS(c.slirp4netnsSubnet) if err != nil { - logrus.Warn("failed to determine Slirp4netns DNS: ", err.Error()) + logrus.Warn("Failed to determine Slirp4netns DNS: ", err.Error()) } else { nameservers = append([]string{slirp4netnsDNS.String()}, nameservers...) } @@ -2058,7 +2058,7 @@ func (c *Container) getHosts() string { // When using slirp4netns, the interface gets a static IP slirp4netnsIP, err := GetSlirp4netnsIP(c.slirp4netnsSubnet) if err != nil { - logrus.Warnf("failed to determine slirp4netnsIP: %v", err.Error()) + logrus.Warnf("Failed to determine slirp4netnsIP: %v", err.Error()) } else { hosts += fmt.Sprintf("# used by slirp4netns\n%s\t%s %s\n", slirp4netnsIP.String(), c.Hostname(), c.config.Name) } @@ -2109,12 +2109,12 @@ func (c *Container) getHosts() string { } else if c.config.NetMode.IsSlirp4netns() { gatewayIP, err := GetSlirp4netnsGateway(c.slirp4netnsSubnet) if err != nil { - logrus.Warn("failed to determine gatewayIP: ", err.Error()) + logrus.Warn("Failed to determine gatewayIP: ", err.Error()) } else { hosts += fmt.Sprintf("%s host.containers.internal\n", gatewayIP.String()) } } else { - logrus.Debug("network configuration does not support host.containers.internal address") + logrus.Debug("Network configuration does not support host.containers.internal address") } } diff --git a/libpod/container_log.go b/libpod/container_log.go index 89dd5e8b0..18840bff2 100644 --- a/libpod/container_log.go +++ b/libpod/container_log.go @@ -18,7 +18,7 @@ import ( var logDrivers []string func init() { - logDrivers = append(logDrivers, define.KubernetesLogging, define.NoLogging) + logDrivers = append(logDrivers, define.KubernetesLogging, define.NoLogging, define.PassthroughLogging) } // Log is a runtime function that can read one or more container logs. @@ -34,6 +34,8 @@ func (r *Runtime) Log(ctx context.Context, containers []*Container, options *log // ReadLog reads a containers log based on the input options and returns log lines over a channel. func (c *Container) ReadLog(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error { switch c.LogDriver() { + case define.PassthroughLogging: + return errors.Wrapf(define.ErrNoLogs, "this container is using the 'passthrough' log driver, cannot read logs") case define.NoLogging: return errors.Wrapf(define.ErrNoLogs, "this container is using the 'none' log driver, cannot read logs") case define.JournaldLogging: @@ -83,7 +85,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption } nll, err := logs.NewLogLine(line.Text) if err != nil { - logrus.Errorf("Error getting new log line: %v", err) + logrus.Errorf("Getting new log line: %v", err) continue } if nll.Partial() { @@ -108,7 +110,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption state, err := c.State() if err != nil || state != define.ContainerStateRunning { if err != nil && errors.Cause(err) != define.ErrNoSuchCtr { - logrus.Errorf("Error getting container state: %v", err) + logrus.Errorf("Getting container state: %v", err) } go func() { // Make sure to wait at least for the poll duration @@ -116,7 +118,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption time.Sleep(watch.POLL_DURATION) tailError := t.StopAtEOF() if tailError != nil && tailError.Error() != "tail: stop at eof" { - logrus.Errorf("Error stopping logger: %v", tailError) + logrus.Errorf("Stopping logger: %v", tailError) } }() return nil @@ -132,7 +134,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption } go func() { if err := c.runtime.Events(ctx, eventOptions); err != nil { - logrus.Errorf("Error waiting for container to exit: %v", err) + logrus.Errorf("Waiting for container to exit: %v", err) } }() // Now wait for the died event and signal to finish @@ -143,7 +145,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption time.Sleep(watch.POLL_DURATION) tailError := t.StopAtEOF() if tailError != nil && fmt.Sprintf("%v", tailError) != "tail: stop at eof" { - logrus.Errorf("Error stopping logger: %v", tailError) + logrus.Errorf("Stopping logger: %v", tailError) } }() } 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/define/config.go b/libpod/define/config.go index 6c426f2ec..a5cf07afc 100644 --- a/libpod/define/config.go +++ b/libpod/define/config.go @@ -78,6 +78,9 @@ const JSONLogging = "json-file" // NoLogging is the string conmon expects when specifying to use no log driver whatsoever const NoLogging = "none" +// PassthroughLogging is the string conmon expects when specifying to use the passthrough driver +const PassthroughLogging = "passthrough" + // Strings used for --sdnotify option to podman const ( SdNotifyModeContainer = "container" @@ -87,3 +90,6 @@ const ( // DefaultRlimitValue is the value set by default for nofile and nproc const RLimitDefaultValue = uint64(1048576) + +// BindMountPrefix distinguishes its annotations from others +const BindMountPrefix = "bind-mount-options:" diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go index 90703a807..7decb18a8 100644 --- a/libpod/define/container_inspect.go +++ b/libpod/define/container_inspect.go @@ -202,10 +202,16 @@ type InspectContainerState struct { Error string `json:"Error"` // TODO StartedAt time.Time `json:"StartedAt"` FinishedAt time.Time `json:"FinishedAt"` - Healthcheck HealthCheckResults `json:"Healthcheck,omitempty"` + Health HealthCheckResults `json:"Health,omitempty"` Checkpointed bool `json:"Checkpointed,omitempty"` } +// Healthcheck returns the HealthCheckResults. This is used for old podman compat +// to make the "Healthcheck" key available in the go template. +func (s *InspectContainerState) Healthcheck() HealthCheckResults { + return s.Health +} + // HealthCheckResults describes the results/logs from a healthcheck type HealthCheckResults struct { // Status healthy or unhealthy diff --git a/libpod/events.go b/libpod/events.go index 22c51aeec..342af02d2 100644 --- a/libpod/events.go +++ b/libpod/events.go @@ -33,7 +33,7 @@ func (c *Container) newContainerEvent(status events.Status) { } if err := c.runtime.eventer.Write(e); err != nil { - logrus.Errorf("unable to write pod event: %q", err) + logrus.Errorf("Unable to write pod event: %q", err) } } @@ -46,7 +46,7 @@ func (c *Container) newContainerExitedEvent(exitCode int32) { e.Type = events.Container e.ContainerExitCode = int(exitCode) if err := c.runtime.eventer.Write(e); err != nil { - logrus.Errorf("unable to write container exited event: %q", err) + logrus.Errorf("Unable to write container exited event: %q", err) } } @@ -61,7 +61,7 @@ func (c *Container) newExecDiedEvent(sessionID string, exitCode int) { e.Attributes = make(map[string]string) e.Attributes["execID"] = sessionID if err := c.runtime.eventer.Write(e); err != nil { - logrus.Errorf("unable to write exec died event: %q", err) + logrus.Errorf("Unable to write exec died event: %q", err) } } @@ -73,7 +73,7 @@ func (c *Container) newNetworkEvent(status events.Status, netName string) { e.Type = events.Network e.Network = netName if err := c.runtime.eventer.Write(e); err != nil { - logrus.Errorf("unable to write pod event: %q", err) + logrus.Errorf("Unable to write pod event: %q", err) } } @@ -84,7 +84,7 @@ func (p *Pod) newPodEvent(status events.Status) { e.Name = p.Name() e.Type = events.Pod if err := p.runtime.eventer.Write(e); err != nil { - logrus.Errorf("unable to write pod event: %q", err) + logrus.Errorf("Unable to write pod event: %q", err) } } @@ -94,7 +94,7 @@ func (r *Runtime) newSystemEvent(status events.Status) { e.Type = events.System if err := r.eventer.Write(e); err != nil { - logrus.Errorf("unable to write system event: %q", err) + logrus.Errorf("Unable to write system event: %q", err) } } @@ -104,7 +104,7 @@ func (v *Volume) newVolumeEvent(status events.Status) { e.Name = v.Name() e.Type = events.Volume if err := v.runtime.eventer.Write(e); err != nil { - logrus.Errorf("unable to write volume event: %q", err) + logrus.Errorf("Unable to write volume event: %q", err) } } diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go index 3e16d8679..72e03355a 100644 --- a/libpod/events/journal_linux.go +++ b/libpod/events/journal_linux.go @@ -195,7 +195,7 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) { / if code, ok := entry.Fields["PODMAN_EXIT_CODE"]; ok { intCode, err := strconv.Atoi(code) if err != nil { - logrus.Errorf("Error parsing event exit code %s", code) + logrus.Errorf("Parsing event exit code %s", code) } else { newEvent.ContainerExitCode = intCode } diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go index c32ba85cb..91f031513 100644 --- a/libpod/healthcheck.go +++ b/libpod/healthcheck.go @@ -162,7 +162,7 @@ func newHealthCheckLog(start, end time.Time, exitCode int, log string) define.He // updatedHealthCheckStatus updates the health status of the container // in the healthcheck log func (c *Container) updateHealthStatus(status string) error { - healthCheck, err := c.GetHealthCheckLog() + healthCheck, err := c.getHealthCheckLog() if err != nil { return err } @@ -176,7 +176,7 @@ func (c *Container) updateHealthStatus(status string) error { // UpdateHealthCheckLog parses the health check results and writes the log func (c *Container) updateHealthCheckLog(hcl define.HealthCheckLog, inStartPeriod bool) error { - healthCheck, err := c.GetHealthCheckLog() + healthCheck, err := c.getHealthCheckLog() if err != nil { return err } @@ -213,10 +213,11 @@ func (c *Container) healthCheckLogPath() string { return filepath.Join(filepath.Dir(c.state.RunDir), "healthcheck.log") } -// GetHealthCheckLog returns HealthCheck results by reading the container's +// getHealthCheckLog returns HealthCheck results by reading the container's // health check log file. If the health check log file does not exist, then // an empty healthcheck struct is returned -func (c *Container) GetHealthCheckLog() (define.HealthCheckResults, error) { +// The caller should lock the container before this function is called. +func (c *Container) getHealthCheckLog() (define.HealthCheckResults, error) { var healthCheck define.HealthCheckResults if _, err := os.Stat(c.healthCheckLogPath()); os.IsNotExist(err) { return healthCheck, nil @@ -236,7 +237,12 @@ func (c *Container) HealthCheckStatus() (string, error) { if !c.HasHealthCheck() { return "", errors.Errorf("container %s has no defined healthcheck", c.ID()) } - results, err := c.GetHealthCheckLog() + c.lock.Lock() + defer c.lock.Unlock() + if err := c.syncContainer(); err != nil { + return "", err + } + results, err := c.getHealthCheckLog() if err != nil { return "", errors.Wrapf(err, "unable to get healthcheck log for %s", c.ID()) } diff --git a/libpod/info.go b/libpod/info.go index 36dc8bc2a..a2fd18491 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -186,7 +186,7 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) { conmonInfo, ociruntimeInfo, err := r.defaultOCIRuntime.RuntimeInfo() if err != nil { - logrus.Errorf("Error getting info on OCI runtime %s: %v", r.defaultOCIRuntime.Name(), err) + logrus.Errorf("Getting info on OCI runtime %s: %v", r.defaultOCIRuntime.Name(), err) } else { info.Conmon = conmonInfo info.OCIRuntime = ociruntimeInfo diff --git a/libpod/kube.go b/libpod/kube.go index 9b96dd99d..bf86a9d16 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -1,9 +1,11 @@ package libpod import ( + "context" "fmt" "math/rand" "os" + "reflect" "sort" "strconv" "strings" @@ -27,14 +29,14 @@ import ( // GenerateForKube takes a slice of libpod containers and generates // one v1.Pod description that includes just a single container. -func GenerateForKube(ctrs []*Container) (*v1.Pod, error) { +func GenerateForKube(ctx context.Context, ctrs []*Container) (*v1.Pod, error) { // Generate the v1.Pod yaml description - return simplePodWithV1Containers(ctrs) + return simplePodWithV1Containers(ctx, ctrs) } // GenerateForKube takes a slice of libpod containers and generates // one v1.Pod description -func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) { +func (p *Pod) GenerateForKube(ctx context.Context) (*v1.Pod, []v1.ServicePort, error) { // Generate the v1.Pod yaml description var ( ports []v1.ContainerPort //nolint @@ -78,7 +80,7 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) { servicePorts = containerPortsToServicePorts(ports) hostNetwork = infraContainer.NetworkMode() == string(namespaces.NetworkMode(specgen.Host)) } - pod, err := p.podWithContainers(allContainers, ports, hostNetwork) + pod, err := p.podWithContainers(ctx, allContainers, ports, hostNetwork) if err != nil { return nil, servicePorts, err } @@ -88,7 +90,7 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) { // 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: @@ -218,7 +220,7 @@ func containersToServicePorts(containers []v1.Container) []v1.ServicePort { return sps } -func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPort, hostNetwork bool) (*v1.Pod, error) { +func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, ports []v1.ContainerPort, hostNetwork bool) (*v1.Pod, error) { deDupPodVolumes := make(map[string]*v1.Volume) first := true podContainers := make([]v1.Container, 0, len(containers)) @@ -239,11 +241,13 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor isInit := ctr.IsInitCtr() - ctr, volumes, _, err := containerToV1Container(ctr) + ctr, volumes, _, annotations, err := containerToV1Container(ctx, ctr) if err != nil { return nil, err } - + for k, v := range annotations { + podAnnotations[define.BindMountPrefix+k] = v + } // Since port bindings for the pod are handled by the // infra container, wipe them here. ctr.Ports = nil @@ -251,7 +255,9 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor // 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 } @@ -267,7 +273,7 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor deDupPodVolumes[vol.Name] = &vol } } else { - _, _, infraDNS, err := containerToV1Container(ctr) + _, _, infraDNS, _, err := containerToV1Container(ctx, ctr) if err != nil { return nil, err } @@ -337,7 +343,7 @@ func newPodObject(podName string, annotations map[string]string, initCtrs, conta // simplePodWithV1Containers is a function used by inspect when kube yaml needs to be generated // for a single container. we "insert" that container description in a pod. -func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) { +func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod, error) { kubeCtrs := make([]v1.Container, 0, len(ctrs)) kubeInitCtrs := []v1.Container{} kubeVolumes := make([]v1.Volume, 0) @@ -355,17 +361,19 @@ func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) { if !ctr.HostNetwork() { hostNetwork = false } - kubeCtr, kubeVols, ctrDNS, err := containerToV1Container(ctr) + kubeCtr, kubeVols, ctrDNS, annotations, err := containerToV1Container(ctx, ctr) if err != nil { return nil, err } + for k, v := range annotations { + kubeAnnotations[define.BindMountPrefix+k] = v + } if isInit { kubeInitCtrs = append(kubeInitCtrs, kubeCtr) } else { kubeCtrs = append(kubeCtrs, kubeCtr) } kubeVolumes = append(kubeVolumes, kubeVols...) - // Combine DNS information in sum'd structure if ctrDNS != nil { // nameservers @@ -411,42 +419,44 @@ func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) { // containerToV1Container converts information we know about a libpod container // to a V1.Container specification. -func containerToV1Container(c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, error) { +func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, map[string]string, error) { kubeContainer := v1.Container{} kubeVolumes := []v1.Volume{} + annotations := make(map[string]string) kubeSec, err := generateKubeSecurityContext(c) if err != nil { - return kubeContainer, kubeVolumes, nil, err + return kubeContainer, kubeVolumes, nil, annotations, err } // 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) - return kubeContainer, kubeVolumes, nil, errors.Wrapf(define.ErrNotImplemented, "linux devices") + kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.config.Spec.Linux.Devices) + return kubeContainer, kubeVolumes, nil, annotations, errors.Wrapf(define.ErrNotImplemented, "linux devices") } if len(c.config.UserVolumes) > 0 { - volumeMounts, volumes, err := libpodMountsToKubeVolumeMounts(c) + volumeMounts, volumes, localAnnotations, err := libpodMountsToKubeVolumeMounts(c) if err != nil { - return kubeContainer, kubeVolumes, nil, err + return kubeContainer, kubeVolumes, nil, nil, err } + annotations = localAnnotations kubeContainer.VolumeMounts = volumeMounts kubeVolumes = append(kubeVolumes, volumes...) } envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env) if err != nil { - return kubeContainer, kubeVolumes, nil, err + return kubeContainer, kubeVolumes, nil, annotations, err } portmappings, err := c.PortMappings() if err != nil { - return kubeContainer, kubeVolumes, nil, err + return kubeContainer, kubeVolumes, nil, annotations, err } ports, err := ocicniPortMappingToContainerPort(portmappings) if err != nil { - return kubeContainer, kubeVolumes, nil, err + return kubeContainer, kubeVolumes, nil, annotations, err } // Handle command and arguments. @@ -463,6 +473,17 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, *v1.PodDNS _, image := c.Image() kubeContainer.Image = image kubeContainer.Stdin = c.Stdin() + img, _, err := c.runtime.libimageRuntime.LookupImage(image, nil) + if err != nil { + return kubeContainer, kubeVolumes, nil, annotations, err + } + imgData, err := img.Inspect(ctx, false) + if err != nil { + return kubeContainer, kubeVolumes, nil, annotations, err + } + if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) { + kubeContainer.Command = nil + } kubeContainer.WorkingDir = c.WorkingDir() kubeContainer.Ports = ports @@ -540,7 +561,7 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, *v1.PodDNS } dns.Options = dnsOptions } - return kubeContainer, kubeVolumes, &dns, nil + return kubeContainer, kubeVolumes, &dns, annotations, nil } // ocicniPortMappingToContainerPort takes an ocicni portmapping and converts @@ -591,16 +612,23 @@ func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) { } // libpodMountsToKubeVolumeMounts converts the containers mounts to a struct kube understands -func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, error) { +func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, map[string]string, error) { namedVolumes, mounts := c.sortUserVolumes(c.config.Spec) vms := make([]v1.VolumeMount, 0, len(mounts)) vos := make([]v1.Volume, 0, len(mounts)) + annotations := make(map[string]string) var suffix string for index, m := range mounts { + for _, opt := range m.Options { + if opt == "Z" || opt == "z" { + annotations[m.Source] = opt + break + } + } vm, vo, err := generateKubeVolumeMount(m) if err != nil { - return vms, vos, err + return vms, vos, annotations, err } // Name will be the same, so use the index as suffix suffix = fmt.Sprintf("-%d", index) @@ -614,7 +642,7 @@ func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume vms = append(vms, vm) vos = append(vos, vo) } - return vms, vos, nil + return vms, vos, annotations, nil } // generateKubePersistentVolumeClaim converts a ContainerNamedVolume to a Kubernetes PersistentVolumeClaim diff --git a/libpod/lock/file/file_lock.go b/libpod/lock/file/file_lock.go index 2643c9211..4685872b6 100644 --- a/libpod/lock/file/file_lock.go +++ b/libpod/lock/file/file_lock.go @@ -139,7 +139,7 @@ func (locks *FileLocks) DeallocateAllLocks() error { err := os.Remove(p) if err != nil { lastErr = err - logrus.Errorf("deallocating lock %s", p) + logrus.Errorf("Deallocating lock %s", p) } } return lastErr diff --git a/libpod/lock/shm/shm_lock_nocgo.go b/libpod/lock/shm/shm_lock_nocgo.go index ea1488c90..627344d9c 100644 --- a/libpod/lock/shm/shm_lock_nocgo.go +++ b/libpod/lock/shm/shm_lock_nocgo.go @@ -16,7 +16,7 @@ type SHMLocks struct { // numLocks must not be 0, and may be rounded up to a multiple of the bitmap // size used by the underlying implementation. func CreateSHMLock(path string, numLocks uint32) (*SHMLocks, error) { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return &SHMLocks{}, nil } @@ -24,13 +24,13 @@ func CreateSHMLock(path string, numLocks uint32) (*SHMLocks, error) { // POSIX semaphores. numLocks must match the number of locks the shared memory // segment was created with. func OpenSHMLock(path string, numLocks uint32) (*SHMLocks, error) { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return &SHMLocks{}, nil } // GetMaxLocks returns the maximum number of locks in the SHM func (locks *SHMLocks) GetMaxLocks() uint32 { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return 0 } @@ -40,7 +40,7 @@ func (locks *SHMLocks) GetMaxLocks() uint32 { // fail to release, causing a program freeze. // Close() is only intended to be used while testing the locks. func (locks *SHMLocks) Close() error { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return nil } @@ -50,7 +50,7 @@ func (locks *SHMLocks) Close() error { // Allocations past the maximum number of locks given when the SHM segment was // created will result in an error, and no semaphore will be allocated. func (locks *SHMLocks) AllocateSemaphore() (uint32, error) { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return 0, nil } @@ -59,7 +59,7 @@ func (locks *SHMLocks) AllocateSemaphore() (uint32, error) { // If the semaphore is already in use or the index is invalid an error will be // returned. func (locks *SHMLocks) AllocateGivenSemaphore(sem uint32) error { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return nil } @@ -67,14 +67,14 @@ func (locks *SHMLocks) AllocateGivenSemaphore(sem uint32) error { // reallocated to another container or pod. // The given semaphore must be already allocated, or an error will be returned. func (locks *SHMLocks) DeallocateSemaphore(sem uint32) error { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return nil } // DeallocateAllSemaphores frees all semaphores so they can be reallocated to // other containers and pods. func (locks *SHMLocks) DeallocateAllSemaphores() error { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return nil } @@ -86,7 +86,7 @@ func (locks *SHMLocks) DeallocateAllSemaphores() error { // but before the caller has queried the database to determine this, will // succeed. func (locks *SHMLocks) LockSemaphore(sem uint32) error { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return nil } @@ -97,6 +97,6 @@ func (locks *SHMLocks) LockSemaphore(sem uint32) error { // but before the caller has queried the database to determine this, will // succeed. func (locks *SHMLocks) UnlockSemaphore(sem uint32) error { - logrus.Error("locks are not supported without cgo") + logrus.Error("Locks are not supported without cgo") return nil } diff --git a/libpod/logs/log.go b/libpod/logs/log.go index a584de0ee..19a121fe9 100644 --- a/libpod/logs/log.go +++ b/libpod/logs/log.go @@ -267,6 +267,6 @@ func (l *LogLine) Write(stdout io.Writer, stderr io.Writer, logOpts *LogOptions) } default: // Warn the user if the device type does not match. Most likely the file is corrupted. - logrus.Warnf("unknown Device type '%s' in log file from Container %s", l.Device, l.CID) + logrus.Warnf("Unknown Device type '%s' in log file from Container %s", l.Device, l.CID) } } diff --git a/libpod/network/cni/cni_conversion.go b/libpod/network/cni/cni_conversion.go index d69dd7eb3..93d871767 100644 --- a/libpod/network/cni/cni_conversion.go +++ b/libpod/network/cni/cni_conversion.go @@ -14,7 +14,6 @@ import ( "time" "github.com/containernetworking/cni/libcni" - "github.com/containernetworking/cni/pkg/version" "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/libpod/network/util" pkgutil "github.com/containers/podman/v3/pkg/util" @@ -105,7 +104,7 @@ func createNetworkFromCNIConfigList(conf *libcni.NetworkConfigList, confPath str default: // A warning would be good but users would get this warning everytime so keep this at info level. - logrus.Infof("unsupported CNI config type %s in %s, this network can still be used but inspect or list cannot show all information", + logrus.Infof("Unsupported CNI config type %s in %s, this network can still be used but inspect or list cannot show all information", firstPlugin.Network.Type, confPath) } @@ -283,7 +282,10 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ ipMasq = false } // create CNI plugin configuration - ncList := newNcList(network.Name, version.Current(), network.Labels, network.Options) + // explicitly use CNI version 0.4.0 here, to use v1.0.0 at least containernetwork-plugins-1.0.1 has to be installed + // the dnsname plugin also needs to be updated for 1.0.0 + // TODO change to 1.0.0 when most distros support it + ncList := newNcList(network.Name, "0.4.0", network.Labels, network.Options) var plugins []interface{} switch network.Driver { diff --git a/libpod/network/cni/cni_exec.go b/libpod/network/cni/cni_exec.go index c4d7f49f7..ae857bcfb 100644 --- a/libpod/network/cni/cni_exec.go +++ b/libpod/network/cni/cni_exec.go @@ -30,6 +30,7 @@ import ( "github.com/containernetworking/cni/pkg/invoke" "github.com/containernetworking/cni/pkg/version" + "github.com/containers/podman/v3/pkg/rootless" ) type cniExec struct { @@ -67,6 +68,17 @@ func (e *cniExec) ExecPlugin(ctx context.Context, pluginPath string, stdinData [ c.Stdout = stdout c.Stderr = stderr + // The dnsname plugin tries to use XDG_RUNTIME_DIR to store files. + // podman run will have XDG_RUNTIME_DIR set and thus the cni plugin can use + // it. The problem is that XDG_RUNTIME_DIR is unset for the conmon process + // for rootful users. This causes issues since the cleanup process is spawned + // by conmon and thus not have XDG_RUNTIME_DIR set to same value as podman run. + // Because of it dnsname will not find the config files and cannot correctly cleanup. + // To fix this we should also unset XDG_RUNTIME_DIR for the cni plugins as rootful. + if !rootless.IsRootless() { + c.Env = append(c.Env, "XDG_RUNTIME_DIR=") + } + err := c.Run() if err != nil { return nil, annotatePluginError(err, pluginPath, stdout.Bytes(), stderr.Bytes()) diff --git a/libpod/network/cni/config.go b/libpod/network/cni/config.go index 2a6ad8eb3..3df155637 100644 --- a/libpod/network/cni/config.go +++ b/libpod/network/cni/config.go @@ -162,7 +162,7 @@ func (n *cniNetwork) NetworkRemove(nameOrID string) error { err = netlink.LinkDel(link) // only log the error, it is not fatal if err != nil { - logrus.Infof("failed to remove network interface %s: %v", network.libpodNet.NetworkInterface, err) + logrus.Infof("Failed to remove network interface %s: %v", network.libpodNet.NetworkInterface, err) } } } @@ -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/network.go b/libpod/network/cni/network.go index d77e63a5d..02801641e 100644 --- a/libpod/network/cni/network.go +++ b/libpod/network/cni/network.go @@ -127,7 +127,7 @@ func (n *cniNetwork) loadNetworks() error { conf, err := libcni.ConfListFromFile(file) if err != nil { // do not log ENOENT errors - if !os.IsNotExist(err) { + if !errors.Is(err, os.ErrNotExist) { logrus.Warnf("Error loading CNI config file %s: %v", file, err) } continue diff --git a/libpod/network/cni/run.go b/libpod/network/cni/run.go index b69953c4b..bd873f89b 100644 --- a/libpod/network/cni/run.go +++ b/libpod/network/cni/run.go @@ -10,7 +10,7 @@ import ( "github.com/containernetworking/cni/libcni" cnitypes "github.com/containernetworking/cni/pkg/types" - "github.com/containernetworking/cni/pkg/types/current" + types040 "github.com/containernetworking/cni/pkg/types/040" "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/network/types" @@ -107,14 +107,9 @@ func (n *cniNetwork) Setup(namespacePath string, options types.SetupOptions) (ma return nil, retErr } - var cnires *current.Result - cnires, retErr = current.GetResult(res) - if retErr != nil { - return nil, retErr - } - logrus.Debugf("cni result for container %s network %s: %v", options.ContainerID, name, cnires) + logrus.Debugf("cni result for container %s network %s: %v", options.ContainerID, name, res) var status types.StatusBlock - status, retErr = CNIResultToStatus(cnires) + status, retErr = CNIResultToStatus(res) if retErr != nil { return nil, retErr } @@ -125,8 +120,12 @@ func (n *cniNetwork) Setup(namespacePath string, options types.SetupOptions) (ma // CNIResultToStatus convert the cni result to status block // nolint:golint -func CNIResultToStatus(cniResult *current.Result) (types.StatusBlock, error) { +func CNIResultToStatus(res cnitypes.Result) (types.StatusBlock, error) { result := types.StatusBlock{} + cniResult, err := types040.GetResult(res) + if err != nil { + return result, err + } nameservers := make([]net.IP, 0, len(cniResult.DNS.Nameservers)) for _, nameserver := range cniResult.DNS.Nameservers { ip := net.ParseIP(nameserver) @@ -187,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 } @@ -274,7 +270,7 @@ func (n *cniNetwork) teardown(namespacePath string, options types.TeardownOption if err == nil { rt = newRt } else { - logrus.Warnf("failed to load cached network config: %v, falling back to loading network %s from disk", err, name) + logrus.Warnf("Failed to load cached network config: %v, falling back to loading network %s from disk", err, name) network := n.networks[name] if network == nil { multiErr = multierror.Append(multiErr, errors.Wrapf(define.ErrNoSuchNetwork, "network %s", name)) diff --git a/libpod/network/cni/run_test.go b/libpod/network/cni/run_test.go index f6da22a76..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{ @@ -1256,7 +1255,7 @@ var _ = Describe("run CNI", func() { Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("network somenet: network not found")) logString := logBuffer.String() - Expect(logString).To(ContainSubstring("failed to load cached network config")) + Expect(logString).To(ContainSubstring("Failed to load cached network config")) }) }) @@ -1283,7 +1282,7 @@ var _ = Describe("run CNI", func() { err = libpodNet.Teardown(netNSContainer.Path(), teardownOpts) Expect(err).To(BeNil()) logString := logBuffer.String() - Expect(logString).To(ContainSubstring("failed to load cached network config")) + Expect(logString).To(ContainSubstring("Failed to load cached network config")) }) }) }) diff --git a/libpod/network/types/network.go b/libpod/network/types/network.go index 6053ceb29..2fe4f3da2 100644 --- a/libpod/network/types/network.go +++ b/libpod/network/types/network.go @@ -32,11 +32,11 @@ type ContainerNetwork interface { // Network describes the Network attributes. type Network struct { // Name of the Network. - Name string `json:"name,omitempty"` + Name string `json:"name"` // ID of the Network. - ID string `json:"id,omitempty"` + ID string `json:"id"` // Driver for this Network, e.g. bridge, macvlan... - Driver string `json:"driver,omitempty"` + Driver string `json:"driver"` // InterfaceName is the network interface name on the host. NetworkInterface string `json:"network_interface,omitempty"` // Created contains the timestamp when this network was created. @@ -97,7 +97,7 @@ func (n *IPNet) UnmarshalText(text []byte) error { type Subnet struct { // Subnet for this Network in CIDR form. // swagger:strfmt string - Subnet IPNet `json:"subnet,omitempty"` + Subnet IPNet `json:"subnet"` // Gateway IP for this Network. // swagger:strfmt string Gateway net.IP `json:"gateway,omitempty"` @@ -134,14 +134,14 @@ type NetInterface struct { // Networks list of assigned subnets with their gateway. Networks []NetAddress `json:"networks,omitempty"` // MacAddress for this Interface. - MacAddress net.HardwareAddr `json:"mac_address,omitempty"` + MacAddress net.HardwareAddr `json:"mac_address"` } // NetAddress contains the subnet and gatway. type NetAddress struct { // Subnet of this NetAddress. Note that the subnet contains the // actual ip of the net interface and not the network address. - Subnet IPNet `json:"subnet,omitempty"` + Subnet IPNet `json:"subnet"` // Gateway for the Subnet. This can be nil if there is no gateway, e.g. internal network. Gateway net.IP `json:"gateway,omitempty"` } @@ -151,33 +151,35 @@ 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. StaticMAC net.HardwareAddr `json:"static_mac,omitempty"` // InterfaceName for this container. Required. - InterfaceName string `json:"interface_name,omitempty"` + InterfaceName string `json:"interface_name"` } // NetworkOptions for a given container. type NetworkOptions struct { // ContainerID is the container id, used for iptables comments and ipam allocation. - ContainerID string `json:"container_id,omitempty"` + ContainerID string `json:"container_id"` // ContainerName is the container name, used as dns name. - ContainerName string `json:"container_name,omitempty"` + ContainerName string `json:"container_name"` // PortMappings contains the port mappings for this container PortMappings []PortMapping `json:"port_mappings,omitempty"` // Networks contains all networks with the PerNetworkOptions. // The map should contain at least one element. - Networks map[string]PerNetworkOptions `json:"networks,omitempty"` + Networks map[string]PerNetworkOptions `json:"networks"` } // PortMapping is one or more ports that will be mapped into the container. type PortMapping struct { // HostIP is the IP that we will bind to on the host. // If unset, assumed to be 0.0.0.0 (all interfaces). - HostIP string `json:"host_ip,omitempty"` + HostIP string `json:"host_ip"` // ContainerPort is the port number that will be exposed from the // container. // Mandatory. @@ -186,7 +188,7 @@ type PortMapping struct { // the container. // If omitted, a random port on the host (guaranteed to be over 1024) // will be assigned. - HostPort uint16 `json:"host_port,omitempty"` + HostPort uint16 `json:"host_port"` // Range is the number of ports that will be forwarded, starting at // HostPort and ContainerPort and counting up. // This is 1-indexed, so 1 is assumed to be a single port (only the @@ -195,12 +197,12 @@ type PortMapping struct { // If unset, assumed to be 1 (a single port). // Both hostport + range and containerport + range must be less than // 65536. - Range uint16 `json:"range,omitempty"` + Range uint16 `json:"range"` // Protocol is the protocol forward. // Must be either "tcp", "udp", and "sctp", or some combination of these // separated by commas. // If unset, assumed to be TCP. - Protocol string `json:"protocol,omitempty"` + Protocol string `json:"protocol"` } // OCICNIPortMapping maps to the standard CNI portmapping Capability. diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 96b6fb298..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 } @@ -320,14 +355,14 @@ func (r *RootlessCNI) Cleanup(runtime *Runtime) error { } } if err != nil { - logrus.Errorf("failed to kill slirp4netns process: %s", err) + logrus.Errorf("Failed to kill slirp4netns process: %s", err) } err = os.RemoveAll(r.dir) if err != nil { logrus.Error(err) } } else if err != nil && !os.IsNotExist(err) { - logrus.Errorf("could not read rootless cni directory, skipping cleanup: %s", err) + logrus.Errorf("Could not read rootless cni directory, skipping cleanup: %s", err) } } return nil @@ -458,7 +493,7 @@ func (r *Runtime) GetRootlessCNINetNs(new bool) (*RootlessCNI, error) { defer func() { if err := cmd.Process.Release(); err != nil { - logrus.Errorf("unable to release command process: %q", err) + logrus.Errorf("Unable to release command process: %q", err) } }() @@ -635,10 +670,10 @@ func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q map[string]types.St defer func() { if retErr != nil { if err := netns.UnmountNS(ctrNS); err != nil { - logrus.Errorf("Error unmounting partially created network namespace for container %s: %v", ctr.ID(), err) + logrus.Errorf("Unmounting partially created network namespace for container %s: %v", ctr.ID(), err) } if err := ctrNS.Close(); err != nil { - logrus.Errorf("Error closing partially created network namespace for container %s: %v", ctr.ID(), err) + logrus.Errorf("Closing partially created network namespace for container %s: %v", ctr.ID(), 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 a5c035757..46cda89a9 100644 --- a/libpod/networking_slirp4netns.go +++ b/libpod/networking_slirp4netns.go @@ -210,7 +210,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error { var err error path, err = exec.LookPath("slirp4netns") if err != nil { - logrus.Errorf("could not find slirp4netns, the network namespace won't be configured: %v", err) + logrus.Errorf("Could not find slirp4netns, the network namespace won't be configured: %v", err) return nil } } @@ -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{} @@ -303,7 +303,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error { defer func() { servicereaper.AddPID(cmd.Process.Pid) if err := cmd.Process.Release(); err != nil { - logrus.Errorf("unable to release command process: %q", err) + logrus.Errorf("Unable to release command process: %q", err) } }() @@ -421,7 +421,7 @@ func waitForSync(syncR *os.File, cmd *exec.Cmd, logFile io.ReadSeeker, timeout t if status.Exited() { // Seek at the beginning of the file and read all its content if _, err := logFile.Seek(0, 0); err != nil { - logrus.Errorf("could not seek log file: %q", err) + logrus.Errorf("Could not seek log file: %q", err) } logContent, err := ioutil.ReadAll(logFile) if err != nil { @@ -506,7 +506,7 @@ func (r *Runtime) setupRootlessPortMappingViaRLK(ctr *Container, netnsPath strin defer func() { servicereaper.AddPID(cmd.Process.Pid) if err := cmd.Process.Release(); err != nil { - logrus.Errorf("unable to release rootlessport process: %q", err) + logrus.Errorf("Unable to release rootlessport process: %q", err) } }() if err := waitForSync(syncR, cmd, logFile, 3*time.Second); err != nil { @@ -559,7 +559,7 @@ func (r *Runtime) setupRootlessPortMappingViaSlirp(ctr *Container, cmd *exec.Cmd } defer func() { if err := conn.Close(); err != nil { - logrus.Errorf("unable to close connection: %q", err) + logrus.Errorf("Unable to close connection: %q", err) } }() hostIP := i.HostIP diff --git a/libpod/oci_attach_linux.go b/libpod/oci_attach_linux.go index de435b58a..d4d4a1076 100644 --- a/libpod/oci_attach_linux.go +++ b/libpod/oci_attach_linux.go @@ -40,7 +40,9 @@ func openUnixSocket(path string) (*net.UnixConn, error) { // Does not check if state is appropriate // started is only required if startContainer is true func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan define.TerminalSize, startContainer bool, started chan bool, attachRdy chan<- bool) error { - if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput { + passthrough := c.LogDriver() == define.PassthroughLogging + + if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput && !passthrough { return errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to") } if startContainer && started == nil { @@ -52,24 +54,27 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <- return err } - logrus.Debugf("Attaching to container %s", c.ID()) + var conn *net.UnixConn + if !passthrough { + logrus.Debugf("Attaching to container %s", c.ID()) - registerResizeFunc(resize, c.bundlePath()) + registerResizeFunc(resize, c.bundlePath()) - attachSock, err := c.AttachSocketPath() - if err != nil { - return err - } + attachSock, err := c.AttachSocketPath() + if err != nil { + return err + } - conn, err := openUnixSocket(attachSock) - if err != nil { - return errors.Wrapf(err, "failed to connect to container's attach socket: %v", attachSock) - } - defer func() { - if err := conn.Close(); err != nil { - logrus.Errorf("unable to close socket: %q", err) + conn, err = openUnixSocket(attachSock) + if err != nil { + return errors.Wrapf(err, "failed to connect to container's attach socket: %v", attachSock) } - }() + defer func() { + if err := conn.Close(); err != nil { + logrus.Errorf("unable to close socket: %q", err) + } + }() + } // If starting was requested, start the container and notify when that's // done. @@ -80,6 +85,10 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <- started <- true } + if passthrough { + return nil + } + receiveStdoutError, stdinDone := setupStdioChannels(streams, conn, detachKeys) if attachRdy != nil { attachRdy <- true @@ -142,7 +151,7 @@ func (c *Container) attachToExec(streams *define.AttachStreams, keys *string, se if newSize != nil { err = c.ociRuntime.ExecAttachResize(c, sessionID, *newSize) if err != nil { - logrus.Warn("resize failed", err) + logrus.Warnf("Resize failed: %v", err) } } @@ -153,7 +162,7 @@ func (c *Container) attachToExec(streams *define.AttachStreams, keys *string, se } defer func() { if err := conn.Close(); err != nil { - logrus.Errorf("unable to close socket: %q", err) + logrus.Errorf("Unable to close socket: %q", err) } }() @@ -210,7 +219,7 @@ func setupStdioChannels(streams *define.AttachStreams, conn *net.UnixConn, detac _, err = utils.CopyDetachable(conn, streams.InputStream, detachKeys) if err == nil { if connErr := conn.CloseWrite(); connErr != nil { - logrus.Errorf("unable to close conn: %q", connErr) + logrus.Errorf("Unable to close conn: %q", connErr) } } } diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go index 5a7677b04..822377bfe 100644 --- a/libpod/oci_conmon_exec_linux.go +++ b/libpod/oci_conmon_exec_linux.go @@ -528,7 +528,7 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp if newSize != nil { err = c.ociRuntime.ExecAttachResize(c, sessionID, *newSize) if err != nil { - logrus.Warn("resize failed", err) + logrus.Warnf("Resize failed: %v", err) } } @@ -540,7 +540,7 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp } defer func() { if err := conn.Close(); err != nil { - logrus.Errorf("unable to close socket: %q", err) + logrus.Errorf("Unable to close socket: %q", err) } }() diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index 831e89223..71a7b29fa 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -215,7 +215,7 @@ func (r *ConmonOCIRuntime) CreateContainer(ctr *Container, restoreOptions *Conta } defer func() { if err := unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS); err != nil { - logrus.Errorf("unable to clone new namespace: %q", err) + logrus.Errorf("Unable to clone new namespace: %q", err) } }() @@ -524,7 +524,7 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http. conn = newConn defer func() { if err := conn.Close(); err != nil { - logrus.Errorf("unable to close container %s attach socket: %q", ctr.ID(), err) + logrus.Errorf("Unable to close container %s attach socket: %q", ctr.ID(), err) } }() @@ -936,7 +936,7 @@ func waitPidStop(pid int, timeout time.Duration) error { close(done) return } - logrus.Errorf("Error pinging PID %d with signal 0: %v", pid, err) + logrus.Errorf("Pinging PID %d with signal 0: %v", pid, err) } time.Sleep(100 * time.Millisecond) } @@ -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 { @@ -1199,7 +1199,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co pid, err := readConmonPipeData(parentSyncPipe, ociLog) if err != nil { if err2 := r.DeleteContainer(ctr); err2 != nil { - logrus.Errorf("Error removing container %s from runtime after creation failed", ctr.ID()) + logrus.Errorf("Removing container %s from runtime after creation failed", ctr.ID()) } return err } @@ -1207,7 +1207,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co conmonPID, err := readConmonPidFile(ctr.config.ConmonPidFile) if err != nil { - logrus.Warnf("error reading conmon pid file for container %s: %v", ctr.ID(), err) + logrus.Warnf("Error reading conmon pid file for container %s: %v", ctr.ID(), err) } else if conmonPID > 0 { // conmon not having a pid file is a valid state, so don't set it if we don't have it logrus.Infof("Got Conmon PID as %d", conmonPID) @@ -1220,7 +1220,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co default: if sent, err := daemon.SdNotify(false, fmt.Sprintf("MAINPID=%d", conmonPID)); err != nil { - logrus.Errorf("Error notifying systemd of Conmon PID: %v", err) + logrus.Errorf("Notifying systemd of Conmon PID: %v", err) } else if sent { logrus.Debugf("Notify MAINPID sent successfully") } @@ -1288,6 +1288,8 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p logDriverArg = define.JournaldLogging case define.NoLogging: logDriverArg = define.NoLogging + case define.PassthroughLogging: + logDriverArg = define.PassthroughLogging case define.JSONLogging: fallthrough //lint:ignore ST1015 the default case has to be here @@ -1346,7 +1348,7 @@ func startCommandGivenSelinux(cmd *exec.Cmd, ctr *Container) error { defer func() { if err := os.Setenv("NOTIFY_SOCKET", ctr.notifySocket); err != nil { - logrus.Errorf("Error resetting NOTIFY_SOCKET=%s", ctr.notifySocket) + logrus.Errorf("Resetting NOTIFY_SOCKET=%s", ctr.notifySocket) } }() } @@ -1385,7 +1387,7 @@ func startCommandGivenSelinux(cmd *exec.Cmd, ctr *Container) error { // Ignore error returned from SetProcessLabel("") call, // can't recover. if labelErr := label.SetProcessLabel(""); labelErr != nil { - logrus.Errorf("unable to set process label: %q", err) + logrus.Errorf("Unable to set process label: %q", err) } runtime.UnlockOSThread() return err @@ -1608,7 +1610,7 @@ func httpAttachTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, cid numW, err2 := http.Write(buf[1:numR]) if err2 != nil { if err != nil { - logrus.Errorf("Error reading container %s STDOUT: %v", cid, err) + logrus.Errorf("Reading container %s STDOUT: %v", cid, err) } return err2 } else if numW+1 != numR { @@ -1618,7 +1620,7 @@ func httpAttachTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, cid // there isn't a delay on the terminal side. if err2 := http.Flush(); err2 != nil { if err != nil { - logrus.Errorf("Error reading container %s STDOUT: %v", cid, err) + logrus.Errorf("Reading container %s STDOUT: %v", cid, err) } return err2 } @@ -1670,7 +1672,7 @@ func httpAttachNonTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, numH, err2 := http.Write(headerBuf) if err2 != nil { if err != nil { - logrus.Errorf("Error reading container %s standard streams: %v", cid, err) + logrus.Errorf("Reading container %s standard streams: %v", cid, err) } return err2 @@ -1680,7 +1682,7 @@ func httpAttachNonTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, // of the protocol. if numH != 8 { if err != nil { - logrus.Errorf("Error reading container %s standard streams: %v", cid, err) + logrus.Errorf("Reading container %s standard streams: %v", cid, err) } return io.ErrShortWrite @@ -1689,13 +1691,13 @@ func httpAttachNonTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, numW, err2 := http.Write(buf[1:numR]) if err2 != nil { if err != nil { - logrus.Errorf("Error reading container %s standard streams: %v", cid, err) + logrus.Errorf("Reading container %s standard streams: %v", cid, err) } return err2 } else if numW+1 != numR { if err != nil { - logrus.Errorf("Error reading container %s standard streams: %v", cid, err) + logrus.Errorf("Reading container %s standard streams: %v", cid, err) } return io.ErrShortWrite @@ -1704,7 +1706,7 @@ func httpAttachNonTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter, // there isn't a delay on the terminal side. if err2 := http.Flush(); err2 != nil { if err != nil { - logrus.Errorf("Error reading container %s STDOUT: %v", cid, err) + logrus.Errorf("Reading container %s STDOUT: %v", cid, err) } return err2 } diff --git a/libpod/oci_util.go b/libpod/oci_util.go index 7db267915..c1afc0d20 100644 --- a/libpod/oci_util.go +++ b/libpod/oci_util.go @@ -72,7 +72,7 @@ func bindPorts(ports []types.OCICNIPortMapping) ([]*os.File, error) { // note that this does not affect the fd, see the godoc for server.File() err = server.Close() if err != nil { - logrus.Warnf("failed to close connection: %v", err) + logrus.Warnf("Failed to close connection: %v", err) } case "tcp": @@ -106,13 +106,13 @@ func bindPorts(ports []types.OCICNIPortMapping) ([]*os.File, error) { // note that this does not affect the fd, see the godoc for server.File() err = server.Close() if err != nil { - logrus.Warnf("failed to close connection: %v", err) + logrus.Warnf("Failed to close connection: %v", err) } case "sctp": if !notifySCTP { notifySCTP = true - logrus.Warnf("port reservation for SCTP is not supported") + logrus.Warnf("Port reservation for SCTP is not supported") } default: return nil, fmt.Errorf("unknown protocol %s", i.Protocol) diff --git a/libpod/options.go b/libpod/options.go index a80f51c6a..553af43fd 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1114,7 +1114,7 @@ func WithLogDriver(driver string) CtrCreateOption { switch driver { case "": return errors.Wrapf(define.ErrInvalidArg, "log driver must be set") - case define.JournaldLogging, define.KubernetesLogging, define.JSONLogging, define.NoLogging: + case define.JournaldLogging, define.KubernetesLogging, define.JSONLogging, define.NoLogging, define.PassthroughLogging: break default: return errors.Wrapf(define.ErrInvalidArg, "invalid log driver") 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 ef4a85bcb..05349aff5 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 { @@ -43,7 +43,7 @@ func (p *Pod) startInitContainers(ctx context.Context) error { } // Removing a container this way requires an explicit call to clean up the db if err := p.runtime.state.RemoveContainerFromPod(p, initCon); err != nil { - logrus.Errorf("Error removing container %s from database: %v", initCon.ID(), err) + logrus.Errorf("Removing container %s from database: %v", initCon.ID(), err) } icLock.Unlock() } @@ -591,10 +591,10 @@ 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 @@ -618,30 +618,30 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) { } } - 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/pod_internal.go b/libpod/pod_internal.go index 079b631a0..d903b8719 100644 --- a/libpod/pod_internal.go +++ b/libpod/pod_internal.go @@ -71,7 +71,7 @@ func (p *Pod) refresh() error { case config.SystemdCgroupsManager: cgroupPath, err := systemdSliceFromPath(p.config.CgroupParent, fmt.Sprintf("libpod_pod_%s", p.ID())) if err != nil { - logrus.Errorf("Error creating CGroup for pod %s: %v", p.ID(), err) + logrus.Errorf("Creating CGroup for pod %s: %v", p.ID(), err) } p.state.CgroupPath = cgroupPath case config.CgroupfsCgroupsManager: diff --git a/libpod/reset.go b/libpod/reset.go index 8e753e845..7b25ed680 100644 --- a/libpod/reset.go +++ b/libpod/reset.go @@ -27,7 +27,7 @@ func (r *Runtime) Reset(ctx context.Context) error { if errors.Cause(err) == define.ErrNoSuchPod { continue } - logrus.Errorf("Error removing Pod %s: %v", p.ID(), err) + logrus.Errorf("Removing Pod %s: %v", p.ID(), err) } } @@ -42,13 +42,13 @@ func (r *Runtime) Reset(ctx context.Context) error { if errors.Cause(err) == define.ErrNoSuchCtr { continue } - logrus.Errorf("Error removing container %s: %v", c.ID(), err) + logrus.Errorf("Removing container %s: %v", c.ID(), err) } } } if err := r.stopPauseProcess(); err != nil { - logrus.Errorf("Error stopping pause process: %v", err) + logrus.Errorf("Stopping pause process: %v", err) } rmiOptions := &libimage.RemoveImagesOptions{Filters: []string{"readonly=false"}} @@ -65,7 +65,7 @@ func (r *Runtime) Reset(ctx context.Context) error { if errors.Cause(err) == define.ErrNoSuchVolume { continue } - logrus.Errorf("Error removing volume %s: %v", v.config.Name, err) + logrus.Errorf("Removing volume %s: %v", v.config.Name, err) } } @@ -123,7 +123,7 @@ func (r *Runtime) Reset(ctx context.Context) error { if storageConfPath, err := storage.DefaultConfigFile(rootless.IsRootless()); err == nil { if _, err = os.Stat(storageConfPath); err == nil { fmt.Printf("A storage.conf file exists at %s\n", storageConfPath) - fmt.Println("You should remove this file if you did not modified the configuration.") + fmt.Println("You should remove this file if you did not modify the configuration.") } } else { if prevError != nil { diff --git a/libpod/runtime.go b/libpod/runtime.go index a2279e56d..27885bf5c 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -211,7 +211,7 @@ func newRuntimeFromConfig(ctx context.Context, conf *config.Config, options ...R os.Exit(1) return nil }); err != nil && errors.Cause(err) != shutdown.ErrHandlerExists { - logrus.Errorf("Error registering shutdown handler for libpod: %v", err) + logrus.Errorf("Registering shutdown handler for libpod: %v", err) } if err := shutdown.Start(); err != nil { @@ -344,7 +344,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { logrus.Warn(msg) } } else { - logrus.Warn(msg) + logrus.Warnf("%s: %v", msg, err) } } } @@ -388,7 +388,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { // Don't forcibly shut down // We could be opening a store in use by another libpod if _, err := store.Shutdown(false); err != nil { - logrus.Errorf("Error removing store for partially-created runtime: %s", err) + logrus.Errorf("Removing store for partially-created runtime: %s", err) } } }() @@ -436,7 +436,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { // This will allow us to ship configs including optional // runtimes that might not be installed (crun, kata). // Only a infof so default configs don't spec errors. - logrus.Debugf("configured OCI runtime %s initialization failed: %v", name, err) + logrus.Debugf("Configured OCI runtime %s initialization failed: %v", name, err) continue } @@ -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") } @@ -767,7 +780,7 @@ func (r *Runtime) libimageEvents() { Type: events.Image, } if err := r.eventer.Write(e); err != nil { - logrus.Errorf("unable to write image event: %q", err) + logrus.Errorf("Unable to write image event: %q", err) } } @@ -807,11 +820,11 @@ func (r *Runtime) Shutdown(force bool) error { if force { ctrs, err := r.state.AllContainers() if err != nil { - logrus.Errorf("Error retrieving containers from database: %v", err) + logrus.Errorf("Retrieving containers from database: %v", err) } else { for _, ctr := range ctrs { if err := ctr.StopWithTimeout(r.config.Engine.StopTimeout); err != nil { - logrus.Errorf("Error stopping container %s: %v", ctr.ID(), err) + logrus.Errorf("Stopping container %s: %v", ctr.ID(), err) } } } @@ -833,7 +846,7 @@ func (r *Runtime) Shutdown(force bool) error { } if err := r.state.Close(); err != nil { if lastError != nil { - logrus.Errorf("%v", lastError) + logrus.Error(lastError) } lastError = err } @@ -879,17 +892,17 @@ func (r *Runtime) refresh(alivePath string) error { // until this has run. for _, ctr := range ctrs { if err := ctr.refresh(); err != nil { - logrus.Errorf("Error refreshing container %s: %v", ctr.ID(), err) + logrus.Errorf("Refreshing container %s: %v", ctr.ID(), err) } } for _, pod := range pods { if err := pod.refresh(); err != nil { - logrus.Errorf("Error refreshing pod %s: %v", pod.ID(), err) + logrus.Errorf("Refreshing pod %s: %v", pod.ID(), err) } } for _, vol := range vols { if err := vol.refresh(); err != nil { - logrus.Errorf("Error refreshing volume %s: %v", vol.Name(), err) + logrus.Errorf("Refreshing volume %s: %v", vol.Name(), err) } } @@ -1099,7 +1112,7 @@ func (r *Runtime) reloadContainersConf() error { return err } r.config = config - logrus.Infof("applied new containers configuration: %v", config) + logrus.Infof("Applied new containers configuration: %v", config) return nil } @@ -1110,7 +1123,7 @@ func (r *Runtime) reloadStorageConf() error { return err } storage.ReloadConfigurationFile(configFile, &r.storageConfig) - logrus.Infof("applied new storage configuration: %v", r.storageConfig) + logrus.Infof("Applied new storage configuration: %v", r.storageConfig) return nil } diff --git a/libpod/runtime_cstorage.go b/libpod/runtime_cstorage.go index cd2f226af..5694967aa 100644 --- a/libpod/runtime_cstorage.go +++ b/libpod/runtime_cstorage.go @@ -106,22 +106,22 @@ func (r *Runtime) removeStorageContainer(idOrName string, force bool) error { logrus.Infof("Storage for container %s already removed", ctr.ID) return nil } - return errors.Wrapf(err, "error looking up container %q mounts", idOrName) + logrus.Warnf("Checking if container %q is mounted, attempting to delete: %v", idOrName, err) } if timesMounted > 0 { return errors.Wrapf(define.ErrCtrStateInvalid, "container %q is mounted and cannot be removed without using force", idOrName) } } else if _, err := r.store.Unmount(ctr.ID, true); err != nil { - if errors.Cause(err) == storage.ErrContainerUnknown { + if errors.Is(err, storage.ErrContainerUnknown) { // Container again gone, no error logrus.Infof("Storage for container %s already removed", ctr.ID) return nil } - return errors.Wrapf(err, "error unmounting container %q", idOrName) + logrus.Warnf("Unmounting container %q while attempting to delete storage: %v", idOrName, err) } if err := r.store.DeleteContainer(ctr.ID); err != nil { - if errors.Cause(err) == storage.ErrContainerUnknown { + if errors.Cause(err) == storage.ErrNotAContainer || errors.Cause(err) == storage.ErrContainerUnknown { // Container again gone, no error logrus.Infof("Storage for container %s already removed", ctr.ID) return nil diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index d4f67a115..00979a500 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -59,7 +59,7 @@ func (r *Runtime) PrepareVolumeOnCreateContainer(ctx context.Context, ctr *Conta defer func() { if err := ctr.cleanupStorage(); err != nil { - logrus.Errorf("error cleaning up container storage %s: %v", ctr.ID(), err) + logrus.Errorf("Cleaning up container storage %s: %v", ctr.ID(), err) } }() @@ -69,7 +69,7 @@ func (r *Runtime) PrepareVolumeOnCreateContainer(ctx context.Context, ctr *Conta ctr.state.Mounted = true ctr.state.Mountpoint = mountPoint if err = ctr.save(); err != nil { - logrus.Errorf("Error saving container %s state: %v", ctr.ID(), err) + logrus.Errorf("Saving container %s state: %v", ctr.ID(), err) } } @@ -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() @@ -286,7 +291,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai defer func() { if retErr != nil { if err := ctr.lock.Free(); err != nil { - logrus.Errorf("Error freeing lock for container after creation failed: %v", err) + logrus.Errorf("Freeing lock for container after creation failed: %v", err) } } }() @@ -409,7 +414,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai defer func() { if retErr != nil { if err := ctr.teardownStorage(); err != nil { - logrus.Errorf("Error removing partially-created container root filesystem: %s", err) + logrus.Errorf("Removing partially-created container root filesystem: %s", err) } } }() @@ -473,7 +478,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai } switch ctr.config.LogDriver { - case define.NoLogging: + case define.NoLogging, define.PassthroughLogging: break case define.JournaldLogging: ctr.initializeJournal(ctx) @@ -696,7 +701,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo if cleanupErr == nil { cleanupErr = err } else { - logrus.Errorf("cleanup storage: %v", err) + logrus.Errorf("Cleanup storage: %v", err) } } @@ -709,7 +714,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo if cleanupErr == nil { cleanupErr = err } else { - logrus.Errorf("Error removing container %s from database: %v", c.ID(), err) + logrus.Errorf("Removing container %s from database: %v", c.ID(), err) } } } @@ -718,7 +723,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo if cleanupErr == nil { cleanupErr = err } else { - logrus.Errorf("Error removing container %s from database: %v", c.ID(), err) + logrus.Errorf("Removing container %s from database: %v", c.ID(), err) } } } @@ -728,7 +733,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo if cleanupErr == nil { cleanupErr = errors.Wrapf(err, "error freeing lock for container %s", c.ID()) } else { - logrus.Errorf("free container lock: %v", err) + logrus.Errorf("Free container lock: %v", err) } } @@ -747,7 +752,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo continue } if err := runtime.removeVolume(ctx, volume, false); err != nil && errors.Cause(err) != define.ErrNoSuchVolume { - logrus.Errorf("cleanup volume (%s): %v", v, err) + logrus.Errorf("Cleanup volume (%s): %v", v, err) } } } @@ -888,7 +893,7 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol continue } if err := r.removeVolume(ctx, volume, false); err != nil && err != define.ErrNoSuchVolume && err != define.ErrVolumeBeingUsed { - logrus.Errorf("cleanup volume (%s): %v", v, err) + logrus.Errorf("Cleanup volume (%s): %v", v, err) } } } diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index a42f9a365..1915a5c4d 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -48,13 +48,34 @@ 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) e.Type = events.Image e.Name = idOrName if err := r.eventer.Write(e); err != nil { - logrus.Errorf("unable to write build event: %q", err) + logrus.Errorf("Unable to write build event: %q", err) } } diff --git a/libpod/runtime_migrate.go b/libpod/runtime_migrate.go index 3e63bc19e..087991e6f 100644 --- a/libpod/runtime_migrate.go +++ b/libpod/runtime_migrate.go @@ -56,7 +56,7 @@ func (r *Runtime) migrate(ctx context.Context) error { return err } - logrus.Infof("stopping all containers") + logrus.Infof("Stopping all containers") for _, ctr := range runningContainers { fmt.Printf("stopped %s\n", ctr.ID()) if err := ctr.Stop(); err != nil { @@ -77,7 +77,7 @@ func (r *Runtime) migrate(ctx context.Context) error { // Reset pause process location oldLocation := filepath.Join(ctr.state.RunDir, "conmon.pid") if ctr.config.ConmonPidFile == oldLocation { - logrus.Infof("changing conmon PID file for %s", ctr.ID()) + logrus.Infof("Changing conmon PID file for %s", ctr.ID()) ctr.config.ConmonPidFile = filepath.Join(ctr.config.StaticDir, "conmon.pid") needsWrite = true } diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 7571fdfff..5036dd680 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -66,7 +66,7 @@ func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, option defer func() { if deferredErr != nil { if err := pod.lock.Free(); err != nil { - logrus.Errorf("Error freeing pod lock after failed creation: %v", err) + logrus.Errorf("Freeing pod lock after failed creation: %v", err) } } }() @@ -224,7 +224,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon") conmonCgroup, err := cgroups.Load(conmonCgroupPath) if err != nil && err != cgroups.ErrCgroupDeleted && err != cgroups.ErrCgroupV1Rootless { - logrus.Errorf("Error retrieving pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err) + logrus.Errorf("Retrieving pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err) } // New resource limits @@ -259,7 +259,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if removalErr == nil { removalErr = err } else { - logrus.Errorf("Error removing container %s from pod %s: %v", ctr.ID(), p.ID(), err) + logrus.Errorf("Removing container %s from pod %s: %v", ctr.ID(), p.ID(), err) } } } @@ -275,7 +275,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) for volName := range ctrNamedVolumes { volume, err := r.state.Volume(volName) if err != nil && errors.Cause(err) != define.ErrNoSuchVolume { - logrus.Errorf("Error retrieving volume %s: %v", volName, err) + logrus.Errorf("Retrieving volume %s: %v", volName, err) continue } if !volume.Anonymous() { @@ -285,7 +285,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if errors.Cause(err) == define.ErrNoSuchVolume || errors.Cause(err) == define.ErrVolumeRemoved { continue } - logrus.Errorf("Error removing volume %s: %v", volName, err) + logrus.Errorf("Removing volume %s: %v", volName, err) } } @@ -299,7 +299,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if removalErr == nil { removalErr = errors.Wrapf(err, "error removing pod %s cgroup", p.ID()) } else { - logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) + logrus.Errorf("Deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) } } case config.CgroupfsCgroupsManager: @@ -321,7 +321,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if removalErr == nil { removalErr = errors.Wrapf(err, "error removing pod %s conmon cgroup", p.ID()) } else { - logrus.Errorf("Error deleting pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err) + logrus.Errorf("Deleting pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err) } } } @@ -330,7 +330,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if removalErr == nil { removalErr = errors.Wrapf(err, "error retrieving pod %s cgroup", p.ID()) } else { - logrus.Errorf("Error retrieving pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) + logrus.Errorf("Retrieving pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) } } if err == nil { @@ -338,7 +338,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if removalErr == nil { removalErr = errors.Wrapf(err, "error removing pod %s cgroup", p.ID()) } else { - logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) + logrus.Errorf("Deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) } } } @@ -371,7 +371,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if removalErr == nil { removalErr = errors.Wrapf(err, "error freeing pod %s lock", p.ID()) } else { - logrus.Errorf("Error freeing pod %s lock: %v", p.ID(), err) + logrus.Errorf("Freeing pod %s lock: %v", p.ID(), err) } } diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go index d1ea7d4fd..def6ca411 100644 --- a/libpod/runtime_volume_linux.go +++ b/libpod/runtime_volume_linux.go @@ -140,7 +140,7 @@ func (r *Runtime) newVolume(ctx context.Context, options ...VolumeCreateOption) defer func() { if deferredErr != nil { if err := volume.lock.Free(); err != nil { - logrus.Errorf("Error freeing volume lock after failed creation: %v", err) + logrus.Errorf("Freeing volume lock after failed creation: %v", err) } } }() @@ -246,7 +246,7 @@ func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error // If force is set, evict the volume, even if errors // occur. Otherwise we'll never be able to get rid of // them. - logrus.Errorf("Error unmounting volume %s: %v", v.Name(), err) + logrus.Errorf("Unmounting volume %s: %v", v.Name(), err) } else { return errors.Wrapf(err, "error unmounting volume %s", v.Name()) } @@ -290,7 +290,7 @@ func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error // Remove the volume from the state if err := r.state.RemoveVolume(v); err != nil { if removalErr != nil { - logrus.Errorf("Error removing volume %s from plugin %s: %v", v.Name(), v.Driver(), removalErr) + logrus.Errorf("Removing volume %s from plugin %s: %v", v.Name(), v.Driver(), removalErr) } return errors.Wrapf(err, "error removing volume %s", v.Name()) } @@ -300,7 +300,7 @@ func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error if removalErr == nil { removalErr = errors.Wrapf(err, "error freeing lock for volume %s", v.Name()) } else { - logrus.Errorf("Error freeing lock for volume %q: %v", v.Name(), err) + logrus.Errorf("Freeing lock for volume %q: %v", v.Name(), err) } } @@ -310,7 +310,7 @@ func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error if removalErr == nil { removalErr = errors.Wrapf(err, "error cleaning up volume storage for %q", v.Name()) } else { - logrus.Errorf("Error cleaning up volume storage for volume %q: %v", v.Name(), err) + logrus.Errorf("Cleaning up volume storage for volume %q: %v", v.Name(), err) } } diff --git a/libpod/shutdown/handler.go b/libpod/shutdown/handler.go index 1e8a9ec3b..cca74c3c4 100644 --- a/libpod/shutdown/handler.go +++ b/libpod/shutdown/handler.go @@ -61,7 +61,7 @@ func Start() error { } logrus.Infof("Invoking shutdown handler %s", name) if err := handler(sig); err != nil { - logrus.Errorf("Error running shutdown handler %s: %v", name, err) + logrus.Errorf("Running shutdown handler %s: %v", name, err) } } handlerLock.Unlock() diff --git a/libpod/storage.go b/libpod/storage.go index 4aa42dc8e..5c265df40 100644 --- a/libpod/storage.go +++ b/libpod/storage.go @@ -118,22 +118,22 @@ func (r *storageService) CreateContainerStorage(ctx context.Context, systemConte container, err := r.store.CreateContainer(containerID, names, imageID, "", string(mdata), &options) if err != nil { - logrus.Debugf("failed to create container %s(%s): %v", metadata.ContainerName, containerID, err) + logrus.Debugf("Failed to create container %s(%s): %v", metadata.ContainerName, containerID, err) return ContainerInfo{}, err } - logrus.Debugf("created container %q", container.ID) + logrus.Debugf("Created container %q", container.ID) // If anything fails after this point, we need to delete the incomplete // container before returning. defer func() { if retErr != nil { if err := r.store.DeleteContainer(container.ID); err != nil { - logrus.Infof("%v deleting partially-created container %q", err, container.ID) + logrus.Infof("Error deleting partially-created container %q: %v", container.ID, err) return } - logrus.Infof("deleted partially-created container %q", container.ID) + logrus.Infof("Deleted partially-created container %q", container.ID) } }() @@ -155,13 +155,13 @@ func (r *storageService) CreateContainerStorage(ctx context.Context, systemConte if err != nil { return ContainerInfo{}, err } - logrus.Debugf("container %q has work directory %q", container.ID, containerDir) + logrus.Debugf("Container %q has work directory %q", container.ID, containerDir) containerRunDir, err := r.store.ContainerRunDirectory(container.ID) if err != nil { return ContainerInfo{}, err } - logrus.Debugf("container %q has run directory %q", container.ID, containerRunDir) + logrus.Debugf("Container %q has run directory %q", container.ID, containerRunDir) return ContainerInfo{ UIDMap: options.UIDMap, @@ -184,8 +184,12 @@ func (r *storageService) DeleteContainer(idOrName string) error { } err = r.store.DeleteContainer(container.ID) if err != nil { - logrus.Debugf("failed to delete container %q: %v", container.ID, err) - return err + if errors.Cause(err) == storage.ErrNotAContainer || errors.Cause(err) == storage.ErrContainerUnknown { + logrus.Infof("Storage for container %s already removed", container.ID) + } else { + logrus.Debugf("Failed to delete container %q: %v", container.ID, err) + return err + } } return nil } @@ -193,7 +197,7 @@ func (r *storageService) DeleteContainer(idOrName string) error { func (r *storageService) SetContainerMetadata(idOrName string, metadata RuntimeContainerMetadata) error { mdata, err := json.Marshal(&metadata) if err != nil { - logrus.Debugf("failed to encode metadata for %q: %v", idOrName, err) + logrus.Debugf("Failed to encode metadata for %q: %v", idOrName, err) return err } return r.store.SetMetadata(idOrName, string(mdata)) @@ -225,10 +229,10 @@ func (r *storageService) MountContainerImage(idOrName string) (string, error) { } mountPoint, err := r.store.Mount(container.ID, metadata.MountLabel) if err != nil { - logrus.Debugf("failed to mount container %q: %v", container.ID, err) + logrus.Debugf("Failed to mount container %q: %v", container.ID, err) return "", err } - logrus.Debugf("mounted container %q at %q", container.ID, mountPoint) + logrus.Debugf("Mounted container %q at %q", container.ID, mountPoint) return mountPoint, nil } @@ -252,10 +256,10 @@ func (r *storageService) UnmountContainerImage(idOrName string, force bool) (boo } mounted, err := r.store.Unmount(container.ID, force) if err != nil { - logrus.Debugf("failed to unmount container %q: %v", container.ID, err) + logrus.Debugf("Failed to unmount container %q: %v", container.ID, err) return false, err } - logrus.Debugf("unmounted container %q", container.ID) + logrus.Debugf("Unmounted container %q", container.ID) return mounted, nil } diff --git a/libpod/util.go b/libpod/util.go index d3f7da91e..8f8303ff2 100644 --- a/libpod/util.go +++ b/libpod/util.go @@ -240,14 +240,14 @@ func hijackWriteError(toWrite error, cid string, terminal bool, httpBuf *bufio.R // We need a header. header := makeHTTPAttachHeader(2, uint32(len(errString))) if _, err := httpBuf.Write(header); err != nil { - logrus.Errorf("Error writing header for container %s attach connection error: %v", cid, err) + logrus.Errorf("Writing header for container %s attach connection error: %v", cid, err) } } if _, err := httpBuf.Write(errString); err != nil { - logrus.Errorf("Error writing error to container %s HTTP attach connection: %v", cid, err) + logrus.Errorf("Writing error to container %s HTTP attach connection: %v", cid, err) } if err := httpBuf.Flush(); err != nil { - logrus.Errorf("Error flushing HTTP buffer for container %s HTTP attach connection: %v", cid, err) + logrus.Errorf("Flushing HTTP buffer for container %s HTTP attach connection: %v", cid, err) } } } @@ -259,7 +259,7 @@ func hijackWriteErrorAndClose(toWrite error, cid string, terminal bool, httpCon hijackWriteError(toWrite, cid, terminal, httpBuf) if err := httpCon.Close(); err != nil { - logrus.Errorf("Error closing container %s HTTP attach connection: %v", cid, err) + logrus.Errorf("Closing container %s HTTP attach connection: %v", cid, err) } } diff --git a/libpod/util_linux.go b/libpod/util_linux.go index 32b058d27..e2ea97185 100644 --- a/libpod/util_linux.go +++ b/libpod/util_linux.go @@ -119,7 +119,7 @@ func LabelVolumePath(path string) error { func Unmount(mount string) { if err := unix.Unmount(mount, unix.MNT_DETACH); err != nil { if err != syscall.EINVAL { - logrus.Warnf("failed to unmount %s : %v", mount, err) + logrus.Warnf("Failed to unmount %s : %v", mount, err) } else { logrus.Debugf("failed to unmount %s : %v", mount, err) } diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index a15fdb553..18005e24a 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -410,11 +410,11 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON, if l.HasHealthCheck() && state.Status != "created" { state.Health = &types.Health{ - Status: inspect.State.Healthcheck.Status, - FailingStreak: inspect.State.Healthcheck.FailingStreak, + Status: inspect.State.Health.Status, + FailingStreak: inspect.State.Health.FailingStreak, } - log := inspect.State.Healthcheck.Log + log := inspect.State.Health.Log for _, item := range log { res := &types.HealthcheckResult{} diff --git a/pkg/api/handlers/compat/containers_start.go b/pkg/api/handlers/compat/containers_start.go index ca2b5d84c..fb68389bc 100644 --- a/pkg/api/handlers/compat/containers_start.go +++ b/pkg/api/handlers/compat/containers_start.go @@ -25,7 +25,7 @@ func StartContainer(w http.ResponseWriter, r *http.Request) { } if len(query.DetachKeys) > 0 { // TODO - start does not support adding detach keys - logrus.Info("the detach keys parameter is not supported on start container") + logrus.Info("The detach keys parameter is not supported on start container") } runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) name := utils.GetName(r) diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go index e872f885a..0051e7235 100644 --- a/pkg/api/handlers/compat/containers_stats.go +++ b/pkg/api/handlers/compat/containers_stats.go @@ -227,10 +227,10 @@ func toBlkioStatEntry(entries []cgroups.BlkIOEntry) []docker.BlkioStatEntry { for i, e := range entries { bits, err := json.Marshal(e) if err != nil { - logrus.Errorf("unable to marshal blkio stats: %q", err) + logrus.Errorf("Unable to marshal blkio stats: %q", err) } if err := json.Unmarshal(bits, &results[i]); err != nil { - logrus.Errorf("unable to unmarshal blkio stats: %q", err) + logrus.Errorf("Unable to unmarshal blkio stats: %q", err) } } return results diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go index a79b33ecc..901acdac4 100644 --- a/pkg/api/handlers/compat/events.go +++ b/pkg/api/handlers/compat/events.go @@ -94,7 +94,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) { } if err := coder.Encode(e); err != nil { - logrus.Errorf("unable to write json: %q", err) + logrus.Errorf("Unable to write json: %q", err) } flush() case <-r.Context().Done(): diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index b4f08a746..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 { @@ -289,9 +291,10 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { - Compress bool `schema:"compress"` - Format string `schema:"format"` - References []string `schema:"references"` + Compress bool `schema:"compress"` + Format string `schema:"format"` + OciAcceptUncompressedLayers bool `schema:"ociAcceptUncompressedLayers"` + References []string `schema:"references"` }{ Format: define.OCIArchive, } @@ -353,11 +356,11 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { // Use the ABI image engine to share as much code as possible. opts := entities.ImageSaveOptions{ - Compress: query.Compress, - Format: query.Format, - MultiImageArchive: len(query.References) > 1, - Output: output, - RemoveSignatures: true, + Compress: query.Compress, + Format: query.Format, + MultiImageArchive: len(query.References) > 1, + OciAcceptUncompressedLayers: query.OciAcceptUncompressedLayers, + Output: output, } imageEngine := abi.ImageEngine{Libpod: runtime} diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go index 9f46ecc52..7bd6d3dbf 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -186,9 +186,9 @@ func PodStop(w http.ResponseWriter, r *http.Request) { } // Try to clean up the pod - but only warn on failure, it's nonfatal. if cleanupCtrs, cleanupErr := pod.Cleanup(r.Context()); cleanupErr != nil { - logrus.Errorf("Error cleaning up pod %s: %v", pod.ID(), cleanupErr) + logrus.Errorf("Cleaning up pod %s: %v", pod.ID(), cleanupErr) for id, err := range cleanupCtrs { - logrus.Errorf("Error cleaning up pod %s container %s: %v", pod.ID(), id, err) + logrus.Errorf("Cleaning up pod %s container %s: %v", pod.ID(), id, err) } } diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go index 5cdb31de1..6f875fc30 100644 --- a/pkg/api/handlers/utils/containers.go +++ b/pkg/api/handlers/utils/containers.go @@ -78,7 +78,7 @@ func WaitContainerDocker(w http.ResponseWriter, r *http.Request) { exitCode, err := waitDockerCondition(ctx, name, interval, condition) var errStruct *struct{ Message string } if err != nil { - logrus.Errorf("error while waiting on condition: %q", err) + logrus.Errorf("While waiting on condition: %q", err) errStruct = &struct { Message string }{ @@ -94,7 +94,7 @@ func WaitContainerDocker(w http.ResponseWriter, r *http.Request) { enc.SetEscapeHTML(true) err = enc.Encode(&responseData) if err != nil { - logrus.Errorf("unable to write json: %q", err) + logrus.Errorf("Unable to write json: %q", err) } } diff --git a/pkg/api/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go index 7625f9546..29139a98e 100644 --- a/pkg/api/handlers/utils/handler.go +++ b/pkg/api/handlers/utils/handler.go @@ -89,21 +89,21 @@ func WriteResponse(w http.ResponseWriter, code int, value interface{}) { w.WriteHeader(code) if _, err := fmt.Fprintln(w, v); err != nil { - logrus.Errorf("unable to send string response: %q", err) + logrus.Errorf("Unable to send string response: %q", err) } case *os.File: w.Header().Set("Content-Type", "application/octet; charset=us-ascii") w.WriteHeader(code) if _, err := io.Copy(w, v); err != nil { - logrus.Errorf("unable to copy to response: %q", err) + logrus.Errorf("Unable to copy to response: %q", err) } case io.Reader: w.Header().Set("Content-Type", "application/x-tar") w.WriteHeader(code) if _, err := io.Copy(w, v); err != nil { - logrus.Errorf("unable to copy to response: %q", err) + logrus.Errorf("Unable to copy to response: %q", err) } default: WriteJSON(w, code, value) @@ -162,7 +162,7 @@ func WriteJSON(w http.ResponseWriter, code int, value interface{}) { coder := json.NewEncoder(w) coder.SetEscapeHTML(true) if err := coder.Encode(value); err != nil { - logrus.Errorf("unable to write json: %q", err) + logrus.Errorf("Unable to write json: %q", err) } } diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 95981226c..aa573eaa6 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -176,6 +176,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - in: query // name: limit // type: integer + // default: 25 // description: maximum number of results // - in: query // name: filters @@ -186,6 +187,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - `is-official=(true|false)` // - `stars=<number>` Matches images that has at least 'number' stars. // - in: query + // name: tlsVerify + // type: boolean + // default: false + // description: skip TLS verification for registries + // - in: query // name: listTags // type: boolean // description: list the available tags in the repository @@ -1044,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: | @@ -1075,6 +1087,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - in: query // name: limit // type: integer + // default: 25 // description: maximum number of results // - in: query // name: noTrunc @@ -1088,6 +1101,16 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - `is-automated=(true|false)` // - `is-official=(true|false)` // - `stars=<number>` Matches images that has at least 'number' stars. + // - in: query + // name: tlsVerify + // type: boolean + // default: false + // description: skip TLS verification for registries + // - in: query + // name: listTags + // type: boolean + // default: false + // description: list the available tags in the repository // produces: // - application/json // responses: @@ -1150,6 +1173,10 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // name: compress // type: boolean // description: use compression on image + // - in: query + // name: ociAcceptUncompressedLayers + // type: boolean + // description: accept uncompressed layers when copying OCI images // produces: // - application/json // responses: diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go index 34d0fa246..c7174775e 100644 --- a/pkg/api/server/server.go +++ b/pkg/api/server/server.go @@ -233,7 +233,7 @@ func (s *APIServer) Serve() error { s.pprof = &http.Server{Addr: "localhost:8888", Handler: pprofMux} err := s.pprof.ListenAndServe() if err != nil && err != http.ErrServerClosed { - logrus.Warn("API profiler service failed: " + err.Error()) + logrus.Warnf("API profiler service failed: %v", err) } }() } @@ -272,7 +272,7 @@ func (s *APIServer) Shutdown() error { go func() { defer cancel() if err := s.pprof.Shutdown(ctx); err != nil { - logrus.Warn("Failed to cleanly shutdown API pprof service: " + err.Error()) + logrus.Warnf("Failed to cleanly shutdown API pprof service: %v", err) } }() <-ctx.Done() diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index 6aff880f4..070e222ad 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -208,7 +208,7 @@ func RemoveAuthfile(authfile string) { return } if err := os.Remove(authfile); err != nil { - logrus.Errorf("Error removing temporary auth file %q: %v", authfile, err) + logrus.Errorf("Removing temporary auth file %q: %v", authfile, err) } } 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/containers/attach.go b/pkg/bindings/containers/attach.go index 6efbcb57b..abf58aaf9 100644 --- a/pkg/bindings/containers/attach.go +++ b/pkg/bindings/containers/attach.go @@ -102,7 +102,7 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri } defer func() { if err := terminal.Restore(int(file.Fd()), state); err != nil { - logrus.Errorf("unable to restore terminal: %q", err) + logrus.Errorf("Unable to restore terminal: %q", err) } logrus.SetFormatter(&logrus.TextFormatter{}) }() @@ -166,7 +166,7 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri _, err := utils.CopyDetachable(socket, stdin, detachKeysInBytes) if err != nil && err != define.ErrDetach { - logrus.Error("failed to write input to service: " + err.Error()) + logrus.Errorf("Failed to write input to service: %v", err) } stdinChan <- err @@ -349,7 +349,7 @@ func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, i resize := func() { w, h, err := terminal.GetSize(int(file.Fd())) if err != nil { - logrus.Warnf("failed to obtain TTY size: %v", err) + logrus.Warnf("Failed to obtain TTY size: %v", err) } var resizeErr error @@ -359,7 +359,7 @@ func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, i resizeErr = ResizeContainerTTY(ctx, id, new(ResizeTTYOptions).WithHeight(h).WithWidth(w)) } if resizeErr != nil { - logrus.Infof("failed to resize TTY: %v", resizeErr) + logrus.Infof("Failed to resize TTY: %v", resizeErr) } } @@ -443,13 +443,13 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar } defer func() { if err := terminal.Restore(int(terminalFile.Fd()), state); err != nil { - logrus.Errorf("unable to restore terminal: %q", err) + logrus.Errorf("Unable to restore terminal: %q", err) } logrus.SetFormatter(&logrus.TextFormatter{}) }() w, h, err := terminal.GetSize(int(terminalFile.Fd())) if err != nil { - logrus.Warnf("failed to obtain TTY size: %v", err) + logrus.Warnf("Failed to obtain TTY size: %v", err) } body.Width = uint16(w) body.Height = uint16(h) @@ -502,7 +502,7 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar logrus.Debugf("Copying STDIN to socket") _, err := utils.CopyDetachable(socket, options.InputStream, []byte{}) if err != nil { - logrus.Error("failed to write input to service: " + err.Error()) + logrus.Errorf("Failed to write input to service: %v", err) } if closeWrite, ok := socket.(CloseWriter); ok { diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 9d5aad23b..403d90721 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -16,6 +16,7 @@ import ( "strconv" "strings" + "github.com/containers/buildah/define" "github.com/containers/podman/v3/pkg/auth" "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/domain/entities" @@ -39,6 +40,10 @@ var ( // Build creates an image using a containerfile reference func Build(ctx context.Context, containerFiles []string, options entities.BuildOptions) (*entities.BuildReport, error) { + if options.CommonBuildOpts == nil { + options.CommonBuildOpts = new(define.CommonBuildOptions) + } + params := url.Values{} if caps := options.AddCapabilities; len(caps) > 0 { @@ -230,6 +235,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()) @@ -312,7 +320,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO contextDir, err := filepath.Abs(options.ContextDirectory) if err != nil { - logrus.Errorf("cannot find absolute path of %v: %v", options.ContextDirectory, err) + logrus.Errorf("Cannot find absolute path of %v: %v", options.ContextDirectory, err) return nil, err } @@ -339,7 +347,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } containerfile, err := filepath.Abs(c) if err != nil { - logrus.Errorf("cannot find absolute path of %v: %v", c, err) + logrus.Errorf("Cannot find absolute path of %v: %v", c, err) return nil, err } @@ -371,7 +379,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } tarfile, err := nTar(append(excludes, dontexcludes...), tarContent...) if err != nil { - logrus.Errorf("cannot tar container entries %v error: %v", tarContent, err) + logrus.Errorf("Cannot tar container entries %v error: %v", tarContent, err) return nil, err } defer func() { @@ -477,7 +485,7 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) { for _, src := range sources { s, err := filepath.Abs(src) if err != nil { - logrus.Errorf("cannot stat one of source context: %v", err) + logrus.Errorf("Cannot stat one of source context: %v", err) merr = multierror.Append(merr, err) return } diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go index 801f5ed96..dc6bd91c3 100644 --- a/pkg/bindings/images/types.go +++ b/pkg/bindings/images/types.go @@ -65,6 +65,8 @@ type ExportOptions struct { Compress *bool // Format of the output Format *string + // Accept uncompressed layers when copying OCI images. + OciAcceptUncompressedLayers *bool } //go:generate go run ../generator/generator.go PruneOptions @@ -72,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_export_options.go b/pkg/bindings/images/types_export_options.go index 6229e435c..649b6814e 100644 --- a/pkg/bindings/images/types_export_options.go +++ b/pkg/bindings/images/types_export_options.go @@ -46,3 +46,18 @@ func (o *ExportOptions) GetFormat() string { } return *o.Format } + +// WithOciAcceptUncompressedLayers set field OciAcceptUncompressedLayers to given value +func (o *ExportOptions) WithOciAcceptUncompressedLayers(value bool) *ExportOptions { + o.OciAcceptUncompressedLayers = &value + return o +} + +// GetOciAcceptUncompressedLayers returns value of field OciAcceptUncompressedLayers +func (o *ExportOptions) GetOciAcceptUncompressedLayers() bool { + if o.OciAcceptUncompressedLayers == nil { + var z bool + return z + } + return *o.OciAcceptUncompressedLayers +} 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/bindings/test/fixture/Containerfile b/pkg/bindings/test/fixture/Containerfile new file mode 100644 index 000000000..3a1031f32 --- /dev/null +++ b/pkg/bindings/test/fixture/Containerfile @@ -0,0 +1 @@ +From quay.io/libpod/alpine_nginx diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go index ff8f72c85..aa8ff0537 100644 --- a/pkg/bindings/test/images_test.go +++ b/pkg/bindings/test/images_test.go @@ -9,9 +9,11 @@ import ( "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/bindings/containers" "github.com/containers/podman/v3/pkg/bindings/images" + "github.com/containers/podman/v3/pkg/domain/entities" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/onsi/gomega/gexec" + . "github.com/onsi/gomega/gexec" + . "github.com/onsi/gomega/gstruct" ) var _ = Describe("Podman images", func() { @@ -20,7 +22,7 @@ var _ = Describe("Podman images", func() { // err error // podmanTest *PodmanTestIntegration bt *bindingTest - s *gexec.Session + s *Session err error ) @@ -37,7 +39,7 @@ var _ = Describe("Podman images", func() { s = bt.startAPIService() time.Sleep(1 * time.Second) err := bt.NewConnection() - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { @@ -57,19 +59,19 @@ var _ = Describe("Podman images", func() { // Inspect by short name data, err := images.GetImage(bt.conn, alpine.shortName, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) // Inspect with full ID _, err = images.GetImage(bt.conn, data.ID, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) // Inspect with partial ID _, err = images.GetImage(bt.conn, data.ID[0:12], nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) // Inspect by long name _, err = images.GetImage(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) // TODO it looks like the images API always returns size regardless // of bool or not. What should we do ? // Expect(data.Size).To(BeZero()) @@ -77,7 +79,7 @@ var _ = Describe("Podman images", func() { options := new(images.GetOptions).WithSize(true) // Enabling the size parameter should result in size being populated data, err = images.GetImage(bt.conn, alpine.name, options) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(data.Size).To(BeNumerically(">", 0)) }) @@ -90,7 +92,7 @@ var _ = Describe("Podman images", func() { // Remove an image by name, validate image is removed and error is nil inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) response, errs = images.Remove(bt.conn, []string{busybox.shortName}, nil) Expect(len(errs)).To(BeZero()) @@ -101,10 +103,10 @@ var _ = Describe("Podman images", func() { // Start a container with alpine image var top string = "top" _, err = bt.RunTopContainer(&top, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) // we should now have a container called "top" running containerResponse, err := containers.Inspect(bt.conn, "top", nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(containerResponse.Name).To(Equal("top")) // try to remove the image "alpine". This should fail since we are not force @@ -115,7 +117,7 @@ var _ = Describe("Podman images", func() { // Removing the image "alpine" where force = true options := new(images.RemoveOptions).WithForce(true) response, errs = images.Remove(bt.conn, []string{alpine.shortName}, options) - Expect(errs).To(BeNil()) + Expect(errs).To(Or(HaveLen(0), BeNil())) // To be extra sure, check if the previously created container // is gone as well. _, err = containers.Inspect(bt.conn, "top", nil) @@ -141,11 +143,11 @@ var _ = Describe("Podman images", func() { // Validates if the image is tagged successfully. err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) // Validates if name updates when the image is retagged. _, err := images.GetImage(bt.conn, "alpine:demo", nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) }) @@ -154,7 +156,7 @@ var _ = Describe("Podman images", func() { // Array to hold the list of images returned imageSummary, err := images.List(bt.conn, nil) // There Should be no errors in the response. - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) // Since in the begin context two images are created the // list context should have only 2 images Expect(len(imageSummary)).To(Equal(2)) @@ -163,23 +165,23 @@ var _ = Describe("Podman images", func() { // And the count should be three now. bt.Pull("testimage:20200929") imageSummary, err = images.List(bt.conn, nil) - Expect(err).To(BeNil()) - Expect(len(imageSummary)).To(Equal(3)) + Expect(err).ToNot(HaveOccurred()) + Expect(len(imageSummary)).To(BeNumerically(">=", 2)) // Validate the image names. var names []string for _, i := range imageSummary { names = append(names, i.RepoTags...) } - Expect(StringInSlice(alpine.name, names)).To(BeTrue()) - Expect(StringInSlice(busybox.name, names)).To(BeTrue()) + Expect(names).To(ContainElement(alpine.name)) + Expect(names).To(ContainElement(busybox.name)) // List images with a filter filters := make(map[string][]string) filters["reference"] = []string{alpine.name} options := new(images.ListOptions).WithFilters(filters).WithAll(false) filteredImages, err := images.List(bt.conn, options) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(len(filteredImages)).To(BeNumerically("==", 1)) // List images with a bad filter @@ -194,17 +196,17 @@ var _ = Describe("Podman images", func() { It("Image Exists", func() { // exists on bogus image should be false, with no error exists, err := images.Exists(bt.conn, "foobar", nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeFalse()) // exists with shortname should be true exists, err = images.Exists(bt.conn, alpine.shortName, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeTrue()) // exists with fqname should be true exists, err = images.Exists(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeTrue()) }) @@ -213,37 +215,37 @@ var _ = Describe("Podman images", func() { _, errs := images.Remove(bt.conn, []string{alpine.name}, nil) Expect(len(errs)).To(BeZero()) exists, err := images.Exists(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeFalse()) f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) defer f.Close() - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) names, err := images.Load(bt.conn, f) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(names.Names[0]).To(Equal(alpine.name)) exists, err = images.Exists(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeTrue()) // load with a repo name f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) _, errs = images.Remove(bt.conn, []string{alpine.name}, nil) Expect(len(errs)).To(BeZero()) exists, err = images.Exists(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeFalse()) names, err = images.Load(bt.conn, f) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(names.Names[0]).To(Equal(alpine.name)) // load with a bad repo name should trigger a 500 f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) _, errs = images.Remove(bt.conn, []string{alpine.name}, nil) Expect(len(errs)).To(BeZero()) exists, err = images.Exists(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeFalse()) }) @@ -252,11 +254,11 @@ var _ = Describe("Podman images", func() { exportPath := filepath.Join(bt.tempDirPath, alpine.tarballName) w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName)) defer w.Close() - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) err = images.Export(bt.conn, []string{alpine.name}, w, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) _, err = os.Stat(exportPath) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) // TODO how do we verify that a format change worked? }) @@ -266,21 +268,21 @@ var _ = Describe("Podman images", func() { _, errs := images.Remove(bt.conn, []string{alpine.name}, nil) Expect(len(errs)).To(BeZero()) exists, err := images.Exists(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeFalse()) f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) defer f.Close() - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) changes := []string{"CMD /bin/foobar"} testMessage := "test_import" options := new(images.ImportOptions).WithMessage(testMessage).WithChanges(changes).WithReference(alpine.name) _, err = images.Import(bt.conn, f, options) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) exists, err = images.Exists(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeTrue()) data, err := images.GetImage(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(data.Comment).To(Equal(testMessage)) }) @@ -294,9 +296,9 @@ var _ = Describe("Podman images", func() { var foundID bool data, err := images.GetImage(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) history, err := images.History(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) for _, i := range history { if i.ID == data.ID { foundID = true @@ -308,7 +310,7 @@ var _ = Describe("Podman images", func() { It("Search for an image", func() { reports, err := images.Search(bt.conn, "alpine", nil) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(len(reports)).To(BeNumerically(">", 1)) var foundAlpine bool for _, i := range reports { @@ -322,7 +324,7 @@ var _ = Describe("Podman images", func() { // Search for alpine with a limit of 10 options := new(images.SearchOptions).WithLimit(10) reports, err = images.Search(bt.conn, "docker.io/alpine", options) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) Expect(len(reports)).To(BeNumerically("<=", 10)) filters := make(map[string][]string) @@ -330,7 +332,7 @@ var _ = Describe("Podman images", func() { // Search for alpine with stars greater than 100 options = new(images.SearchOptions).WithFilters(filters) reports, err = images.Search(bt.conn, "docker.io/alpine", options) - Expect(err).To(BeNil()) + Expect(err).ToNot(HaveOccurred()) for _, i := range reports { Expect(i.Stars).To(BeNumerically(">=", 100)) } @@ -367,4 +369,12 @@ var _ = Describe("Podman images", func() { _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", nil) Expect(err).To(HaveOccurred()) }) + + It("Build no options", func() { + results, err := images.Build(bt.conn, []string{"fixture/Containerfile"}, entities.BuildOptions{}) + Expect(err).ToNot(HaveOccurred()) + Expect(*results).To(MatchFields(IgnoreMissing, Fields{ + "ID": Not(BeEmpty()), + })) + }) }) diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go index 9fdf04933..f53e31f9b 100644 --- a/pkg/checkpoint/checkpoint_restore.go +++ b/pkg/checkpoint/checkpoint_restore.go @@ -51,7 +51,7 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt } defer func() { if err := os.RemoveAll(dir); err != nil { - logrus.Errorf("could not recursively remove %s: %q", dir, err) + logrus.Errorf("Could not recursively remove %s: %q", dir, err) } }() err = archive.Untar(archiveFile, dir, options) diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index c575212b1..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{} @@ -301,10 +302,10 @@ type ImageSaveOptions struct { // than one image. Additional tags will be interpreted as references // to images which are added to the archive. MultiImageArchive bool + // Accept uncompressed layers when copying OCI images. + OciAcceptUncompressedLayers bool // Output - write image to the specified path. Output string - // Do not save the signature from the source image - RemoveSignatures bool // Quiet - suppress output when copying images Quiet bool } diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index dc5f7a0df..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 } @@ -825,26 +829,12 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri }) if ctr.AutoRemove() { if err := ic.removeContainer(ctx, ctr, entities.RmOptions{}); err != nil { - logrus.Errorf("Error removing container %s: %v", ctr.ID(), err) + logrus.Errorf("Removing container %s: %v", ctr.ID(), err) } } return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID()) } - - if ecode, err := ctr.Wait(ctx); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { - // Check events - event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited) - if err != nil { - logrus.Errorf("Cannot get exit code: %v", err) - exitCode = define.ExecErrorCodeNotFound - } else { - exitCode = event.ContainerExitCode - } - } - } else { - exitCode = int(ecode) - } + exitCode = ic.GetContainerExitCode(ctx, ctr) reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), RawInput: rawInput, @@ -874,7 +864,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri reports = append(reports, report) if ctr.AutoRemove() { if err := ic.removeContainer(ctx, ctr, entities.RmOptions{}); err != nil { - logrus.Errorf("Error removing container %s: %v", ctr.ID(), err) + logrus.Errorf("Removing container %s: %v", ctr.ID(), err) } } continue @@ -985,34 +975,43 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta report.ExitCode = define.ExitCode(err) return &report, err } - - if ecode, err := ctr.Wait(ctx); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { - // Check events - event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited) - if err != nil { - logrus.Errorf("Cannot get exit code: %v", err) - report.ExitCode = define.ExecErrorCodeNotFound - } else { - report.ExitCode = event.ContainerExitCode - } - } - } else { - report.ExitCode = int(ecode) - } + report.ExitCode = ic.GetContainerExitCode(ctx, ctr) if opts.Rm && !ctr.ShouldRestart(ctx) { if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil { if errors.Cause(err) == define.ErrNoSuchCtr || errors.Cause(err) == define.ErrCtrRemoved { logrus.Infof("Container %s was already removed, skipping --rm", ctr.ID()) } else { - logrus.Errorf("Error removing container %s: %v", ctr.ID(), err) + logrus.Errorf("Removing container %s: %v", ctr.ID(), err) } } } return &report, nil } +func (ic *ContainerEngine) GetContainerExitCode(ctx context.Context, ctr *libpod.Container) int { + exitCode, err := ctr.Wait(ctx) + if err == nil { + return int(exitCode) + } + if errors.Cause(err) != define.ErrNoSuchCtr { + logrus.Errorf("Could not retrieve exit code: %v", err) + return define.ExecErrorCodeNotFound + } + // Make 4 attempt with 0.25s backoff between each for 1 second total + var event *events.Event + for i := 0; i < 4; i++ { + event, err = ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited) + if err != nil { + time.Sleep(250 * time.Millisecond) + continue + } + return int(event.ContainerExitCode) + } + logrus.Errorf("Could not retrieve exit code from event: %v", err) + return define.ExecErrorCodeNotFound +} + func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error { if options.StdoutWriter == nil && options.StderrWriter == nil { return errors.New("no io.Writer set for container logs") diff --git a/pkg/domain/infra/abi/containers_runlabel.go b/pkg/domain/infra/abi/containers_runlabel.go index 435baa8c8..add82f0fb 100644 --- a/pkg/domain/infra/abi/containers_runlabel.go +++ b/pkg/domain/infra/abi/containers_runlabel.go @@ -87,7 +87,7 @@ func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string, ctr, err := ic.Libpod.LookupContainer(name) if err != nil { if errors.Cause(err) != define.ErrNoSuchCtr { - logrus.Debugf("Error occurred searching for container %s: %s", name, err.Error()) + logrus.Debugf("Error occurred searching for container %s: %v", name, err) return err } } else { @@ -167,7 +167,7 @@ func generateRunlabelCommand(runlabel string, img *libimage.Image, inputName str // I would prefer to use os.getenv but it appears PWD is not in the os env list. d, err := os.Getwd() if err != nil { - logrus.Error("unable to determine current working directory") + logrus.Error("Unable to determine current working directory") return "" } return d diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index 1e614ce58..081a2464b 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -107,7 +107,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, // Generate kube pods and services from pods. if len(pods) >= 1 { - pos, svcs, err := getKubePods(pods, options.Service) + pos, svcs, err := getKubePods(ctx, pods, options.Service) if err != nil { return nil, err } @@ -120,7 +120,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, // Generate the kube pods from containers. if len(ctrs) >= 1 { - po, err := libpod.GenerateForKube(ctrs) + po, err := libpod.GenerateForKube(ctx, ctrs) if err != nil { return nil, err } @@ -153,12 +153,12 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, } // getKubePods returns kube pod and service YAML files from podman pods. -func getKubePods(pods []*libpod.Pod, getService bool) ([][]byte, [][]byte, error) { +func getKubePods(ctx context.Context, pods []*libpod.Pod, getService bool) ([][]byte, [][]byte, error) { pos := [][]byte{} svcs := [][]byte{} for _, p := range pods { - po, sp, err := p.GenerateForKube() + po, sp, err := p.GenerateForKube(ctx) if err != nil { return nil, nil, err } diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index a88d38a10..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 @@ -367,7 +375,11 @@ func (ir *ImageEngine) Load(ctx context.Context, options entities.ImageLoadOptio func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error { saveOptions := &libimage.SaveOptions{} saveOptions.DirForceCompress = options.Compress - saveOptions.RemoveSignatures = options.RemoveSignatures + saveOptions.OciAcceptUncompressedLayers = options.OciAcceptUncompressedLayers + + // Force signature removal to preserve backwards compat. + // See https://github.com/containers/podman/pull/11669#issuecomment-925250264 + saveOptions.RemoveSignatures = true if !options.Quiet { saveOptions.Writer = os.Stderr @@ -572,7 +584,7 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie } defer func() { if err = rawSource.Close(); err != nil { - logrus.Errorf("unable to close %s image source %q", srcRef.DockerReference().Name(), err) + logrus.Errorf("Unable to close %s image source %q", srcRef.DockerReference().Name(), err) } }() topManifestBlob, manifestType, err := rawSource.GetManifest(ctx, nil) diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go index 1dd0686ac..d1bd5e2e4 100644 --- a/pkg/domain/infra/abi/manifest.go +++ b/pkg/domain/infra/abi/manifest.go @@ -146,7 +146,7 @@ func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string) ( switch manType { case manifest.DockerV2Schema2MediaType: - logrus.Warnf("Warning! The manifest type %s is not a manifest list but a single image.", manType) + logrus.Warnf("The manifest type %s is not a manifest list but a single image.", manType) schema2Manifest, err := manifest.Schema2FromManifest(result) if err != nil { return nil, errors.Wrapf(err, "error parsing manifest blob %q as a %q", string(result), manType) diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 87506f70c..cf72a6253 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -113,7 +113,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en report.Volumes = append(report.Volumes, r.Volumes...) validKinds++ default: - logrus.Infof("kube kind %s not supported", kind) + logrus.Infof("Kube kind %s not supported", kind) continue } } @@ -319,8 +319,8 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if err != nil { return nil, err } - specgenOpts := kube.CtrSpecGenOptions{ + Annotations: annotations, Container: initCtr, Image: pulledImage, Volumes: volumes, @@ -435,6 +435,7 @@ func (ic *ContainerEngine) getImageAndLabelInfo(ctx context.Context, cwd string, buildOpts.Isolation = buildahDefine.IsolationChroot buildOpts.CommonBuildOpts = commonOpts buildOpts.Output = container.Image + buildOpts.ContextDirectory = filepath.Dir(buildFile) if _, _, err := ic.Libpod.Build(ctx, *buildOpts, []string{buildFile}...); err != nil { return nil, nil, err } @@ -662,21 +663,21 @@ func getBuildFile(imageName string, cwd string) (string, error) { containerfilePath := filepath.Join(cwd, buildDirName, "Containerfile") dockerfilePath := filepath.Join(cwd, buildDirName, "Dockerfile") - _, err := os.Stat(filepath.Join(containerfilePath)) + _, err := os.Stat(containerfilePath) if err == nil { - logrus.Debugf("building %s with %s", imageName, containerfilePath) + logrus.Debugf("Building %s with %s", imageName, containerfilePath) return containerfilePath, nil } // If the error is not because the file does not exist, take // a mulligan and try Dockerfile. If that also fails, return that // error if err != nil && !os.IsNotExist(err) { - logrus.Errorf("%v: unable to check for %s", err, containerfilePath) + logrus.Error(err.Error()) } _, err = os.Stat(filepath.Join(dockerfilePath)) if err == nil { - logrus.Debugf("building %s with %s", imageName, dockerfilePath) + logrus.Debugf("Building %s with %s", imageName, dockerfilePath) return dockerfilePath, nil } // Strike two 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/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_linux.go index a9bd2d5fb..3b129f5ea 100644 --- a/pkg/domain/infra/abi/terminal/sigproxy_linux.go +++ b/pkg/domain/infra/abi/terminal/sigproxy_linux.go @@ -42,7 +42,7 @@ func ProxySignals(ctr *libpod.Container) { if errors.Cause(err) == define.ErrCtrStateInvalid { logrus.Infof("Ceasing signal forwarding to container %s as it has stopped", ctr.ID()) } else { - logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err) + logrus.Errorf("forwarding signal %d to container %s: %v", s, ctr.ID(), err) } // If the container dies, and we find out here, // we need to forward that one signal to @@ -51,7 +51,7 @@ func ProxySignals(ctr *libpod.Container) { // play out. signal.StopCatch(sigBuffer) if err := syscall.Kill(syscall.Getpid(), s.(syscall.Signal)); err != nil { - logrus.Errorf("failed to kill pid %d", syscall.Getpid()) + logrus.Errorf("Failed to kill pid %d", syscall.Getpid()) } return } diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_linux.go index 09c0f802d..ba047bf33 100644 --- a/pkg/domain/infra/abi/terminal/terminal_linux.go +++ b/pkg/domain/infra/abi/terminal/terminal_linux.go @@ -29,7 +29,7 @@ func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, execConfig *libpo defer cancel() defer func() { if err := restoreTerminal(oldTermState); err != nil { - logrus.Errorf("unable to restore terminal: %q", err) + logrus.Errorf("Unable to restore terminal: %q", err) } }() } @@ -53,7 +53,7 @@ func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, } defer func() { if err := restoreTerminal(oldTermState); err != nil { - logrus.Errorf("unable to restore terminal: %q", err) + logrus.Errorf("Unable to restore terminal: %q", err) } }() defer cancel() diff --git a/pkg/domain/infra/abi/trust.go b/pkg/domain/infra/abi/trust.go index d3aff62ba..af7814163 100644 --- a/pkg/domain/infra/abi/trust.go +++ b/pkg/domain/infra/abi/trust.go @@ -165,7 +165,7 @@ var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "sig func trustTypeDescription(trustType string) string { trustDescription, exist := typeDescription[trustType] if !exist { - logrus.Warnf("invalid trust type %s", trustType) + logrus.Warnf("Invalid trust type %s", trustType) } return trustDescription } diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go index 5cbee2e76..7ec6135ee 100644 --- a/pkg/domain/infra/runtime_libpod.go +++ b/pkg/domain/infra/runtime_libpod.go @@ -369,7 +369,7 @@ func StartWatcher(rt *libpod.Runtime) { logrus.Debugf("waiting for SIGHUP to reload configuration") <-ch if err := rt.Reload(); err != nil { - logrus.Errorf("unable to reload configuration: %v", err) + logrus.Errorf("Unable to reload configuration: %v", err) continue } } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 81ddce42f..9fe2d163c 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -561,7 +561,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri errorhandling.Contains(err, define.ErrCtrRemoved) { logrus.Debugf("Container %s does not exist: %v", id, err) } else { - logrus.Errorf("Error removing container %s: %v", id, err) + logrus.Errorf("Removing container %s: %v", id, err) } } } @@ -646,7 +646,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri errorhandling.Contains(err, types.ErrLayerUnknown) { logrus.Debugf("Container %s does not exist: %v", ctr.ID, err) } else { - logrus.Errorf("Error removing container %s: %v", ctr.ID, err) + logrus.Errorf("Removing container %s: %v", ctr.ID, err) } } } @@ -731,7 +731,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta errorhandling.Contains(err, types.ErrLayerUnknown) { logrus.Debugf("Container %s does not exist: %v", con.ID, err) } else { - logrus.Errorf("Error removing container %s: %v", con.ID, err) + logrus.Errorf("Removing container %s: %v", con.ID, err) } } } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 9a746d68c..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 @@ -256,6 +256,7 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, err error ) options := new(images.ExportOptions).WithFormat(opts.Format).WithCompress(opts.Compress) + options = options.WithOciAcceptUncompressedLayers(opts.OciAcceptUncompressedLayers) switch opts.Format { case "oci-dir", "docker-dir": diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go index 6adbc9f34..44a0c3efd 100644 --- a/pkg/errorhandling/errorhandling.go +++ b/pkg/errorhandling/errorhandling.go @@ -63,7 +63,7 @@ func StringsToErrors(strErrs []string) []error { // a defer. func SyncQuiet(f *os.File) { if err := f.Sync(); err != nil { - logrus.Errorf("unable to sync file %s: %q", f.Name(), err) + logrus.Errorf("Unable to sync file %s: %q", f.Name(), err) } } @@ -71,7 +71,7 @@ func SyncQuiet(f *os.File) { // a defer. func CloseQuiet(f *os.File) { if err := f.Close(); err != nil { - logrus.Errorf("unable to close file %s: %q", f.Name(), err) + logrus.Errorf("Unable to close file %s: %q", f.Name(), err) } } diff --git a/pkg/hooks/exec/exec.go b/pkg/hooks/exec/exec.go index f6b6636ad..2b7bc5f31 100644 --- a/pkg/hooks/exec/exec.go +++ b/pkg/hooks/exec/exec.go @@ -56,7 +56,7 @@ func Run(ctx context.Context, hook *rspec.Hook, state []byte, stdout io.Writer, return err, err case <-ctx.Done(): if err := cmd.Process.Kill(); err != nil { - logrus.Errorf("failed to kill pid %v", cmd.Process) + logrus.Errorf("Failed to kill pid %v", cmd.Process) } timer := time.NewTimer(postKillTimeout) defer timer.Stop() diff --git a/pkg/hooks/exec/runtimeconfigfilter.go b/pkg/hooks/exec/runtimeconfigfilter.go index 10b8fedc2..3ab3073b2 100644 --- a/pkg/hooks/exec/runtimeconfigfilter.go +++ b/pkg/hooks/exec/runtimeconfigfilter.go @@ -61,7 +61,7 @@ func RuntimeConfigFilter(ctx context.Context, hooks []spec.Hook, config *spec.Sp if err == nil { logrus.Debugf("precreate hook %d made configuration changes:\n%s", i, diff) } else { - logrus.Warnf("precreate hook %d made configuration changes, but we could not compute a diff: %v", i, err) + logrus.Warnf("Precreate hook %d made configuration changes, but we could not compute a diff: %v", i, err) } } diff --git a/pkg/hooks/monitor.go b/pkg/hooks/monitor.go index 6fa94cd17..ece6e52d1 100644 --- a/pkg/hooks/monitor.go +++ b/pkg/hooks/monitor.go @@ -36,7 +36,7 @@ func (m *Manager) Monitor(ctx context.Context, sync chan<- error) { for _, dir := range m.directories { err = watcher.Add(dir) if err != nil { - logrus.Errorf("failed to watch %q for hooks", dir) + logrus.Errorf("Failed to watch %q for hooks", dir) sync <- err return } @@ -52,7 +52,7 @@ func (m *Manager) Monitor(ctx context.Context, sync chan<- error) { for _, dir := range m.directories { err = ReadDir(dir, m.extensionStages, m.hooks) if err != nil { - logrus.Errorf("failed loading hooks for %s: %v", event.Name, err) + logrus.Errorf("Failed loading hooks for %s: %v", event.Name, err) } } case <-ctx.Done(): diff --git a/pkg/machine/config.go b/pkg/machine/config.go index 8db2335aa..3ff5c7fe7 100644 --- a/pkg/machine/config.go +++ b/pkg/machine/config.go @@ -58,6 +58,9 @@ type ListResponse struct { LastUp time.Time Running bool VMType string + CPUs uint64 + Memory uint64 + DiskSize uint64 } type SSHOptions struct { diff --git a/pkg/machine/fcos.go b/pkg/machine/fcos.go index cfcadeb02..99197ac0e 100644 --- a/pkg/machine/fcos.go +++ b/pkg/machine/fcos.go @@ -139,6 +139,8 @@ func getFCOSDownload(imageStream string) (*fcosDownloadInfo, error) { ) switch imageStream { case "testing", "": + streamType = fedoracoreos.StreamTesting + case "next": streamType = fedoracoreos.StreamNext case "stable": streamType = fedoracoreos.StreamStable 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/machine/qemu/config.go b/pkg/machine/qemu/config.go index 3d0fa4094..9f5f45b58 100644 --- a/pkg/machine/qemu/config.go +++ b/pkg/machine/qemu/config.go @@ -17,6 +17,8 @@ type MachineVM struct { ImagePath string // Memory in megabytes assigned to the vm Memory uint64 + // Disk size in gigabytes assigned to the vm + DiskSize uint64 // Name of the vm Name string // SSH port for user networking diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index d5f538594..727b3cda4 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -64,6 +64,7 @@ func NewMachine(opts machine.InitOptions) (machine.VM, error) { vm.CPUs = opts.CPUS vm.Memory = opts.Memory + vm.DiskSize = opts.DiskSize // Look up the executable execPath, err := exec.LookPath(QemuCommand) @@ -140,7 +141,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) error { v.IdentityPath = filepath.Join(sshDir, v.Name) switch opts.ImagePath { - case "testing", "stable", "": + case "testing", "next", "stable", "": // Get image as usual dd, err := machine.NewFcosDownloader(vmtype, v.Name, opts.ImagePath) if err != nil { @@ -366,7 +367,7 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error { return err } if _, err := os.Stat(pidFile); os.IsNotExist(err) { - logrus.Infof("pid file %s does not exist", pidFile) + logrus.Info(err) return nil } pidString, err := ioutil.ReadFile(pidFile) @@ -391,7 +392,12 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error { logrus.Warn(err) } // Remove socket - return os.Remove(qemuSocketFile) + if err := os.Remove(qemuSocketFile); err != nil { + return err + } + + fmt.Printf("Successfully stopped machine: %s", name) + return nil } // NewQMPMonitor creates the monitor subsection of our vm @@ -459,6 +465,22 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun for _, msg := range files { confirmationMessage += msg + "\n" } + + // Get path to socket and pidFile before we do any cleanups + qemuSocketFile, pidFile, errSocketFile := v.getSocketandPid() + //silently try to delete socket and pid file + //remove socket and pid file if any: warn at low priority if things fail + if errSocketFile == nil { + // Remove the pidfile + if err := os.Remove(pidFile); err != nil && !errors.Is(err, os.ErrNotExist) { + logrus.Debugf("Error while removing pidfile: %v", err) + } + // Remove socket + if err := os.Remove(qemuSocketFile); err != nil && !errors.Is(err, os.ErrNotExist) { + logrus.Debugf("Error while removing podman-machine-socket: %v", err) + } + } + confirmationMessage += "\n" return confirmationMessage, func() error { for _, f := range files { @@ -574,6 +596,9 @@ func GetVMInfos() ([]*machine.ListResponse, error) { listEntry.Name = vm.Name listEntry.VMType = "qemu" + listEntry.CPUs = vm.CPUs + listEntry.Memory = vm.Memory + listEntry.DiskSize = vm.DiskSize fi, err := os.Stat(fullPath) if err != nil { return err diff --git a/pkg/netns/netns_linux.go b/pkg/netns/netns_linux.go index c13ae2f4d..3e6e668b5 100644 --- a/pkg/netns/netns_linux.go +++ b/pkg/netns/netns_linux.go @@ -133,19 +133,19 @@ func NewNSWithName(name string) (ns.NetNS, error) { var origNS ns.NetNS origNS, err = ns.GetNS(threadNsPath) if err != nil { - logrus.Warnf("cannot open current network namespace %s: %q", threadNsPath, err) + logrus.Warnf("Cannot open current network namespace %s: %q", threadNsPath, err) return } defer func() { if err := origNS.Close(); err != nil { - logrus.Errorf("unable to close namespace: %q", err) + logrus.Errorf("Unable to close namespace: %q", err) } }() // create a new netns on the current thread err = unix.Unshare(unix.CLONE_NEWNET) if err != nil { - logrus.Warnf("cannot create a new network namespace: %q", err) + logrus.Warnf("Cannot create a new network namespace: %q", err) return } @@ -157,7 +157,7 @@ func NewNSWithName(name string) (ns.NetNS, error) { // the network namespace owned by root on the host. return } - logrus.Warnf("unable to reset namespace: %q", err) + logrus.Warnf("Unable to reset namespace: %q", err) } }() diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go index 54079baa1..0f154c524 100644 --- a/pkg/ps/ps.go +++ b/pkg/ps/ps.go @@ -139,11 +139,11 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities } startedTime, err = c.StartedTime() if err != nil { - logrus.Errorf("error getting started time for %q: %v", c.ID(), err) + logrus.Errorf("Getting started time for %q: %v", c.ID(), err) } exitedTime, err = c.FinishedTime() if err != nil { - logrus.Errorf("error getting exited time for %q: %v", c.ID(), err) + logrus.Errorf("Getting exited time for %q: %v", c.ID(), err) } pid, err = c.PID() @@ -170,12 +170,12 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities rootFsSize, err := c.RootFsSize() if err != nil { - logrus.Errorf("error getting root fs size for %q: %v", c.ID(), err) + logrus.Errorf("Getting root fs size for %q: %v", c.ID(), err) } rwSize, err := c.RWSize() if err != nil { - logrus.Errorf("error getting rw size for %q: %v", c.ID(), err) + logrus.Errorf("Getting rw size for %q: %v", c.ID(), err) } size.RootFsSize = rootFsSize @@ -241,6 +241,13 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities UTS: uts, } } + + if hc, err := ctr.HealthCheckStatus(); err == nil { + ps.Status = hc + } else { + logrus.Debug(err) + } + return ps, nil } diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 4d8443fcb..6ce4b1e29 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -212,6 +212,7 @@ can_use_shortcut () continue; if (strcmp (argv[argc], "mount") == 0 + || strcmp (argv[argc], "machine") == 0 || strcmp (argv[argc], "search") == 0 || (strcmp (argv[argc], "system") == 0 && argv[argc+1] && strcmp (argv[argc+1], "service") != 0)) { diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index c046ecde7..7f9228666 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -61,20 +61,20 @@ func IsRootless() bool { if rootlessUIDInit != 0 { // This happens if we joined the user+mount namespace as part of if err := os.Setenv("_CONTAINERS_USERNS_CONFIGURED", "done"); err != nil { - logrus.Errorf("failed to set environment variable %s as %s", "_CONTAINERS_USERNS_CONFIGURED", "done") + logrus.Errorf("Failed to set environment variable %s as %s", "_CONTAINERS_USERNS_CONFIGURED", "done") } if err := os.Setenv("_CONTAINERS_ROOTLESS_UID", fmt.Sprintf("%d", rootlessUIDInit)); err != nil { - logrus.Errorf("failed to set environment variable %s as %d", "_CONTAINERS_ROOTLESS_UID", rootlessUIDInit) + logrus.Errorf("Failed to set environment variable %s as %d", "_CONTAINERS_ROOTLESS_UID", rootlessUIDInit) } if err := os.Setenv("_CONTAINERS_ROOTLESS_GID", fmt.Sprintf("%d", rootlessGIDInit)); err != nil { - logrus.Errorf("failed to set environment variable %s as %d", "_CONTAINERS_ROOTLESS_GID", rootlessGIDInit) + logrus.Errorf("Failed to set environment variable %s as %d", "_CONTAINERS_ROOTLESS_GID", rootlessGIDInit) } } isRootless = os.Geteuid() != 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" if !isRootless { hasCapSysAdmin, err := unshare.HasCapSysAdmin() if err != nil { - logrus.Warnf("failed to read CAP_SYS_ADMIN presence for the current process") + logrus.Warnf("Failed to read CAP_SYS_ADMIN presence for the current process") } if err == nil && !hasCapSysAdmin { isRootless = true @@ -284,12 +284,12 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo toWrite = []byte("1") } if _, err := w.Write(toWrite); err != nil { - logrus.Errorf("failed to write byte 0: %q", err) + logrus.Errorf("Failed to write byte 0: %q", err) } if retErr != nil && pid > 0 { if err := unix.Kill(pid, unix.SIGKILL); err != nil { if err != unix.ESRCH { - logrus.Errorf("failed to cleanup process %d: %v", pid, err) + logrus.Errorf("Failed to cleanup process %d: %v", pid, err) } } C.reexec_in_user_namespace_wait(C.int(pid), 0) @@ -325,7 +325,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo uidsMapped = err == nil } if !uidsMapped { - logrus.Warnf("using rootless single mapping into the namespace. This might break some images. Check /etc/subuid and /etc/subgid for adding sub*ids") + logrus.Warnf("Using rootless single mapping into the namespace. This might break some images. Check /etc/subuid and /etc/subgid for adding sub*ids") setgroups := fmt.Sprintf("/proc/%d/setgroups", pid) err = ioutil.WriteFile(setgroups, []byte("deny\n"), 0666) if err != nil { @@ -416,7 +416,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo if err := unix.Kill(int(pidC), s.(unix.Signal)); err != nil { if err != unix.ESRCH { - logrus.Errorf("failed to propagate signal to child process %d: %v", int(pidC), err) + logrus.Errorf("Failed to propagate signal to child process %d: %v", int(pidC), err) } } } diff --git a/pkg/rootlessport/rootlessport_linux.go b/pkg/rootlessport/rootlessport_linux.go index 6c7b8e6d7..37fb7ce79 100644 --- a/pkg/rootlessport/rootlessport_linux.go +++ b/pkg/rootlessport/rootlessport_linux.go @@ -125,17 +125,17 @@ func parent() error { quit := make(chan struct{}) errCh := make(chan error) // start the parent driver. initComplete will be closed when the child connected to the parent. - logrus.Infof("starting parent driver") + logrus.Infof("Starting parent driver") go func() { driverErr := driver.RunParentDriver(initComplete, quit, nil) if driverErr != nil { - logrus.WithError(driverErr).Warn("parent driver exited") + logrus.WithError(driverErr).Warn("Parent driver exited") } errCh <- driverErr close(errCh) }() opaque := driver.OpaqueForChild() - logrus.Infof("opaque=%+v", opaque) + logrus.Infof("Opaque=%+v", opaque) opaqueJSON, err := json.Marshal(opaque) if err != nil { return err @@ -146,9 +146,9 @@ func parent() error { } defer func() { // stop the child - logrus.Info("stopping child driver") + logrus.Info("Stopping child driver") if err := childQuitW.Close(); err != nil { - logrus.WithError(err).Warn("unable to close childQuitW") + logrus.WithError(err).Warn("Unable to close childQuitW") } }() @@ -164,7 +164,7 @@ func parent() error { return err } if err := childNS.Do(func(_ ns.NetNS) error { - logrus.Infof("starting child driver in child netns (%q %v)", cmd.Path, cmd.Args) + logrus.Infof("Starting child driver in child netns (%q %v)", cmd.Path, cmd.Args) return cmd.Start() }); err != nil { return err @@ -179,11 +179,11 @@ func parent() error { defer func() { if err := unix.Kill(cmd.Process.Pid, unix.SIGTERM); err != nil { - logrus.WithError(err).Warn("kill child process") + logrus.WithError(err).Warn("Kill child process") } }() - logrus.Info("waiting for initComplete") + logrus.Info("Waiting for initComplete") // wait for the child to connect to the parent outer: for { @@ -203,15 +203,15 @@ outer: } defer func() { - logrus.Info("stopping parent driver") + logrus.Info("Stopping parent driver") quit <- struct{}{} if err := <-errCh; err != nil { - logrus.WithError(err).Warn("parent driver returned error on exit") + logrus.WithError(err).Warn("Parent driver returned error on exit") } }() // let parent expose ports - logrus.Infof("exposing ports %v", cfg.Mappings) + logrus.Infof("Exposing ports %v", cfg.Mappings) if err := exposePorts(driver, cfg.Mappings, cfg.ChildIP); err != nil { return err } @@ -235,13 +235,13 @@ outer: // remove the socket file on exit defer os.Remove(socketfile) if err != nil { - logrus.Warnf("failed to close the socketDir fd: %v", err) + logrus.Warnf("Failed to close the socketDir fd: %v", err) } defer socket.Close() go serve(socket, driver) } - logrus.Info("ready") + logrus.Info("Ready") // https://github.com/containers/podman/issues/11248 // Copy /dev/null to stdout and stderr to prevent SIGPIPE errors @@ -259,7 +259,7 @@ outer: } // wait for ExitFD to be closed - logrus.Info("waiting for exitfd to be closed") + logrus.Info("Waiting for exitfd to be closed") if _, err := ioutil.ReadAll(exitR); err != nil { return err } @@ -353,10 +353,10 @@ func child() error { errCh <- dErr }() defer func() { - logrus.Info("stopping child driver") + logrus.Info("Stopping child driver") quit <- struct{}{} if err := <-errCh; err != nil { - logrus.WithError(err).Warn("child driver returned error on exit") + logrus.WithError(err).Warn("Child driver returned error on exit") } }() diff --git a/pkg/servicereaper/service.go b/pkg/servicereaper/service.go index e9c4fe908..e105148f0 100644 --- a/pkg/servicereaper/service.go +++ b/pkg/servicereaper/service.go @@ -46,7 +46,7 @@ func reaper(sigc chan os.Signal) { if err != nil { // do not log error for ECHILD if err != syscall.ECHILD { - logrus.Warnf("wait for pid %d failed: %v ", pid, err) + logrus.Warnf("Wait for pid %d failed: %v ", pid, err) } delete(s.pidMap, pid) continue diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index f3ee42b2f..d4bd6073e 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 11027ebdb..a50685d0f 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -24,7 +24,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 } @@ -517,6 +517,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/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index c01d7a1f0..9389b1a20 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -12,6 +12,7 @@ import ( "github.com/containers/common/pkg/parse" "github.com/containers/common/pkg/secrets" "github.com/containers/image/v5/manifest" + "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/network/types" ann "github.com/containers/podman/v3/pkg/annotations" "github.com/containers/podman/v3/pkg/domain/entities" @@ -86,6 +87,8 @@ func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, } type CtrSpecGenOptions struct { + // Annotations from the Pod + Annotations map[string]string // Container as read from the pod yaml Container v1.Container // Image available to use (pulled or found local) @@ -157,7 +160,7 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener return nil, errors.Wrap(err, "Failed to set CPU quota") } if milliCPU > 0 { - period, quota := util.CoresToPeriodAndQuota(float64(milliCPU) / 1000) + period, quota := util.CoresToPeriodAndQuota(float64(milliCPU)) s.ResourceLimits.CPU = &spec.LinuxCPU{ Quota: "a, Period: &period, @@ -289,6 +292,14 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener volume.MountPath = dest switch volumeSource.Type { case KubeVolumeTypeBindMount: + // If the container has bind mounts, we need to check if + // a selinux mount option exists for it + for k, v := range opts.Annotations { + // Make sure the z/Z option is not already there (from editing the YAML) + if strings.Replace(k, define.BindMountPrefix, "", 1) == volumeSource.Source && !util.StringInSlice("z", options) && !util.StringInSlice("Z", options) { + options = append(options, v) + } + } mount := spec.Mount{ Destination: volume.MountPath, Source: volumeSource.Source, diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index 55010f716..beccd9fc2 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -62,7 +62,7 @@ func addRlimits(s *specgen.SpecGenerator, g *generate.Generator) error { if isRootless { var rlimit unix.Rlimit if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit); err != nil { - logrus.Warnf("failed to return RLIMIT_NOFILE ulimit %q", err) + logrus.Warnf("Failed to return RLIMIT_NOFILE ulimit %q", err) } if rlimit.Cur < current { current = rlimit.Cur @@ -79,7 +79,7 @@ func addRlimits(s *specgen.SpecGenerator, g *generate.Generator) error { if isRootless { var rlimit unix.Rlimit if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlimit); err != nil { - logrus.Warnf("failed to return RLIMIT_NPROC ulimit %q", err) + logrus.Warnf("Failed to return RLIMIT_NPROC ulimit %q", err) } if rlimit.Cur < current { current = rlimit.Cur diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go index a12cc09e2..a11debdb5 100644 --- a/pkg/specgen/generate/security.go +++ b/pkg/specgen/generate/security.go @@ -139,7 +139,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, if len(privCapsRequired) == 0 { caplist = capsRequired } else { - logrus.Errorf("capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapsRequired, ",")) + logrus.Errorf("Capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapsRequired, ",")) } } } diff --git a/pkg/specgen/generate/validate.go b/pkg/specgen/generate/validate.go index 50efe7fa3..b0d84825e 100644 --- a/pkg/specgen/generate/validate.go +++ b/pkg/specgen/generate/validate.go @@ -72,10 +72,9 @@ func verifyContainerResourcesCgroupV1(s *specgen.SpecGenerator) ([]string, error // Pids checks if s.ResourceLimits.Pids != nil { - pids := s.ResourceLimits.Pids // TODO: Should this be 0, or checking that ResourceLimits.Pids // is set at all? - if pids.Limit > 0 && !sysInfo.PidsLimit { + if s.ResourceLimits.Pids.Limit >= 0 && !sysInfo.PidsLimit { warnings = append(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.") s.ResourceLimits.Pids = nil } diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index 7aa27487a..70b2aa1ef 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -411,7 +411,7 @@ type ContainerNetworkConfig struct { // Expose is a number of ports that will be forwarded to the container // if PublishExposedPorts is set. // Expose is a map of uint16 (port number) to a string representing - // protocol. Allowed protocols are "tcp", "udp", and "sctp", or some + // protocol i.e map[uint16]string. Allowed protocols are "tcp", "udp", and "sctp", or some // combination of the three separated by commas. // If protocol is set to "" we will assume TCP. // Only available if NetNS is set to Bridge or Slirp, and diff --git a/pkg/specgenutil/volumes.go b/pkg/specgenutil/volumes.go index 0ed08198f..3ce96164f 100644 --- a/pkg/specgenutil/volumes.go +++ b/pkg/specgenutil/volumes.go @@ -243,7 +243,7 @@ func getBindMount(args []string) (spec.Mount, error) { Type: define.TypeBind, } - var setSource, setDest, setRORW, setSuid, setDev, setExec, setRelabel bool + var setSource, setDest, setRORW, setSuid, setDev, setExec, setRelabel, setOwnership bool for _, val := range args { kv := strings.SplitN(val, "=", 2) @@ -343,6 +343,18 @@ func getBindMount(args []string) (spec.Mount, error) { default: return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0]) } + case "U", "chown": + if setOwnership { + return newMount, errors.Wrapf(optionArgError, "cannot pass 'U' or 'chown' option more than once") + } + ok, err := validChownFlag(val) + if err != nil { + return newMount, err + } + if ok { + newMount.Options = append(newMount.Options, "U") + } + setOwnership = true case "consistency": // Often used on MACs and mistakenly on Linux platforms. // Since Docker ignores this option so shall we. @@ -375,7 +387,7 @@ func getTmpfsMount(args []string) (spec.Mount, error) { Source: define.TypeTmpfs, } - var setDest, setRORW, setSuid, setDev, setExec, setTmpcopyup bool + var setDest, setRORW, setSuid, setDev, setExec, setTmpcopyup, setOwnership bool for _, val := range args { kv := strings.SplitN(val, "=", 2) @@ -431,6 +443,18 @@ func getTmpfsMount(args []string) (spec.Mount, error) { } newMount.Destination = filepath.Clean(kv[1]) setDest = true + case "U", "chown": + if setOwnership { + return newMount, errors.Wrapf(optionArgError, "cannot pass 'U' or 'chown' option more than once") + } + ok, err := validChownFlag(val) + if err != nil { + return newMount, err + } + if ok { + newMount.Options = append(newMount.Options, "U") + } + setOwnership = true case "consistency": // Often used on MACs and mistakenly on Linux platforms. // Since Docker ignores this option so shall we. @@ -486,7 +510,7 @@ func getDevptsMount(args []string) (spec.Mount, error) { func getNamedVolume(args []string) (*specgen.NamedVolume, error) { newVolume := new(specgen.NamedVolume) - var setSource, setDest, setRORW, setSuid, setDev, setExec bool + var setSource, setDest, setRORW, setSuid, setDev, setExec, setOwnership bool for _, val := range args { kv := strings.SplitN(val, "=", 2) @@ -532,6 +556,18 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) { } newVolume.Dest = filepath.Clean(kv[1]) setDest = true + case "U", "chown": + if setOwnership { + return newVolume, errors.Wrapf(optionArgError, "cannot pass 'U' or 'chown' option more than once") + } + ok, err := validChownFlag(val) + if err != nil { + return newVolume, err + } + if ok { + newVolume.Options = append(newVolume.Options, "U") + } + setOwnership = true case "consistency": // Often used on MACs and mistakenly on Linux platforms. // Since Docker ignores this option so shall we. @@ -628,3 +664,24 @@ func getTmpfsMounts(tmpfsFlag []string) (map[string]spec.Mount, error) { } return m, nil } + +// validChownFlag ensures that the U or chown flag is correctly used +func validChownFlag(flag string) (bool, error) { + kv := strings.SplitN(flag, "=", 2) + switch len(kv) { + case 1: + case 2: + // U=[true|false] + switch strings.ToLower(kv[1]) { + case "true": + case "false": + return false, nil + default: + return false, errors.Wrapf(optionArgError, "'U' or 'chown' must be set to true or false, instead received %q", kv[1]) + } + default: + return false, errors.Wrapf(optionArgError, "badly formatted option %q", flag) + } + + return true, nil +} diff --git a/pkg/trust/trust.go b/pkg/trust/trust.go index 18a6a1717..584d1fa02 100644 --- a/pkg/trust/trust.go +++ b/pkg/trust/trust.go @@ -188,7 +188,7 @@ func GetGPGIdFromKeyPath(path string) []string { cmd := exec.Command("gpg2", "--with-colons", path) results, err := cmd.Output() if err != nil { - logrus.Errorf("error getting key identity: %s", err) + logrus.Errorf("Getting key identity: %s", err) return nil } return parseUids(results) @@ -203,7 +203,7 @@ func GetGPGIdFromKeyData(key string) []string { } tmpfileName, err := CreateTmpFile("", "", decodeKey) if err != nil { - logrus.Errorf("error creating key date temp file %s", err) + logrus.Errorf("Creating key date temp file %s", err) } defer os.Remove(tmpfileName) return GetGPGIdFromKeyPath(tmpfileName) diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py index dbad6824f..853e9da88 100644 --- a/test/apiv2/python/rest_api/test_v2_0_0_container.py +++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py @@ -56,7 +56,7 @@ class ContainerTestCase(APITestCase): self.assertEqual(r.status_code, 200, r.text) self.assertId(r.content) out = r.json() - self.assertIsNone(out["State"].get("Health")) + self.assertIsNotNone(out["State"].get("Health")) self.assertListEqual(["CMD", "pidof", "top"], out["Config"]["Healthcheck"]["Test"]) self.assertEqual(5000000000, out["Config"]["Healthcheck"]["Interval"]) self.assertEqual(2000000000, out["Config"]["Healthcheck"]["Timeout"]) 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/commit_test.go b/test/e2e/commit_test.go index fbd4068f8..d40faf54b 100644 --- a/test/e2e/commit_test.go +++ b/test/e2e/commit_test.go @@ -332,7 +332,7 @@ var _ = Describe("Podman commit", func() { It("podman commit adds exposed ports", func() { name := "testcon" - s := podmanTest.Podman([]string{"run", "--name", name, "-p", "8080:80", ALPINE, "true"}) + s := podmanTest.Podman([]string{"run", "--name", name, "-p", "8585:80", ALPINE, "true"}) s.WaitWithDefaultTimeout() Expect(s).Should(Exit(0)) diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 20ed72c59..7228682f3 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -311,7 +311,7 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration { func (p PodmanTestIntegration) AddImageToRWStore(image string) { if err := p.RestoreArtifact(image); err != nil { - logrus.Errorf("unable to restore %s to RW store", image) + logrus.Errorf("Unable to restore %s to RW store", image) } } diff --git a/test/e2e/container_inspect_test.go b/test/e2e/container_inspect_test.go index 7d05b09fb..597eeb1a4 100644 --- a/test/e2e/container_inspect_test.go +++ b/test/e2e/container_inspect_test.go @@ -47,25 +47,25 @@ var _ = Describe("Podman container inspect", func() { It("podman inspect shows exposed ports", func() { name := "testcon" - session := podmanTest.Podman([]string{"run", "-d", "--stop-timeout", "0", "--expose", "8080/udp", "--name", name, ALPINE, "sleep", "inf"}) + session := podmanTest.Podman([]string{"run", "-d", "--stop-timeout", "0", "--expose", "8787/udp", "--name", name, ALPINE, "sleep", "inf"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) data := podmanTest.InspectContainer(name) Expect(data).To(HaveLen(1)) Expect(data[0].NetworkSettings.Ports). - To(Equal(map[string][]define.InspectHostPort{"8080/udp": nil})) + To(Equal(map[string][]define.InspectHostPort{"8787/udp": nil})) }) It("podman inspect shows exposed ports on image", func() { name := "testcon" - session := podmanTest.Podman([]string{"run", "-d", "--expose", "8080", "--name", name, nginx}) + session := podmanTest.Podman([]string{"run", "-d", "--expose", "8989", "--name", name, nginx}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) data := podmanTest.InspectContainer(name) Expect(data).To(HaveLen(1)) Expect(data[0].NetworkSettings.Ports). - To(Equal(map[string][]define.InspectHostPort{"80/tcp": nil, "8080/tcp": nil})) + To(Equal(map[string][]define.InspectHostPort{"80/tcp": nil, "8989/tcp": nil})) }) }) diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index 32d98c2a9..d20dc8874 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -618,7 +618,7 @@ var _ = Describe("Podman create", func() { pod.WaitWithDefaultTimeout() Expect(pod).Should(Exit(0)) - session := podmanTest.Podman([]string{"create", "--pod", name, "-p", "8080:80", ALPINE, "top"}) + session := podmanTest.Podman([]string{"create", "--pod", name, "-p", "8086:80", ALPINE, "top"}) session.WaitWithDefaultTimeout() Expect(session).Should(ExitWithError()) }) diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index bf89a0708..cb987e139 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -6,6 +6,8 @@ import ( "path/filepath" "strconv" + "github.com/containers/podman/v3/libpod/define" + "github.com/containers/podman/v3/pkg/util" . "github.com/containers/podman/v3/test/utils" "github.com/ghodss/yaml" @@ -555,6 +557,15 @@ var _ = Describe("Podman generate kube", func() { kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) + b, err := ioutil.ReadFile(outputFile) + Expect(err).ShouldNot(HaveOccurred()) + pod := new(v1.Pod) + err = yaml.Unmarshal(b, pod) + Expect(err).To(BeNil()) + val, found := pod.Annotations[define.BindMountPrefix+vol1] + Expect(found).To(BeTrue()) + Expect(val).To(HaveSuffix("z")) + rm := podmanTest.Podman([]string{"pod", "rm", "-f", "test1"}) rm.WaitWithDefaultTimeout() Expect(rm).Should(Exit(0)) @@ -792,6 +803,45 @@ var _ = Describe("Podman generate kube", func() { Expect(containers[0].Args).To(Equal([]string{"10s"})) }) + It("podman generate kube - no command", func() { + session := podmanTest.Podman([]string{"create", "--name", "test", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + kube := podmanTest.Podman([]string{"generate", "kube", "test"}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + // Now make sure that the container's command is not set to the + // entrypoint and it's arguments to "10s". + pod := new(v1.Pod) + err := yaml.Unmarshal(kube.Out.Contents(), pod) + Expect(err).To(BeNil()) + + containers := pod.Spec.Containers + Expect(len(containers)).To(Equal(1)) + Expect(len(containers[0].Command)).To(Equal(0)) + + cmd := []string{"echo", "hi"} + session = podmanTest.Podman(append([]string{"create", "--name", "test1", ALPINE}, cmd...)) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + kube = podmanTest.Podman([]string{"generate", "kube", "test1"}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + // Now make sure that the container's command is not set to the + // entrypoint and it's arguments to "10s". + pod = new(v1.Pod) + err = yaml.Unmarshal(kube.Out.Contents(), pod) + Expect(err).To(BeNil()) + + containers = pod.Spec.Containers + Expect(len(containers)).To(Equal(1)) + Expect(containers[0].Command).To(Equal(cmd)) + }) + It("podman generate kube - use entrypoint from image", func() { // Build an image with an entrypoint. containerfile := `FROM quay.io/libpod/alpine:latest diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go index 87f042ed9..b2666c789 100644 --- a/test/e2e/healthcheck_run_test.go +++ b/test/e2e/healthcheck_run_test.go @@ -80,6 +80,11 @@ var _ = Describe("Podman healthcheck run", func() { time.Sleep(1 * time.Second) } Expect(exitCode).To(Equal(0)) + + ps := podmanTest.Podman([]string{"ps"}) + ps.WaitWithDefaultTimeout() + Expect(ps).Should(Exit(0)) + Expect(ps.OutputToString()).To(ContainSubstring("(healthy)")) }) It("podman healthcheck that should fail", func() { @@ -117,7 +122,7 @@ var _ = Describe("Podman healthcheck run", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) inspect := podmanTest.InspectContainer("hc") - Expect(inspect[0].State.Healthcheck.Status).To(Equal("starting")) + Expect(inspect[0].State.Health.Status).To(Equal("starting")) }) It("podman healthcheck failed checks in start-period should not change status", func() { @@ -138,7 +143,9 @@ var _ = Describe("Podman healthcheck run", func() { Expect(hc).Should(Exit(1)) inspect := podmanTest.InspectContainer("hc") - Expect(inspect[0].State.Healthcheck.Status).To(Equal("starting")) + Expect(inspect[0].State.Health.Status).To(Equal("starting")) + // test old podman compat (see #11645) + Expect(inspect[0].State.Healthcheck().Status).To(Equal("starting")) }) It("podman healthcheck failed checks must reach retries before unhealthy ", func() { @@ -151,15 +158,16 @@ var _ = Describe("Podman healthcheck run", func() { Expect(hc).Should(Exit(1)) inspect := podmanTest.InspectContainer("hc") - Expect(inspect[0].State.Healthcheck.Status).To(Equal("starting")) + Expect(inspect[0].State.Health.Status).To(Equal("starting")) hc = podmanTest.Podman([]string{"healthcheck", "run", "hc"}) hc.WaitWithDefaultTimeout() Expect(hc).Should(Exit(1)) inspect = podmanTest.InspectContainer("hc") - Expect(inspect[0].State.Healthcheck.Status).To(Equal(define.HealthCheckUnhealthy)) - + Expect(inspect[0].State.Health.Status).To(Equal(define.HealthCheckUnhealthy)) + // test old podman compat (see #11645) + Expect(inspect[0].State.Healthcheck().Status).To(Equal(define.HealthCheckUnhealthy)) }) It("podman healthcheck good check results in healthy even in start-period", func() { @@ -172,7 +180,7 @@ var _ = Describe("Podman healthcheck run", func() { Expect(hc).Should(Exit(0)) inspect := podmanTest.InspectContainer("hc") - Expect(inspect[0].State.Healthcheck.Status).To(Equal(define.HealthCheckHealthy)) + Expect(inspect[0].State.Health.Status).To(Equal(define.HealthCheckHealthy)) }) It("podman healthcheck unhealthy but valid arguments check", func() { @@ -195,14 +203,14 @@ var _ = Describe("Podman healthcheck run", func() { Expect(hc).Should(Exit(1)) inspect := podmanTest.InspectContainer("hc") - Expect(inspect[0].State.Healthcheck.Status).To(Equal("starting")) + Expect(inspect[0].State.Health.Status).To(Equal("starting")) hc = podmanTest.Podman([]string{"healthcheck", "run", "hc"}) hc.WaitWithDefaultTimeout() Expect(hc).Should(Exit(1)) inspect = podmanTest.InspectContainer("hc") - Expect(inspect[0].State.Healthcheck.Status).To(Equal(define.HealthCheckUnhealthy)) + Expect(inspect[0].State.Health.Status).To(Equal(define.HealthCheckUnhealthy)) foo := podmanTest.Podman([]string{"exec", "hc", "touch", "/foo"}) foo.WaitWithDefaultTimeout() @@ -213,6 +221,13 @@ var _ = Describe("Podman healthcheck run", func() { Expect(hc).Should(Exit(0)) inspect = podmanTest.InspectContainer("hc") - Expect(inspect[0].State.Healthcheck.Status).To(Equal(define.HealthCheckHealthy)) + Expect(inspect[0].State.Health.Status).To(Equal(define.HealthCheckHealthy)) + + // Test podman ps --filter heath is working (#11687) + ps := podmanTest.Podman([]string{"ps", "--filter", "health=healthy"}) + ps.WaitWithDefaultTimeout() + Expect(ps).Should(Exit(0)) + Expect(len(ps.OutputToStringArray())).To(Equal(2)) + Expect(ps.OutputToString()).To(ContainSubstring("hc")) }) }) diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index 12165d92d..63a54a5ca 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -451,14 +451,14 @@ var _ = Describe("Podman inspect", func() { It("podman inspect --format json .NetworkSettings.Ports", func() { ctnrName := "Ctnr_" + RandomString(25) - create := podmanTest.Podman([]string{"create", "--name", ctnrName, "-p", "8080:80", ALPINE}) + create := podmanTest.Podman([]string{"create", "--name", ctnrName, "-p", "8084:80", ALPINE}) create.WaitWithDefaultTimeout() Expect(create).Should(Exit(0)) inspect := podmanTest.Podman([]string{"inspect", `--format="{{json .NetworkSettings.Ports}}"`, ctnrName}) inspect.WaitWithDefaultTimeout() Expect(inspect).Should(Exit(0)) - Expect(inspect.OutputToString()).To(Equal(`"{"80/tcp":[{"HostIp":"","HostPort":"8080"}]}"`)) + Expect(inspect.OutputToString()).To(Equal(`"{"80/tcp":[{"HostIp":"","HostPort":"8084"}]}"`)) }) It("Verify container inspect has default network", func() { 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/play_build_test.go b/test/e2e/play_build_test.go index 16f2687f3..564735e07 100644 --- a/test/e2e/play_build_test.go +++ b/test/e2e/play_build_test.go @@ -80,12 +80,17 @@ status: {} FROM quay.io/libpod/alpine_nginx:latest RUN apk update && apk add strace LABEL homer=dad +COPY copyfile /copyfile ` var prebuiltImage = ` FROM quay.io/libpod/alpine_nginx:latest RUN apk update && apk add strace LABEL marge=mom ` + + var copyFile = `just a text file +` + It("Check that image is built using Dockerfile", func() { // Setup yamlDir := filepath.Join(tempdir, RandomString(12)) @@ -97,7 +102,9 @@ LABEL marge=mom Expect(err).To(BeNil()) err = writeYaml(playBuildFile, filepath.Join(app1Dir, "Dockerfile")) Expect(err).To(BeNil()) - + // Write a file to be copied + err = writeYaml(copyFile, filepath.Join(app1Dir, "copyfile")) + Expect(err).To(BeNil()) // Switch to temp dir and restore it afterwards cwd, err := os.Getwd() Expect(err).To(BeNil()) @@ -131,7 +138,9 @@ LABEL marge=mom Expect(err).To(BeNil()) err = writeYaml(playBuildFile, filepath.Join(app1Dir, "Containerfile")) Expect(err).To(BeNil()) - + // Write a file to be copied + err = writeYaml(copyFile, filepath.Join(app1Dir, "copyfile")) + Expect(err).To(BeNil()) // Switch to temp dir and restore it afterwards cwd, err := os.Getwd() Expect(err).To(BeNil()) @@ -172,6 +181,9 @@ LABEL marge=mom Expect(err).To(BeNil()) err = writeYaml(playBuildFile, filepath.Join(app1Dir, "Containerfile")) Expect(err).To(BeNil()) + // Write a file to be copied + err = writeYaml(copyFile, filepath.Join(app1Dir, "copyfile")) + Expect(err).To(BeNil()) // Switch to temp dir and restore it afterwards cwd, err := os.Getwd() @@ -215,6 +227,9 @@ LABEL marge=mom Expect(err).To(BeNil()) err = writeYaml(playBuildFile, filepath.Join(app1Dir, "Containerfile")) Expect(err).To(BeNil()) + // Write a file to be copied + err = writeYaml(copyFile, filepath.Join(app1Dir, "copyfile")) + Expect(err).To(BeNil()) // Switch to temp dir and restore it afterwards cwd, err := os.Getwd() diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 0d5b9d52c..83ce751e6 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -2320,6 +2320,39 @@ MemoryReservation: {{ .HostConfig.MemoryReservation }}`}) } }) + It("podman play kube allows setting resource limits with --cpus 1", func() { + SkipIfContainerized("Resource limits require a running systemd") + SkipIfRootless("CPU limits require root") + podmanTest.CgroupManager = "systemd" + + var ( + expectedCpuLimit string = "1" + ) + + deployment := getDeployment( + withPod(getPod(withCtr(getCtr( + withCpuLimit(expectedCpuLimit), + ))))) + err := generateKubeYaml("deployment", deployment, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + for _, pod := range getPodNamesInDeployment(deployment) { + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(&pod), "--format", `{{ .HostConfig.CpuPeriod }}:{{ .HostConfig.CpuQuota }}`}) + + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + + parts := strings.Split(strings.Trim(inspect.OutputToString(), "\n"), ":") + Expect(parts).To(HaveLen(2)) + + Expect(parts[0]).To(Equal(parts[1])) + } + }) + It("podman play kube reports invalid image name", func() { invalidImageName := "./myimage" diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 67bd28da6..e8bc871da 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -108,7 +108,7 @@ var _ = Describe("Podman pod create", func() { It("podman create pod with network portbindings", func() { name := "test" - session := podmanTest.Podman([]string{"pod", "create", "--name", name, "-p", "8080:80"}) + session := podmanTest.Podman([]string{"pod", "create", "--name", name, "-p", "8081:80"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) pod := session.OutputToString() @@ -117,14 +117,14 @@ var _ = Describe("Podman pod create", func() { webserver.WaitWithDefaultTimeout() Expect(webserver).Should(Exit(0)) - check := SystemExec("nc", []string{"-z", "localhost", "8080"}) + check := SystemExec("nc", []string{"-z", "localhost", "8081"}) Expect(check).Should(Exit(0)) }) It("podman create pod with id file with network portbindings", func() { file := filepath.Join(podmanTest.TempDir, "pod.id") name := "test" - session := podmanTest.Podman([]string{"pod", "create", "--name", name, "--pod-id-file", file, "-p", "8080:80"}) + session := podmanTest.Podman([]string{"pod", "create", "--name", name, "--pod-id-file", file, "-p", "8082:80"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -132,7 +132,7 @@ var _ = Describe("Podman pod create", func() { webserver.WaitWithDefaultTimeout() Expect(webserver).Should(Exit(0)) - check := SystemExec("nc", []string{"-z", "localhost", "8080"}) + check := SystemExec("nc", []string{"-z", "localhost", "8082"}) Expect(check).Should(Exit(0)) }) diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go index 6633b228c..5728cf9b9 100644 --- a/test/e2e/pod_inspect_test.go +++ b/test/e2e/pod_inspect_test.go @@ -85,7 +85,7 @@ var _ = Describe("Podman pod inspect", func() { It("podman pod inspect outputs port bindings", func() { podName := "testPod" - create := podmanTest.Podman([]string{"pod", "create", "--name", podName, "-p", "8080:80"}) + create := podmanTest.Podman([]string{"pod", "create", "--name", podName, "-p", "8383:80"}) create.WaitWithDefaultTimeout() Expect(create).Should(Exit(0)) @@ -98,7 +98,7 @@ var _ = Describe("Podman pod inspect", func() { Expect(err).To(BeNil()) Expect(inspectJSON.InfraConfig).To(Not(BeNil())) Expect(len(inspectJSON.InfraConfig.PortBindings["80/tcp"])).To(Equal(1)) - Expect(inspectJSON.InfraConfig.PortBindings["80/tcp"][0].HostPort).To(Equal("8080")) + Expect(inspectJSON.InfraConfig.PortBindings["80/tcp"][0].HostPort).To(Equal("8383")) }) It("podman pod inspect outputs show correct MAC", func() { diff --git a/test/e2e/pod_start_test.go b/test/e2e/pod_start_test.go index 93c200389..e895b5598 100644 --- a/test/e2e/pod_start_test.go +++ b/test/e2e/pod_start_test.go @@ -92,7 +92,7 @@ var _ = Describe("Podman pod start", func() { pod, _, podid1 := podmanTest.CreatePod(map[string][]string{ "--infra": {"true"}, "--name": {podName[0]}, - "--publish": {"127.0.0.1:8080:80"}, + "--publish": {"127.0.0.1:8083:80"}, }) Expect(pod).To(Exit(0)) @@ -103,7 +103,7 @@ var _ = Describe("Podman pod start", func() { pod, _, podid2 := podmanTest.CreatePod(map[string][]string{ "--infra": {"true"}, "--name": {podName[1]}, - "--publish": {"127.0.0.1:8080:80"}, + "--publish": {"127.0.0.1:8083:80"}, }) Expect(pod).To(Exit(0)) diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go index 010885dd5..881d9fcf0 100644 --- a/test/e2e/ps_test.go +++ b/test/e2e/ps_test.go @@ -609,7 +609,7 @@ var _ = Describe("Podman ps", func() { It("podman ps test with port shared with pod", func() { podName := "testPod" - pod := podmanTest.Podman([]string{"pod", "create", "-p", "8080:80", "--name", podName}) + pod := podmanTest.Podman([]string{"pod", "create", "-p", "8085:80", "--name", podName}) pod.WaitWithDefaultTimeout() Expect(pod).Should(Exit(0)) @@ -621,7 +621,7 @@ var _ = Describe("Podman ps", func() { ps := podmanTest.Podman([]string{"ps", "--filter", fmt.Sprintf("name=%s", ctrName), "--format", "{{.Ports}}"}) ps.WaitWithDefaultTimeout() Expect(ps).Should(Exit(0)) - Expect(ps.OutputToString()).To(ContainSubstring("0.0.0.0:8080->80/tcp")) + Expect(ps.OutputToString()).To(ContainSubstring("0.0.0.0:8085->80/tcp")) }) It("podman ps truncate long create command", func() { 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/run_networking_test.go b/test/e2e/run_networking_test.go index c7ffdaf4c..84707732b 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -98,9 +98,9 @@ var _ = Describe("Podman run networking", func() { Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal("")) }) - It("podman run -p 80-82 -p 8080:8080", func() { + It("podman run -p 80-82 -p 8090:8090", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "80-82", "-p", "8080:8080", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "80-82", "-p", "8090:8090", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) @@ -114,14 +114,14 @@ var _ = Describe("Podman run networking", func() { Expect(len(inspectOut[0].NetworkSettings.Ports["82/tcp"])).To(Equal(1)) Expect(inspectOut[0].NetworkSettings.Ports["82/tcp"][0].HostPort).To(Not(Equal("82"))) Expect(inspectOut[0].NetworkSettings.Ports["82/tcp"][0].HostIP).To(Equal("")) - Expect(len(inspectOut[0].NetworkSettings.Ports["8080/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostPort).To(Equal("8080")) - Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostIP).To(Equal("")) + Expect(len(inspectOut[0].NetworkSettings.Ports["8090/tcp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8090/tcp"][0].HostPort).To(Equal("8090")) + Expect(inspectOut[0].NetworkSettings.Ports["8090/tcp"][0].HostIP).To(Equal("")) }) - It("podman run -p 80-81 -p 8080-8081", func() { + It("podman run -p 80-81 -p 8180-8181", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "80-81", "-p", "8080-8081", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "80-81", "-p", "8180-8181", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) @@ -132,17 +132,17 @@ var _ = Describe("Podman run networking", func() { Expect(len(inspectOut[0].NetworkSettings.Ports["81/tcp"])).To(Equal(1)) Expect(inspectOut[0].NetworkSettings.Ports["81/tcp"][0].HostPort).To(Not(Equal("81"))) Expect(inspectOut[0].NetworkSettings.Ports["81/tcp"][0].HostIP).To(Equal("")) - Expect(len(inspectOut[0].NetworkSettings.Ports["8080/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostPort).To(Not(Equal("8080"))) - Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostIP).To(Equal("")) - Expect(len(inspectOut[0].NetworkSettings.Ports["8081/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["8081/tcp"][0].HostPort).To(Not(Equal("8081"))) - Expect(inspectOut[0].NetworkSettings.Ports["8081/tcp"][0].HostIP).To(Equal("")) + Expect(len(inspectOut[0].NetworkSettings.Ports["8180/tcp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8180/tcp"][0].HostPort).To(Not(Equal("8180"))) + Expect(inspectOut[0].NetworkSettings.Ports["8180/tcp"][0].HostIP).To(Equal("")) + Expect(len(inspectOut[0].NetworkSettings.Ports["8181/tcp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8181/tcp"][0].HostPort).To(Not(Equal("8181"))) + Expect(inspectOut[0].NetworkSettings.Ports["8181/tcp"][0].HostIP).To(Equal("")) }) - It("podman run -p 80 -p 8080-8082:8080-8082", func() { + It("podman run -p 80 -p 8280-8282:8280-8282", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "80", "-p", "8080-8082:8080-8082", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "80", "-p", "8280-8282:8280-8282", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) @@ -150,40 +150,40 @@ var _ = Describe("Podman run networking", func() { Expect(len(inspectOut[0].NetworkSettings.Ports["80/tcp"])).To(Equal(1)) Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Not(Equal("80"))) Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal("")) - Expect(len(inspectOut[0].NetworkSettings.Ports["8080/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostPort).To(Equal("8080")) - Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostIP).To(Equal("")) - Expect(len(inspectOut[0].NetworkSettings.Ports["8081/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["8081/tcp"][0].HostPort).To(Equal("8081")) - Expect(inspectOut[0].NetworkSettings.Ports["8081/tcp"][0].HostIP).To(Equal("")) - Expect(len(inspectOut[0].NetworkSettings.Ports["8082/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["8082/tcp"][0].HostPort).To(Equal("8082")) - Expect(inspectOut[0].NetworkSettings.Ports["8082/tcp"][0].HostIP).To(Equal("")) - }) - - It("podman run -p 8080:80", func() { + Expect(len(inspectOut[0].NetworkSettings.Ports["8280/tcp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8280/tcp"][0].HostPort).To(Equal("8280")) + Expect(inspectOut[0].NetworkSettings.Ports["8280/tcp"][0].HostIP).To(Equal("")) + Expect(len(inspectOut[0].NetworkSettings.Ports["8281/tcp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8281/tcp"][0].HostPort).To(Equal("8281")) + Expect(inspectOut[0].NetworkSettings.Ports["8281/tcp"][0].HostIP).To(Equal("")) + Expect(len(inspectOut[0].NetworkSettings.Ports["8282/tcp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8282/tcp"][0].HostPort).To(Equal("8282")) + Expect(inspectOut[0].NetworkSettings.Ports["8282/tcp"][0].HostIP).To(Equal("")) + }) + + It("podman run -p 8380:80", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "8080:80", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "8380:80", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports["80/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("8080")) + Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("8380")) Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal("")) }) - It("podman run -p 8080:80/TCP", func() { + It("podman run -p 8480:80/TCP", func() { name := "testctr" // "TCP" in upper characters - session := podmanTest.Podman([]string{"create", "-t", "-p", "8080:80/TCP", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "8480:80/TCP", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) // "tcp" in lower characters Expect(len(inspectOut[0].NetworkSettings.Ports["80/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("8080")) + Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("8480")) Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal("")) }) @@ -199,51 +199,51 @@ var _ = Describe("Podman run networking", func() { Expect(inspectOut[0].NetworkSettings.Ports["80/udp"][0].HostIP).To(Equal("")) }) - It("podman run -p 127.0.0.1:8080:80", func() { + It("podman run -p 127.0.0.1:8580:80", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1:8080:80", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1:8580:80", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports["80/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("8080")) + Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("8580")) Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal("127.0.0.1")) }) - It("podman run -p 127.0.0.1:8080:80/udp", func() { + It("podman run -p 127.0.0.1:8680:80/udp", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1:8080:80/udp", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1:8680:80/udp", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports["80/udp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["80/udp"][0].HostPort).To(Equal("8080")) + Expect(inspectOut[0].NetworkSettings.Ports["80/udp"][0].HostPort).To(Equal("8680")) Expect(inspectOut[0].NetworkSettings.Ports["80/udp"][0].HostIP).To(Equal("127.0.0.1")) }) - It("podman run -p [::1]:8080:80/udp", func() { + It("podman run -p [::1]:8780:80/udp", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "[::1]:8080:80/udp", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "[::1]:8780:80/udp", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports["80/udp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["80/udp"][0].HostPort).To(Equal("8080")) + Expect(inspectOut[0].NetworkSettings.Ports["80/udp"][0].HostPort).To(Equal("8780")) Expect(inspectOut[0].NetworkSettings.Ports["80/udp"][0].HostIP).To(Equal("::1")) }) - It("podman run -p [::1]:8080:80/tcp", func() { + It("podman run -p [::1]:8880:80/tcp", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "[::1]:8080:80/tcp", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "[::1]:8880:80/tcp", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports["80/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("8080")) + Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("8880")) Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal("::1")) }) @@ -283,33 +283,33 @@ var _ = Describe("Podman run networking", func() { Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal("")) }) - It("podman run -p 127.0.0.1::8080/udp", func() { + It("podman run -p 127.0.0.1::8980/udp", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1::8080/udp", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1::8980/udp", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) - Expect(len(inspectOut[0].NetworkSettings.Ports["8080/udp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["8080/udp"][0].HostPort).To(Not(Equal("8080"))) - Expect(inspectOut[0].NetworkSettings.Ports["8080/udp"][0].HostIP).To(Equal("127.0.0.1")) + Expect(len(inspectOut[0].NetworkSettings.Ports["8980/udp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8980/udp"][0].HostPort).To(Not(Equal("8980"))) + Expect(inspectOut[0].NetworkSettings.Ports["8980/udp"][0].HostIP).To(Equal("127.0.0.1")) }) - It("podman run -p :8080", func() { + It("podman run -p :8181", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", ":8080", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", ":8181", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) - Expect(len(inspectOut[0].NetworkSettings.Ports["8080/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostPort).To(Not(Equal("8080"))) - Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostIP).To(Equal("")) + Expect(len(inspectOut[0].NetworkSettings.Ports["8181/tcp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8181/tcp"][0].HostPort).To(Not(Equal("8181"))) + Expect(inspectOut[0].NetworkSettings.Ports["8181/tcp"][0].HostIP).To(Equal("")) }) - It("podman run -p 8080:8080 -p 8081:8080", func() { + It("podman run -p xxx:8080 -p yyy:8080", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "4000:8080", "-p", "8000:8080", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "4444:8080", "-p", "5555:8080", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) @@ -320,18 +320,18 @@ var _ = Describe("Podman run networking", func() { hp2 := inspectOut[0].NetworkSettings.Ports["8080/tcp"][1].HostPort // We can't guarantee order - Expect((hp1 == "4000" && hp2 == "8000") || (hp1 == "8000" && hp2 == "4000")).To(BeTrue()) + Expect((hp1 == "4444" && hp2 == "5555") || (hp1 == "5555" && hp2 == "4444")).To(BeTrue()) }) - It("podman run -p 0.0.0.0:8080:80", func() { + It("podman run -p 0.0.0.0:9280:80", func() { name := "testctr" - session := podmanTest.Podman([]string{"create", "-t", "-p", "0.0.0.0:8080:80", "--name", name, ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"create", "-t", "-p", "0.0.0.0:9280:80", "--name", name, ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() inspectOut := podmanTest.InspectContainer(name) Expect(len(inspectOut)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) Expect(len(inspectOut[0].NetworkSettings.Ports["80/tcp"])).To(Equal(1)) - Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("8080")) + Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostPort).To(Equal("9280")) Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal("")) }) @@ -348,20 +348,20 @@ var _ = Describe("Podman run networking", func() { Expect(ncBusy).To(ExitWithError()) }) - It("podman run network expose host port 8081 to container port 8000 using rootlesskit port handler", func() { - session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:port_handler=rootlesskit", "-dt", "-p", "8081:8000", ALPINE, "/bin/sh"}) + It("podman run network expose host port 18081 to container port 8000 using rootlesskit port handler", func() { + session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:port_handler=rootlesskit", "-dt", "-p", "18081:8000", ALPINE, "/bin/sh"}) session.Wait(30) Expect(session).Should(Exit(0)) - ncBusy := SystemExec("nc", []string{"-l", "-p", "8081"}) + ncBusy := SystemExec("nc", []string{"-l", "-p", "18081"}) Expect(ncBusy).To(ExitWithError()) }) - It("podman run network expose host port 8082 to container port 8000 using slirp4netns port handler", func() { - session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:port_handler=slirp4netns", "-dt", "-p", "8082:8000", ALPINE, "/bin/sh"}) + It("podman run network expose host port 18082 to container port 8000 using slirp4netns port handler", func() { + session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:port_handler=slirp4netns", "-dt", "-p", "18082:8000", ALPINE, "/bin/sh"}) session.Wait(30) Expect(session).Should(Exit(0)) - ncBusy := SystemExec("nc", []string{"-l", "-p", "8082"}) + ncBusy := SystemExec("nc", []string{"-l", "-p", "18082"}) Expect(ncBusy).To(ExitWithError()) }) @@ -650,13 +650,13 @@ var _ = Describe("Podman run networking", func() { defer podmanTest.removeCNINetwork(netName) name := "nc-server" - run := podmanTest.Podman([]string{"run", "--log-driver", "k8s-file", "-d", "--name", name, "--net", netName, ALPINE, "nc", "-l", "-p", "8080"}) + run := podmanTest.Podman([]string{"run", "--log-driver", "k8s-file", "-d", "--name", name, "--net", netName, ALPINE, "nc", "-l", "-p", "9480"}) run.WaitWithDefaultTimeout() Expect(run).Should(Exit(0)) // NOTE: we force the k8s-file log driver to make sure the // tests are passing inside a container. - run = podmanTest.Podman([]string{"run", "--log-driver", "k8s-file", "--rm", "--net", netName, "--uidmap", "0:1:4096", ALPINE, "sh", "-c", fmt.Sprintf("echo podman | nc -w 1 %s.dns.podman 8080", name)}) + run = podmanTest.Podman([]string{"run", "--log-driver", "k8s-file", "--rm", "--net", netName, "--uidmap", "0:1:4096", ALPINE, "sh", "-c", fmt.Sprintf("echo podman | nc -w 1 %s.dns.podman 9480", name)}) run.WaitWithDefaultTimeout() Expect(run).Should(Exit(0)) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index ec4b0d997..b6743f4b7 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1148,11 +1148,11 @@ USER mail`, BB) }) It("podman run --pod automatically", func() { - session := podmanTest.Podman([]string{"run", "-d", "--pod", "new:foobar", ALPINE, "nc", "-l", "-p", "8080"}) + session := podmanTest.Podman([]string{"run", "-d", "--pod", "new:foobar", ALPINE, "nc", "-l", "-p", "8686"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - session = podmanTest.Podman([]string{"run", "--pod", "foobar", ALPINE, "/bin/sh", "-c", "echo test | nc -w 1 127.0.0.1 8080"}) + session = podmanTest.Podman([]string{"run", "--pod", "foobar", ALPINE, "/bin/sh", "-c", "echo test | nc -w 1 127.0.0.1 8686"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 4264e1efe..f1baa7780 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -647,7 +647,7 @@ VOLUME /test/`, ALPINE) Expect(len(session.OutputToStringArray())).To(Equal(2)) }) - It("podman run with U volume flag", func() { + It("podman run with --volume and U flag", func() { SkipIfRemote("Overlay volumes only work locally") u, err := user.Current() @@ -698,6 +698,65 @@ VOLUME /test/`, ALPINE) Expect(found).Should(BeTrue()) }) + It("podman run with --mount and U flag", func() { + u, err := user.Current() + Expect(err).To(BeNil()) + name := u.Username + if name == "root" { + name = "containers" + } + + content, err := ioutil.ReadFile("/etc/subuid") + if err != nil { + Skip("cannot read /etc/subuid") + } + + if !strings.Contains(string(content), name) { + Skip("cannot find mappings for the current user") + } + + mountPath := filepath.Join(podmanTest.TempDir, "foo") + os.Mkdir(mountPath, 0755) + + // false bind mount + vol := "type=bind,src=" + mountPath + ",dst=" + dest + ",U=false" + session := podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).ShouldNot(Equal("888:888")) + + // invalid bind mount + vol = "type=bind,src=" + mountPath + ",dst=" + dest + ",U=invalid" + session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) + + // true bind mount + vol = "type=bind,src=" + mountPath + ",dst=" + dest + ",U=true" + session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).Should(Equal("888:888")) + + // tmpfs mount + vol = "type=tmpfs," + "dst=" + dest + ",chown" + session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).Should(Equal("888:888")) + + // named volume mount + namedVolume := podmanTest.Podman([]string{"volume", "create", "foo"}) + namedVolume.WaitWithDefaultTimeout() + Expect(namedVolume).Should(Exit(0)) + + vol = "type=volume,src=foo,dst=" + dest + ",chown=true" + session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).Should(Equal("888:888")) + }) + It("volume permissions after run", func() { imgName := "testimg" dockerfile := fmt.Sprintf(`FROM %s 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/e2e/system_connection_test.go b/test/e2e/system_connection_test.go index 21398887a..6cdb78c5e 100644 --- a/test/e2e/system_connection_test.go +++ b/test/e2e/system_connection_test.go @@ -138,7 +138,7 @@ var _ = Describe("podman system connection", func() { It("add tcp", func() { cmd := []string{"system", "connection", "add", "QA-TCP", - "tcp://localhost:8080", + "tcp://localhost:8888", } session := podmanTest.Podman(cmd) session.WaitWithDefaultTimeout() @@ -150,7 +150,7 @@ var _ = Describe("podman system connection", func() { Expect(cfg.Engine.ActiveService).To(Equal("QA-TCP")) Expect(cfg.Engine.ServiceDestinations["QA-TCP"]).To(Equal( config.Destination{ - URI: "tcp://localhost:8080", + URI: "tcp://localhost:8888", Identity: "", }, )) diff --git a/test/e2e/top_test.go b/test/e2e/top_test.go index 3cf6244b6..93c4f3f12 100644 --- a/test/e2e/top_test.go +++ b/test/e2e/top_test.go @@ -73,6 +73,12 @@ var _ = Describe("Podman top", func() { result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1)) + + // Just a smoke test since groups may change over time. + result = podmanTest.Podman([]string{"container", "top", "test", "groups", "hgroups"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1)) }) It("podman top with options", func() { diff --git a/test/system/001-basic.bats b/test/system/001-basic.bats index 888c075b8..2e5ebe4a3 100644 --- a/test/system/001-basic.bats +++ b/test/system/001-basic.bats @@ -101,7 +101,9 @@ function setup() { fi run_podman 125 --remote - is "$output" "Error: missing command 'podman COMMAND'" "podman remote show usage message without running endpoint" + is "$output" "Error: missing command 'podman COMMAND' +Try 'podman --help' for more information." \ + "podman --remote show usage message without running endpoint" } # This is for development only; it's intended to make sure our timeout diff --git a/test/system/005-info.bats b/test/system/005-info.bats index 0ea0f8356..045045fa6 100644 --- a/test/system/005-info.bats +++ b/test/system/005-info.bats @@ -37,7 +37,7 @@ cgroupVersion: v[12] # FIXME: if we're ever able to get package versions on Debian, # add '-[0-9]' to all '*.package' queries below. tests=" -host.buildahVersion | [0-9.] +host.buildahVersion | [1-9][0-9]*\.[0-9.]\\\+.* host.conmon.path | $expr_path host.conmon.package | .*conmon.* host.cgroupManager | \\\(systemd\\\|cgroupfs\\\) diff --git a/test/system/010-images.bats b/test/system/010-images.bats index 649987dfd..1e9d5f181 100644 --- a/test/system/010-images.bats +++ b/test/system/010-images.bats @@ -19,8 +19,8 @@ load helpers @test "podman images - custom formats" { tests=" -{{.ID}} | [0-9a-f]\\\{12\\\} -{{.ID| upper}} | [0-9A-F]\\\{12\\\} +{{.ID}} | [0-9a-f]\\\{12\\\}\\\$ +{{.ID| upper}} | [0-9A-F]\\\{12\\\}\\\$ {{.Repository}}:{{.Tag}} | $PODMAN_TEST_IMAGE_FQN {{.Labels.created_by}} | test/system/build-testimage {{.Labels.created_at}} | 20[0-9-]\\\+T[0-9:]\\\+Z @@ -28,7 +28,7 @@ load helpers parse_table "$tests" | while read fmt expect; do run_podman images --format "$fmt" - is "$output" "$expect\$" "podman images $fmt" + is "$output" "$expect" "podman images --format '$fmt'" done run_podman images --format "{{.ID}}" --no-trunc diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 3d9d834b3..4080f08b4 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -517,7 +517,8 @@ json-file | f cid="$output" run_podman inspect --format "{{.ImageName}}" $cid - is "$output" "$newtag" "container .ImageName is the container-create name" + is "$output" "$newtag:latest" \ + "container .ImageName is the container-create name" # Same thing, but now with a :tag, and making sure it works with --name newtag2="${newtag}:$(random_string 6|tr A-Z a-z)" @@ -526,7 +527,8 @@ json-file | f cname="$(random_string 14|tr A-Z a-z)" run_podman create --name $cname $newtag2 run_podman inspect --format "{{.ImageName}}" $cname - is "$output" "$newtag2" "container .ImageName is the container-create name" + is "$output" "$newtag2" \ + "container .ImageName is the container-create name, with :tag" # Clean up. run_podman rm $cid $cname @@ -718,7 +720,7 @@ EOF run_podman 125 run --device-cgroup-rule="b 7:2" --rm $IMAGE is "$output" 'Error: invalid device cgroup rule requires type, major:Minor, and access rules: "b 7:2"' run_podman 125 run --device-cgroup-rule="x 7:* rmw" --rm $IMAGE - is "$output" "Error: invalid device type in device-access-add:" + is "$output" "Error: invalid device type in device-access-add: x" run_podman 125 run --device-cgroup-rule="a a:* rmw" --rm $IMAGE is "$output" "Error: strconv.ParseInt: parsing \"a\": invalid syntax" } 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/075-exec.bats b/test/system/075-exec.bats index b7367d153..de767a1e8 100644 --- a/test/system/075-exec.bats +++ b/test/system/075-exec.bats @@ -77,7 +77,7 @@ load helpers is "${lines[1]}" "3000+0 records out" "dd: number of records out" # Verify sha. '% *' strips off the path, keeping only the SHA run_podman exec $cid sha512sum /tmp/bigfile - is "${output% *}" "$expect" "SHA of file in container" + is "${output% *}" "$expect " "SHA of file in container" # Clean up run_podman exec $cid touch /stop 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 97ea0f528..e9959271f 100644 --- a/test/system/120-load.bats +++ b/test/system/120-load.bats @@ -11,7 +11,7 @@ load helpers # initialize, read image ID and name get_iid_and_name() { run_podman images -a --format '{{.ID}} {{.Repository}}:{{.Tag}}' - read iid img_name < <(echo "$output") + read iid img_name <<<"$output" archive=$PODMAN_TMPDIR/myimage-$(random_string 8).tar } @@ -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" } @@ -62,7 +62,7 @@ verify_iid_and_name() { # FIXME: cannot compare IID, see #7371, so we check only the tag run_podman images $fqin --format '{{.Repository}}:{{.Tag}}' - is "$output" "$fqin" "image preserves name across save/load" + is "${lines[0]}" "$fqin" "image preserves name across save/load" # Load with a new tag local new_name=x1$(random_string 14 | tr A-Z a-z) @@ -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" } @@ -183,4 +183,16 @@ verify_iid_and_name() { run_podman rmi -f $img1 $img2 } +@test "podman save --oci-accept-uncompressed-layers" { + archive=$PODMAN_TMPDIR/myimage-$(random_string 8).tar + untar=$PODMAN_TMPDIR/myuntar-$(random_string 8) + mkdir -p $untar + + # Create a tarball, unpack it and make sure the layers are uncompressed. + run_podman save -o $archive --format oci-archive --uncompressed $IMAGE + run tar -C $untar -xvf $archive + run file $untar/blobs/sha256/* + is "$output" ".*POSIX tar archive" "layers are uncompressed" +} + # vim: filetype=sh diff --git a/test/system/125-import.bats b/test/system/125-import.bats index 5995d71bf..5b8d84a2f 100644 --- a/test/system/125-import.bats +++ b/test/system/125-import.bats @@ -20,26 +20,26 @@ load helpers # Simple import run_podman import -q $archive iid="$output" - run_podman run -t --rm $iid cat /random.txt + run_podman run --rm $iid cat /random.txt is "$output" "$random_content" "simple import" run_podman rmi -f $iid # Simple import via stdin run_podman import -q - < <(cat $archive) iid="$output" - run_podman run -t --rm $iid cat /random.txt + run_podman run --rm $iid cat /random.txt is "$output" "$random_content" "simple import via stdin" run_podman rmi -f $iid # Tagged import run_podman import -q $archive $fqin - run_podman run -t --rm $fqin cat /random.txt + run_podman run --rm $fqin cat /random.txt is "$output" "$random_content" "tagged import" run_podman rmi -f $fqin # Tagged import via stdin run_podman import -q - $fqin < <(cat $archive) - run_podman run -t --rm $fqin cat /random.txt + run_podman run --rm $fqin cat /random.txt is "$output" "$random_content" "tagged import via stdin" run_podman rmi -f $fqin } @@ -100,7 +100,7 @@ EOF # Confirm exit within timeout run_podman ps -a --filter name=$a_cnt --format '{{.Status}}' - is "$output" "Exited (33)" "Exit by non-TERM/KILL" + is "$output" "Exited (33) .*" "Exit by non-TERM/KILL" run_podman rm -f $a_cnt run_podman rmi $b_img $a_img diff --git a/test/system/150-login.bats b/test/system/150-login.bats index ed925044c..c003a0409 100644 --- a/test/system/150-login.bats +++ b/test/system/150-login.bats @@ -245,7 +245,7 @@ function _test_skopeo_credential_sharing() { is "$status" "0" "skopeo inspect - exit status" got_name=$(jq -r .Name <<<"$output") - is "$got_name" "$registry/$dest_name" "skopeo inspect -> Name" + is "$got_name" "$registry/$destname" "skopeo inspect -> Name" # Now try without a valid login; it should fail run_podman logout "$@" $registry diff --git a/test/system/160-volumes.bats b/test/system/160-volumes.bats index e21be9ea4..c02525e0d 100644 --- a/test/system/160-volumes.bats +++ b/test/system/160-volumes.bats @@ -191,7 +191,7 @@ EOF run_podman run --rm -v my_vol:/data $IMAGE sh -c "echo hello >> /data/test" run_podman volume create my_vol2 - tarfile=hello$(random_string | tr A-Z a-z).tar + tarfile=${PODMAN_TMPDIR}/hello$(random_string | tr A-Z a-z).tar run_podman volume export my_vol --output=$tarfile # we want to use `run_podman volume export my_vol` but run_podman is wrapping EOF run_podman volume import my_vol2 - < $tarfile @@ -261,7 +261,8 @@ EOF # prune should remove v4 run_podman volume prune --force - is "$output" "${v[4]}" "volume prune, with 1, 2, 3 in use, deletes only 4" + is "$(echo $(sort <<<$output))" "${v[4]} ${v[5]} ${v[6]}" \ + "volume prune, with 1, 2, 3 in use, deletes only 4, 5, 6" # Remove the container using v2 and v3. Prune should now remove those. # The 'echo sort' is to get the output sorted and in one line. diff --git a/test/system/220-healthcheck.bats b/test/system/220-healthcheck.bats index e416629e6..28fe8eb92 100644 --- a/test/system/220-healthcheck.bats +++ b/test/system/220-healthcheck.bats @@ -12,13 +12,13 @@ function _check_health { local testname="$1" local tests="$2" - run_podman inspect --format json healthcheck_c + run_podman inspect --format "{{json .State.Healthcheck}}" healthcheck_c parse_table "$tests" | while read field expect;do # (kludge to deal with parse_table and empty strings) if [ "$expect" = "''" ]; then expect=""; fi - actual=$(jq -r ".[0].State.Healthcheck.$field" <<<"$output") + actual=$(jq -r ".$field" <<<"$output") is "$actual" "$expect" "$testname - .State.Healthcheck.$field" done } @@ -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/260-sdnotify.bats b/test/system/260-sdnotify.bats index 0dae569a8..395e6f94f 100644 --- a/test/system/260-sdnotify.bats +++ b/test/system/260-sdnotify.bats @@ -70,7 +70,7 @@ function _stop_socat() { # Check that MAINPID=xxxxx points to a running conmon process function _assert_mainpid_is_conmon() { - local mainpid=$(expr "$1" : "MAINPID=\([0-9]\+\)") + local mainpid=$(expr "$1" : ".*MAINPID=\([0-9]\+\)") test -n "$mainpid" || die "Could not parse '$1' as 'MAINPID=nnnn'" test -d /proc/$mainpid || die "sdnotify MAINPID=$mainpid - but /proc/$mainpid does not exist" @@ -121,7 +121,7 @@ function _assert_mainpid_is_conmon() { # we look for READY=1 _anywhere_ in the output, not just the last line. is "$output" ".*READY=1.*" "sdnotify sent READY=1" - _assert_mainpid_is_conmon "${lines[0]}" + _assert_mainpid_is_conmon "$output" # Done. Stop container, clean up. run_podman exec $cid touch /stop @@ -163,7 +163,7 @@ function _assert_mainpid_is_conmon() { is "$output" ".*READY=1" "received READY=1 through notify socket" - _assert_mainpid_is_conmon "${lines[0]}" + _assert_mainpid_is_conmon "$output" # Done. Stop container, clean up. run_podman exec $cid touch /stop 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..7f2b81835 100644 --- a/test/system/330-corrupt-images.bats +++ b/test/system/330-corrupt-images.bats @@ -74,11 +74,11 @@ function _corrupt_image_test() { # Corruptify, and confirm that 'podman images' throws an error rm -v ${PODMAN_CORRUPT_TEST_WORKDIR}/root/*-images/$id/${rm_path} run_podman 125 images - is "$output" "Error: error retrieving label for image \"$id\": you may need to remove the image to resolve the error" + is "$output" "Error: error retrieving label for image \"$id\": you may need to remove the image to resolve the error.*" # 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/410-selinux.bats b/test/system/410-selinux.bats index 5ee0e0715..7f7f23000 100644 --- a/test/system/410-selinux.bats +++ b/test/system/410-selinux.bats @@ -29,7 +29,7 @@ function check_label() { if [ -n "$2" ]; then # e.g. from the above example -> "s0:c45,c745" range=$(cut -d: -f4,5 <<<"$context") - is "$range" "$2" "SELinux range" + is "$range" "$2^@" "SELinux range" fi } @@ -101,7 +101,7 @@ function check_label() { --security-opt label=level:s0 \ $IMAGE sh -c 'while test ! -e /stop; do sleep 0.1; done' run_podman inspect --format='{{ .HostConfig.SecurityOpt }}' myc - is "$output" "\[label=type:spc_t,label=level:s0 seccomp=unconfined]" \ + is "$output" "[label=type:spc_t,label=level:s0 seccomp=unconfined]" \ "'podman inspect' preserves all --security-opts" run_podman exec myc touch /stop @@ -113,6 +113,14 @@ function check_label() { @test "podman selinux: shared context in (some) namespaces" { skip_if_no_selinux + # rootless users have no usable cgroups with cgroupsv1, so containers + # must use a pid namespace and not join an existing one. + skip_if_rootless_cgroupsv1 + + if [[ $(podman_runtime) == "runc" ]]; then + skip "some sort of runc bug, not worth fixing (#11784)" + fi + run_podman run -d --name myctr $IMAGE top run_podman exec myctr cat -v /proc/self/attr/current context_c1="$output" @@ -221,24 +229,25 @@ function check_label() { run_podman run -v $tmpdir:/test $IMAGE cat /proc/self/attr/current run ls -dZ ${tmpdir} - is "$output" ${LABEL} "No Relabel Correctly" + is "$output" "${LABEL} ${tmpdir}" "No Relabel Correctly" run_podman run -v $tmpdir:/test:z --security-opt label=disable $IMAGE cat /proc/self/attr/current run ls -dZ $tmpdir - is "$output" ${RELABEL} "Privileged Relabel Correctly" + is "$output" "${RELABEL} $tmpdir" "Privileged Relabel Correctly" run_podman run -v $tmpdir:/test:z --privileged $IMAGE cat /proc/self/attr/current run ls -dZ $tmpdir - is "$output" ${RELABEL} "Privileged Relabel Correctly" + is "$output" "${RELABEL} $tmpdir" "Privileged Relabel Correctly" run_podman run -v $tmpdir:/test:Z $IMAGE cat /proc/self/attr/current level=$(secon -l $output) run ls -dZ $tmpdir - is "$output" "system_u:object_r:container_file_t:$level" "Confined Relabel Correctly" + is "$output" "system_u:object_r:container_file_t:$level $tmpdir" \ + "Confined Relabel Correctly" run_podman run -v $tmpdir:/test:z $IMAGE cat /proc/self/attr/current run ls -dZ $tmpdir - is "$output" ${RELABEL} "Shared Relabel Correctly" + is "$output" "${RELABEL} $tmpdir" "Shared Relabel Correctly" } # vim: filetype=sh diff --git a/test/system/420-cgroups.bats b/test/system/420-cgroups.bats index 89c81a742..025a20012 100644 --- a/test/system/420-cgroups.bats +++ b/test/system/420-cgroups.bats @@ -8,9 +8,7 @@ load helpers @test "podman run, preserves initial --cgroup-manager" { skip_if_remote "podman-remote does not support --cgroup-manager" - if is_rootless && is_cgroupsv1; then - skip "not supported as rootless under cgroups v1" - fi + skip_if_rootless_cgroupsv1 # Find out our default cgroup manager, and from that, get the non-default run_podman info --format '{{.Host.CgroupManager}}' diff --git a/test/system/450-interactive.bats b/test/system/450-interactive.bats index 47bdff9ab..55c2afcd4 100644 --- a/test/system/450-interactive.bats +++ b/test/system/450-interactive.bats @@ -55,9 +55,11 @@ function teardown() { cols=$(( 15 + RANDOM % 60 & 126 )) stty rows $rows cols $cols <$PODMAN_TEST_PTY + CR=$'\r' + # ...and make sure stty under podman reads that. run_podman run -it --name mystty $IMAGE stty size <$PODMAN_TEST_PTY - is "$output" "$rows $cols" "stty under podman run reads the correct dimensions" + is "$output" "$rows $cols$CR" "stty under podman run reads the correct dimensions" run_podman rm -f mystty @@ -75,7 +77,7 @@ function teardown() { @test "podman load - will not read from tty" { run_podman 125 load <$PODMAN_TEST_PTY is "$output" \ - "Error: cannot read from terminal. Use command-line redirection" \ + "Error: cannot read from terminal. Use command-line redirection or the --input flag." \ "Diagnostic from 'podman load' without redirection or -i" } @@ -84,14 +86,15 @@ function teardown() { run_podman run --tty -i --rm $IMAGE echo hello < /dev/null is "$output" ".*The input device is not a TTY.*" "-it _without_ a tty" + CR=$'\r' run_podman run --tty -i --rm $IMAGE echo hello <$PODMAN_TEST_PTY - is "$output" "hello" "-it _with_ a pty" + is "$output" "hello$CR" "-it _with_ a pty" run_podman run --tty=false -i --rm $IMAGE echo hello < /dev/null is "$output" "hello" "-tty=false: no warning" run_podman run --tty -i=false --rm $IMAGE echo hello < /dev/null - is "$output" "hello" "-i=false: no warning" + is "$output" "hello$CR" "-i=false: no warning" } # vim: filetype=sh diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index ef00d0366..29fa309f3 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/600-completion.bats b/test/system/600-completion.bats index fbb0da231..5f4610e9e 100644 --- a/test/system/600-completion.bats +++ b/test/system/600-completion.bats @@ -110,12 +110,10 @@ function check_shell_completion() { is "$output" ".*localhost/$random_image_name:$random_image_tag${nl}" \ "$* $cmd: actual image listed in suggestions" - # check that we complete the image with and without tag after at least one char is typed + # check that we complete the image with tag after at least one char is typed run_completion "$@" $cmd "${extra_args[@]}" "${random_image_name:0:1}" is "$output" ".*$random_image_name:$random_image_tag${nl}" \ "$* $cmd: image name:tag included in suggestions" - is "$output" ".*$random_image_name${nl}" \ - "$* $cmd: image name(w/o tag) included in suggestions" # check that we complete the image id after at least two chars are typed run_completion "$@" $cmd "${extra_args[@]}" "${random_image_id:0:2}" diff --git a/test/system/700-play.bats b/test/system/700-play.bats index 2b05cdd84..f41c50e4c 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -30,7 +30,7 @@ spec: containers: - command: - sleep - - "100" + - \"100\" env: - name: PATH value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin @@ -49,7 +49,7 @@ spec: capabilities: {} privileged: false seLinuxOptions: - level: "s0:c1,c2" + level: \"s0:c1,c2\" readOnlyRootFilesystem: false volumeMounts: - mountPath: /testdir:z @@ -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" + is "$output" "${RELABEL} $TESTDIR" "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 } @@ -84,8 +88,11 @@ RELABEL="system_u:object_r:container_file_t:s0" 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" + is "$output" "${RELABEL} $TESTDIR" "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/test/system/helpers.bash b/test/system/helpers.bash index 28ea924bb..03e1ab82b 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -428,6 +428,18 @@ function skip_if_cgroupsv1() { fi } +###################### +# skip_if_rootless_cgroupsv1 # ...with an optional message +###################### +function skip_if_rootless_cgroupsv1() { + if is_rootless; then + if ! is_cgroupsv2; then + local msg=$(_add_label_if_missing "$1" "rootless cgroupvs1") + skip "${msg:-not supported as rootless under cgroupsv1}" + fi + fi +} + ################################## # skip_if_journald_unavailable # rhbz#1895105: rootless journald permissions ################################## @@ -466,13 +478,30 @@ function is() { local expect="$2" local testname="${3:-${MOST_RECENT_PODMAN_COMMAND:-[no test name given]}}" + local is_expr= if [ -z "$expect" ]; then if [ -z "$actual" ]; then + # Both strings are empty. return fi expect='[no output]' - elif expr "$actual" : "$expect" >/dev/null; then + elif [[ "$actual" = "$expect" ]]; then + # Strings are identical. return + else + # Strings are not identical. Are there wild cards in our expect string? + if expr "$expect" : ".*[^\\][\*\[]" >/dev/null; then + # There is a '[' or '*' without a preceding backslash. + is_expr=' (using expr)' + elif [[ "${expect:0:1}" = '[' ]]; then + # String starts with '[', e.g. checking seconds like '[345]' + is_expr=' (using expr)' + fi + if [[ -n "$is_expr" ]]; then + if expr "$actual" : "$expect" >/dev/null; then + return + fi + fi fi # This is a multi-line message, which may in turn contain multi-line @@ -481,7 +510,7 @@ function is() { readarray -t actual_split <<<"$actual" printf "#/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n" >&2 printf "#| FAIL: $testname\n" >&2 - printf "#| expected: '%s'\n" "$expect" >&2 + printf "#| expected: '%s'%s\n" "$expect" "$is_expr" >&2 printf "#| actual: '%s'\n" "${actual_split[0]}" >&2 local line for line in "${actual_split[@]:1}"; do diff --git a/test/testvol/main.go b/test/testvol/main.go index 721f47bcd..a0f58348b 100644 --- a/test/testvol/main.go +++ b/test/testvol/main.go @@ -59,7 +59,7 @@ func before(cmd *cobra.Command, args []string) error { func main() { if err := rootCmd.Execute(); err != nil { - logrus.Errorf("Error running volume plugin: %v", err) + logrus.Errorf("Running volume plugin: %v", err) os.Exit(1) } diff --git a/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata.go b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata.go index 1c74903ad..7c59ed23f 100644 --- a/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata.go +++ b/vendor/github.com/checkpoint-restore/checkpointctl/lib/metadata.go @@ -6,12 +6,10 @@ import ( "encoding/json" "fmt" "io/ioutil" - "net" "os" "path/filepath" "time" - cnitypes "github.com/containernetworking/cni/pkg/types/current" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) @@ -91,16 +89,73 @@ type CheckpointedPodOptions struct { ProcessLabel string `json:"processLabel"` } -func DetectCheckpointArchiveType(checkpointDirectory string) (CheckpointType, error) { - _, err := os.Stat(filepath.Join(checkpointDirectory, CheckpointedPodsFile)) +// This is metadata stored inside of Pod checkpoint archive +type PodSandboxConfig struct { + Metadata SandboxMetadta `json:"metadata"` + Hostname string `json:"hostname"` +} + +type SandboxMetadta struct { + Name string `json:"name"` + UID string `json:"uid"` + Namespace string `json:"namespace"` +} + +func checkForFile(checkpointDirectory, file string) (bool, error) { + _, err := os.Stat(filepath.Join(checkpointDirectory, file)) if err != nil && !os.IsNotExist(err) { - return Unknown, errors.Wrapf(err, "Failed to access %q\n", CheckpointedPodsFile) + return false, errors.Wrapf(err, "Failed to access %q\n", file) + } + if os.IsNotExist(err) { + return false, nil + } + + return true, nil +} + +func DetectCheckpointArchiveType(checkpointDirectory string) (CheckpointType, error) { + kubelet, err := checkForFile(checkpointDirectory, CheckpointedPodsFile) + if os.IsNotExist(err) { + return Unknown, err + } + + container, err := checkForFile(checkpointDirectory, ConfigDumpFile) + if os.IsNotExist(err) { + return Unknown, err } + + pod, err := checkForFile(checkpointDirectory, PodDumpFile) if os.IsNotExist(err) { + return Unknown, err + } + + if pod && !container && !kubelet { + return Pod, nil + } + + if !pod && container && !kubelet { return Container, nil } - return Kubelet, nil + if !pod && !container && kubelet { + return Kubelet, nil + } + + return Unknown, nil +} + +func ReadPodCheckpointDumpFile(checkpointDirectory string) (*PodSandboxConfig, string, error) { + var podSandboxConfig PodSandboxConfig + podDumpFile, err := ReadJSONFile(&podSandboxConfig, checkpointDirectory, PodDumpFile) + + return &podSandboxConfig, podDumpFile, err +} + +func ReadPodCheckpointOptionsFile(checkpointDirectory string) (*CheckpointedPodOptions, string, error) { + var checkpointedPodOptions CheckpointedPodOptions + podOptionsFile, err := ReadJSONFile(&checkpointedPodOptions, checkpointDirectory, PodOptionsFile) + + return &checkpointedPodOptions, podOptionsFile, err } func ReadContainerCheckpointSpecDump(checkpointDirectory string) (*spec.Spec, string, error) { @@ -124,13 +179,6 @@ func ReadContainerCheckpointDeletedFiles(checkpointDirectory string) ([]string, return deletedFiles, deletedFilesFile, err } -func ReadContainerCheckpointNetworkStatus(checkpointDirectory string) ([]*cnitypes.Result, string, error) { - var networkStatus []*cnitypes.Result - networkStatusFile, err := ReadJSONFile(&networkStatus, checkpointDirectory, NetworkStatusFile) - - return networkStatus, networkStatusFile, err -} - func ReadKubeletCheckpoints(checkpointsDirectory string) (*CheckpointMetadata, string, error) { var checkpointMetadata CheckpointMetadata checkpointMetadataPath, err := ReadJSONFile(&checkpointMetadata, checkpointsDirectory, CheckpointedPodsFile) @@ -138,40 +186,6 @@ func ReadKubeletCheckpoints(checkpointsDirectory string) (*CheckpointMetadata, s return &checkpointMetadata, checkpointMetadataPath, err } -func GetIPFromNetworkStatus(networkStatus []*cnitypes.Result) net.IP { - if len(networkStatus) == 0 { - return nil - } - // Take the first IP address - if len(networkStatus[0].IPs) == 0 { - return nil - } - IP := networkStatus[0].IPs[0].Address.IP - - return IP -} - -func GetMACFromNetworkStatus(networkStatus []*cnitypes.Result) net.HardwareAddr { - if len(networkStatus) == 0 { - return nil - } - // Take the first device with a defined sandbox - if len(networkStatus[0].Interfaces) == 0 { - return nil - } - var MAC net.HardwareAddr - MAC = nil - for _, n := range networkStatus[0].Interfaces { - if n.Sandbox != "" { - MAC, _ = net.ParseMAC(n.Mac) - - break - } - } - - return MAC -} - // WriteJSONFile marshalls and writes the given data to a JSON file func WriteJSONFile(v interface{}, dir, file string) (string, error) { fileJSON, err := json.MarshalIndent(v, "", " ") diff --git a/vendor/github.com/containernetworking/cni/libcni/api.go b/vendor/github.com/containernetworking/cni/libcni/api.go index 7e52bd838..0d82a2dd3 100644 --- a/vendor/github.com/containernetworking/cni/libcni/api.go +++ b/vendor/github.com/containernetworking/cni/libcni/api.go @@ -14,6 +14,12 @@ package libcni +// Note this is the actual implementation of the CNI specification, which +// is reflected in the https://github.com/containernetworking/cni/blob/master/SPEC.md file +// it is typically bundled into runtime providers (i.e. containerd or cri-o would use this +// before calling runc or hcsshim). It is also bundled into CNI providers as well, for example, +// to add an IP to a container, to parse the configuration of the CNI and so on. + import ( "context" "encoding/json" @@ -25,6 +31,7 @@ import ( "github.com/containernetworking/cni/pkg/invoke" "github.com/containernetworking/cni/pkg/types" + "github.com/containernetworking/cni/pkg/types/create" "github.com/containernetworking/cni/pkg/utils" "github.com/containernetworking/cni/pkg/version" ) @@ -278,7 +285,7 @@ func (c *CNIConfig) getCachedConfig(netName string, rt *RuntimeConf) ([]byte, *R unmarshaled := cachedInfo{} if err := json.Unmarshal(bytes, &unmarshaled); err != nil { - return nil, nil, fmt.Errorf("failed to unmarshal cached network %q config: %v", netName, err) + return nil, nil, fmt.Errorf("failed to unmarshal cached network %q config: %w", netName, err) } if unmarshaled.Kind != CNICacheV1 { return nil, nil, fmt.Errorf("read cached network %q config has wrong kind: %v", netName, unmarshaled.Kind) @@ -304,15 +311,8 @@ func (c *CNIConfig) getLegacyCachedResult(netName, cniVersion string, rt *Runtim return nil, nil } - // Read the version of the cached result - decoder := version.ConfigDecoder{} - resultCniVersion, err := decoder.Decode(data) - if err != nil { - return nil, err - } - - // Ensure we can understand the result - result, err := version.NewResult(resultCniVersion, data) + // Load the cached result + result, err := create.CreateFromBytes(data) if err != nil { return nil, err } @@ -322,10 +322,10 @@ func (c *CNIConfig) getLegacyCachedResult(netName, cniVersion string, rt *Runtim // should match the config version unless the config was changed // while the container was running. result, err = result.GetAsVersion(cniVersion) - if err != nil && resultCniVersion != cniVersion { - return nil, fmt.Errorf("failed to convert cached result version %q to config version %q: %v", resultCniVersion, cniVersion, err) + if err != nil { + return nil, fmt.Errorf("failed to convert cached result to config version %q: %w", cniVersion, err) } - return result, err + return result, nil } func (c *CNIConfig) getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) { @@ -346,18 +346,11 @@ func (c *CNIConfig) getCachedResult(netName, cniVersion string, rt *RuntimeConf) newBytes, err := json.Marshal(&cachedInfo.RawResult) if err != nil { - return nil, fmt.Errorf("failed to marshal cached network %q config: %v", netName, err) + return nil, fmt.Errorf("failed to marshal cached network %q config: %w", netName, err) } - // Read the version of the cached result - decoder := version.ConfigDecoder{} - resultCniVersion, err := decoder.Decode(newBytes) - if err != nil { - return nil, err - } - - // Ensure we can understand the result - result, err := version.NewResult(resultCniVersion, newBytes) + // Load the cached result + result, err := create.CreateFromBytes(newBytes) if err != nil { return nil, err } @@ -367,10 +360,10 @@ func (c *CNIConfig) getCachedResult(netName, cniVersion string, rt *RuntimeConf) // should match the config version unless the config was changed // while the container was running. result, err = result.GetAsVersion(cniVersion) - if err != nil && resultCniVersion != cniVersion { - return nil, fmt.Errorf("failed to convert cached result version %q to config version %q: %v", resultCniVersion, cniVersion, err) + if err != nil { + return nil, fmt.Errorf("failed to convert cached result to config version %q: %w", cniVersion, err) } - return result, err + return result, nil } // GetNetworkListCachedResult returns the cached Result of the previous @@ -428,12 +421,12 @@ func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList, for _, net := range list.Plugins { result, err = c.addNetwork(ctx, list.Name, list.CNIVersion, net, result, rt) if err != nil { - return nil, err + return nil, fmt.Errorf("plugin %s failed (add): %w", pluginDescription(net.Network), err) } } if err = c.cacheAdd(result, list.Bytes, list.Name, rt); err != nil { - return nil, fmt.Errorf("failed to set network %q cached result: %v", list.Name, err) + return nil, fmt.Errorf("failed to set network %q cached result: %w", list.Name, err) } return result, nil @@ -469,7 +462,7 @@ func (c *CNIConfig) CheckNetworkList(ctx context.Context, list *NetworkConfigLis cachedResult, err := c.getCachedResult(list.Name, list.CNIVersion, rt) if err != nil { - return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err) + return fmt.Errorf("failed to get network %q cached result: %w", list.Name, err) } for _, net := range list.Plugins { @@ -506,14 +499,14 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList, } else if gtet { cachedResult, err = c.getCachedResult(list.Name, list.CNIVersion, rt) if err != nil { - return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err) + return fmt.Errorf("failed to get network %q cached result: %w", list.Name, err) } } for i := len(list.Plugins) - 1; i >= 0; i-- { net := list.Plugins[i] if err := c.delNetwork(ctx, list.Name, list.CNIVersion, net, cachedResult, rt); err != nil { - return err + return fmt.Errorf("plugin %s failed (delete): %w", pluginDescription(net.Network), err) } } _ = c.cacheDel(list.Name, rt) @@ -521,6 +514,19 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList, return nil } +func pluginDescription(net *types.NetConf) string { + if net == nil { + return "<missing>" + } + pluginType := net.Type + out := fmt.Sprintf("type=%q", pluginType) + name := net.Name + if name != "" { + out += fmt.Sprintf(" name=%q", name) + } + return out +} + // AddNetwork executes the plugin with the ADD command func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error) { result, err := c.addNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, nil, rt) @@ -529,7 +535,7 @@ func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *Runt } if err = c.cacheAdd(result, net.Bytes, net.Network.Name, rt); err != nil { - return nil, fmt.Errorf("failed to set network %q cached result: %v", net.Network.Name, err) + return nil, fmt.Errorf("failed to set network %q cached result: %w", net.Network.Name, err) } return result, nil @@ -546,7 +552,7 @@ func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *Ru cachedResult, err := c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt) if err != nil { - return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err) + return fmt.Errorf("failed to get network %q cached result: %w", net.Network.Name, err) } return c.checkNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt) } @@ -561,7 +567,7 @@ func (c *CNIConfig) DelNetwork(ctx context.Context, net *NetworkConfig, rt *Runt } else if gtet { cachedResult, err = c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt) if err != nil { - return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err) + return fmt.Errorf("failed to get network %q cached result: %w", net.Network.Name, err) } } diff --git a/vendor/github.com/containernetworking/cni/libcni/conf.go b/vendor/github.com/containernetworking/cni/libcni/conf.go index d8920cf8c..d28135ff3 100644 --- a/vendor/github.com/containernetworking/cni/libcni/conf.go +++ b/vendor/github.com/containernetworking/cni/libcni/conf.go @@ -43,7 +43,7 @@ func (e NoConfigsFoundError) Error() string { func ConfFromBytes(bytes []byte) (*NetworkConfig, error) { conf := &NetworkConfig{Bytes: bytes} if err := json.Unmarshal(bytes, &conf.Network); err != nil { - return nil, fmt.Errorf("error parsing configuration: %s", err) + return nil, fmt.Errorf("error parsing configuration: %w", err) } if conf.Network.Type == "" { return nil, fmt.Errorf("error parsing configuration: missing 'type'") @@ -54,7 +54,7 @@ func ConfFromBytes(bytes []byte) (*NetworkConfig, error) { func ConfFromFile(filename string) (*NetworkConfig, error) { bytes, err := ioutil.ReadFile(filename) if err != nil { - return nil, fmt.Errorf("error reading %s: %s", filename, err) + return nil, fmt.Errorf("error reading %s: %w", filename, err) } return ConfFromBytes(bytes) } @@ -62,7 +62,7 @@ func ConfFromFile(filename string) (*NetworkConfig, error) { func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) { rawList := make(map[string]interface{}) if err := json.Unmarshal(bytes, &rawList); err != nil { - return nil, fmt.Errorf("error parsing configuration list: %s", err) + return nil, fmt.Errorf("error parsing configuration list: %w", err) } rawName, ok := rawList["name"] @@ -114,11 +114,11 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) { for i, conf := range plugins { newBytes, err := json.Marshal(conf) if err != nil { - return nil, fmt.Errorf("failed to marshal plugin config %d: %v", i, err) + return nil, fmt.Errorf("failed to marshal plugin config %d: %w", i, err) } netConf, err := ConfFromBytes(newBytes) if err != nil { - return nil, fmt.Errorf("failed to parse plugin config %d: %v", i, err) + return nil, fmt.Errorf("failed to parse plugin config %d: %w", i, err) } list.Plugins = append(list.Plugins, netConf) } @@ -129,7 +129,7 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) { func ConfListFromFile(filename string) (*NetworkConfigList, error) { bytes, err := ioutil.ReadFile(filename) if err != nil { - return nil, fmt.Errorf("error reading %s: %s", filename, err) + return nil, fmt.Errorf("error reading %s: %w", filename, err) } return ConfListFromBytes(bytes) } @@ -218,7 +218,7 @@ func InjectConf(original *NetworkConfig, newValues map[string]interface{}) (*Net config := make(map[string]interface{}) err := json.Unmarshal(original.Bytes, &config) if err != nil { - return nil, fmt.Errorf("unmarshal existing network bytes: %s", err) + return nil, fmt.Errorf("unmarshal existing network bytes: %w", err) } for key, value := range newValues { diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go b/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go index 8e6d30b82..e79bffe63 100644 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go +++ b/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go @@ -20,6 +20,7 @@ import ( "os" "github.com/containernetworking/cni/pkg/types" + "github.com/containernetworking/cni/pkg/types/create" "github.com/containernetworking/cni/pkg/version" ) @@ -83,14 +84,7 @@ func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte return nil, err } - // Plugin must return result in same version as specified in netconf - versionDecoder := &version.ConfigDecoder{} - confVersion, err := versionDecoder.Decode(netconf) - if err != nil { - return nil, err - } - - return version.NewResult(confVersion, stdoutBytes) + return create.CreateFromBytes(stdoutBytes) } func ExecPluginWithoutResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) error { diff --git a/vendor/github.com/containernetworking/cni/pkg/types/020/types.go b/vendor/github.com/containernetworking/cni/pkg/types/020/types.go index 36f31678a..99b151ff2 100644 --- a/vendor/github.com/containernetworking/cni/pkg/types/020/types.go +++ b/vendor/github.com/containernetworking/cni/pkg/types/020/types.go @@ -22,25 +22,47 @@ import ( "os" "github.com/containernetworking/cni/pkg/types" + convert "github.com/containernetworking/cni/pkg/types/internal" ) const ImplementedSpecVersion string = "0.2.0" -var SupportedVersions = []string{"", "0.1.0", ImplementedSpecVersion} +var supportedVersions = []string{"", "0.1.0", ImplementedSpecVersion} + +// Register converters for all versions less than the implemented spec version +func init() { + convert.RegisterConverter("0.1.0", []string{ImplementedSpecVersion}, convertFrom010) + convert.RegisterConverter(ImplementedSpecVersion, []string{"0.1.0"}, convertTo010) + + // Creator + convert.RegisterCreator(supportedVersions, NewResult) +} // Compatibility types for CNI version 0.1.0 and 0.2.0 +// NewResult creates a new Result object from JSON data. The JSON data +// must be compatible with the CNI versions implemented by this type. func NewResult(data []byte) (types.Result, error) { result := &Result{} if err := json.Unmarshal(data, result); err != nil { return nil, err } - return result, nil + for _, v := range supportedVersions { + if result.CNIVersion == v { + if result.CNIVersion == "" { + result.CNIVersion = "0.1.0" + } + return result, nil + } + } + return nil, fmt.Errorf("result type supports %v but unmarshalled CNIVersion is %q", + supportedVersions, result.CNIVersion) } +// GetResult converts the given Result object to the ImplementedSpecVersion +// and returns the concrete type or an error func GetResult(r types.Result) (*Result, error) { - // We expect version 0.1.0/0.2.0 results - result020, err := r.GetAsVersion(ImplementedSpecVersion) + result020, err := convert.Convert(r, ImplementedSpecVersion) if err != nil { return nil, err } @@ -51,6 +73,32 @@ func GetResult(r types.Result) (*Result, error) { return result, nil } +func convertFrom010(from types.Result, toVersion string) (types.Result, error) { + if toVersion != "0.2.0" { + panic("only converts to version 0.2.0") + } + fromResult := from.(*Result) + return &Result{ + CNIVersion: ImplementedSpecVersion, + IP4: fromResult.IP4.Copy(), + IP6: fromResult.IP6.Copy(), + DNS: *fromResult.DNS.Copy(), + }, nil +} + +func convertTo010(from types.Result, toVersion string) (types.Result, error) { + if toVersion != "0.1.0" { + panic("only converts to version 0.1.0") + } + fromResult := from.(*Result) + return &Result{ + CNIVersion: "0.1.0", + IP4: fromResult.IP4.Copy(), + IP6: fromResult.IP6.Copy(), + DNS: *fromResult.DNS.Copy(), + }, nil +} + // Result is what gets returned from the plugin (via stdout) to the caller type Result struct { CNIVersion string `json:"cniVersion,omitempty"` @@ -60,17 +108,16 @@ type Result struct { } func (r *Result) Version() string { - return ImplementedSpecVersion + return r.CNIVersion } func (r *Result) GetAsVersion(version string) (types.Result, error) { - for _, supportedVersion := range SupportedVersions { - if version == supportedVersion { - r.CNIVersion = version - return r, nil - } + // If the creator of the result did not set the CNIVersion, assume it + // should be the highest spec version implemented by this Result + if r.CNIVersion == "" { + r.CNIVersion = ImplementedSpecVersion } - return nil, fmt.Errorf("cannot convert version %q to %s", SupportedVersions, version) + return convert.Convert(r, version) } func (r *Result) Print() error { @@ -93,6 +140,22 @@ type IPConfig struct { Routes []types.Route } +func (i *IPConfig) Copy() *IPConfig { + if i == nil { + return nil + } + + var routes []types.Route + for _, fromRoute := range i.Routes { + routes = append(routes, *fromRoute.Copy()) + } + return &IPConfig{ + IP: i.IP, + Gateway: i.Gateway, + Routes: routes, + } +} + // net.IPNet is not JSON (un)marshallable so this duality is needed // for our custom IPNet type diff --git a/vendor/github.com/containernetworking/cni/pkg/types/040/types.go b/vendor/github.com/containernetworking/cni/pkg/types/040/types.go new file mode 100644 index 000000000..3633b0eaa --- /dev/null +++ b/vendor/github.com/containernetworking/cni/pkg/types/040/types.go @@ -0,0 +1,306 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package types040 + +import ( + "encoding/json" + "fmt" + "io" + "net" + "os" + + "github.com/containernetworking/cni/pkg/types" + types020 "github.com/containernetworking/cni/pkg/types/020" + convert "github.com/containernetworking/cni/pkg/types/internal" +) + +const ImplementedSpecVersion string = "0.4.0" + +var supportedVersions = []string{"0.3.0", "0.3.1", ImplementedSpecVersion} + +// Register converters for all versions less than the implemented spec version +func init() { + // Up-converters + convert.RegisterConverter("0.1.0", supportedVersions, convertFrom02x) + convert.RegisterConverter("0.2.0", supportedVersions, convertFrom02x) + convert.RegisterConverter("0.3.0", supportedVersions, convertInternal) + convert.RegisterConverter("0.3.1", supportedVersions, convertInternal) + + // Down-converters + convert.RegisterConverter("0.4.0", []string{"0.3.0", "0.3.1"}, convertInternal) + convert.RegisterConverter("0.4.0", []string{"0.1.0", "0.2.0"}, convertTo02x) + convert.RegisterConverter("0.3.1", []string{"0.1.0", "0.2.0"}, convertTo02x) + convert.RegisterConverter("0.3.0", []string{"0.1.0", "0.2.0"}, convertTo02x) + + // Creator + convert.RegisterCreator(supportedVersions, NewResult) +} + +func NewResult(data []byte) (types.Result, error) { + result := &Result{} + if err := json.Unmarshal(data, result); err != nil { + return nil, err + } + for _, v := range supportedVersions { + if result.CNIVersion == v { + return result, nil + } + } + return nil, fmt.Errorf("result type supports %v but unmarshalled CNIVersion is %q", + supportedVersions, result.CNIVersion) +} + +func GetResult(r types.Result) (*Result, error) { + resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion) + if err != nil { + return nil, err + } + result, ok := resultCurrent.(*Result) + if !ok { + return nil, fmt.Errorf("failed to convert result") + } + return result, nil +} + +func NewResultFromResult(result types.Result) (*Result, error) { + newResult, err := convert.Convert(result, ImplementedSpecVersion) + if err != nil { + return nil, err + } + return newResult.(*Result), nil +} + +// Result is what gets returned from the plugin (via stdout) to the caller +type Result struct { + CNIVersion string `json:"cniVersion,omitempty"` + Interfaces []*Interface `json:"interfaces,omitempty"` + IPs []*IPConfig `json:"ips,omitempty"` + Routes []*types.Route `json:"routes,omitempty"` + DNS types.DNS `json:"dns,omitempty"` +} + +func convert020IPConfig(from *types020.IPConfig, ipVersion string) *IPConfig { + return &IPConfig{ + Version: ipVersion, + Address: from.IP, + Gateway: from.Gateway, + } +} + +func convertFrom02x(from types.Result, toVersion string) (types.Result, error) { + fromResult := from.(*types020.Result) + toResult := &Result{ + CNIVersion: toVersion, + DNS: *fromResult.DNS.Copy(), + Routes: []*types.Route{}, + } + if fromResult.IP4 != nil { + toResult.IPs = append(toResult.IPs, convert020IPConfig(fromResult.IP4, "4")) + for _, fromRoute := range fromResult.IP4.Routes { + toResult.Routes = append(toResult.Routes, fromRoute.Copy()) + } + } + + if fromResult.IP6 != nil { + toResult.IPs = append(toResult.IPs, convert020IPConfig(fromResult.IP6, "6")) + for _, fromRoute := range fromResult.IP6.Routes { + toResult.Routes = append(toResult.Routes, fromRoute.Copy()) + } + } + + return toResult, nil +} + +func convertInternal(from types.Result, toVersion string) (types.Result, error) { + fromResult := from.(*Result) + toResult := &Result{ + CNIVersion: toVersion, + DNS: *fromResult.DNS.Copy(), + Routes: []*types.Route{}, + } + for _, fromIntf := range fromResult.Interfaces { + toResult.Interfaces = append(toResult.Interfaces, fromIntf.Copy()) + } + for _, fromIPC := range fromResult.IPs { + toResult.IPs = append(toResult.IPs, fromIPC.Copy()) + } + for _, fromRoute := range fromResult.Routes { + toResult.Routes = append(toResult.Routes, fromRoute.Copy()) + } + return toResult, nil +} + +func convertTo02x(from types.Result, toVersion string) (types.Result, error) { + fromResult := from.(*Result) + toResult := &types020.Result{ + CNIVersion: toVersion, + DNS: *fromResult.DNS.Copy(), + } + + for _, fromIP := range fromResult.IPs { + // Only convert the first IP address of each version as 0.2.0 + // and earlier cannot handle multiple IP addresses + if fromIP.Version == "4" && toResult.IP4 == nil { + toResult.IP4 = &types020.IPConfig{ + IP: fromIP.Address, + Gateway: fromIP.Gateway, + } + } else if fromIP.Version == "6" && toResult.IP6 == nil { + toResult.IP6 = &types020.IPConfig{ + IP: fromIP.Address, + Gateway: fromIP.Gateway, + } + } + if toResult.IP4 != nil && toResult.IP6 != nil { + break + } + } + + for _, fromRoute := range fromResult.Routes { + is4 := fromRoute.Dst.IP.To4() != nil + if is4 && toResult.IP4 != nil { + toResult.IP4.Routes = append(toResult.IP4.Routes, types.Route{ + Dst: fromRoute.Dst, + GW: fromRoute.GW, + }) + } else if !is4 && toResult.IP6 != nil { + toResult.IP6.Routes = append(toResult.IP6.Routes, types.Route{ + Dst: fromRoute.Dst, + GW: fromRoute.GW, + }) + } + } + + // 0.2.0 and earlier require at least one IP address in the Result + if toResult.IP4 == nil && toResult.IP6 == nil { + return nil, fmt.Errorf("cannot convert: no valid IP addresses") + } + + return toResult, nil +} + +func (r *Result) Version() string { + return r.CNIVersion +} + +func (r *Result) GetAsVersion(version string) (types.Result, error) { + // If the creator of the result did not set the CNIVersion, assume it + // should be the highest spec version implemented by this Result + if r.CNIVersion == "" { + r.CNIVersion = ImplementedSpecVersion + } + return convert.Convert(r, version) +} + +func (r *Result) Print() error { + return r.PrintTo(os.Stdout) +} + +func (r *Result) PrintTo(writer io.Writer) error { + data, err := json.MarshalIndent(r, "", " ") + if err != nil { + return err + } + _, err = writer.Write(data) + return err +} + +// Interface contains values about the created interfaces +type Interface struct { + Name string `json:"name"` + Mac string `json:"mac,omitempty"` + Sandbox string `json:"sandbox,omitempty"` +} + +func (i *Interface) String() string { + return fmt.Sprintf("%+v", *i) +} + +func (i *Interface) Copy() *Interface { + if i == nil { + return nil + } + newIntf := *i + return &newIntf +} + +// Int returns a pointer to the int value passed in. Used to +// set the IPConfig.Interface field. +func Int(v int) *int { + return &v +} + +// IPConfig contains values necessary to configure an IP address on an interface +type IPConfig struct { + // IP version, either "4" or "6" + Version string + // Index into Result structs Interfaces list + Interface *int + Address net.IPNet + Gateway net.IP +} + +func (i *IPConfig) String() string { + return fmt.Sprintf("%+v", *i) +} + +func (i *IPConfig) Copy() *IPConfig { + if i == nil { + return nil + } + + ipc := &IPConfig{ + Version: i.Version, + Address: i.Address, + Gateway: i.Gateway, + } + if i.Interface != nil { + intf := *i.Interface + ipc.Interface = &intf + } + return ipc +} + +// JSON (un)marshallable types +type ipConfig struct { + Version string `json:"version"` + Interface *int `json:"interface,omitempty"` + Address types.IPNet `json:"address"` + Gateway net.IP `json:"gateway,omitempty"` +} + +func (c *IPConfig) MarshalJSON() ([]byte, error) { + ipc := ipConfig{ + Version: c.Version, + Interface: c.Interface, + Address: types.IPNet(c.Address), + Gateway: c.Gateway, + } + + return json.Marshal(ipc) +} + +func (c *IPConfig) UnmarshalJSON(data []byte) error { + ipc := ipConfig{} + if err := json.Unmarshal(data, &ipc); err != nil { + return err + } + + c.Version = ipc.Version + c.Interface = ipc.Interface + c.Address = net.IPNet(ipc.Address) + c.Gateway = ipc.Gateway + return nil +} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/100/types.go b/vendor/github.com/containernetworking/cni/pkg/types/100/types.go new file mode 100644 index 000000000..0e1e8b857 --- /dev/null +++ b/vendor/github.com/containernetworking/cni/pkg/types/100/types.go @@ -0,0 +1,307 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package types100 + +import ( + "encoding/json" + "fmt" + "io" + "net" + "os" + + "github.com/containernetworking/cni/pkg/types" + types040 "github.com/containernetworking/cni/pkg/types/040" + convert "github.com/containernetworking/cni/pkg/types/internal" +) + +const ImplementedSpecVersion string = "1.0.0" + +var supportedVersions = []string{ImplementedSpecVersion} + +// Register converters for all versions less than the implemented spec version +func init() { + // Up-converters + convert.RegisterConverter("0.1.0", supportedVersions, convertFrom02x) + convert.RegisterConverter("0.2.0", supportedVersions, convertFrom02x) + convert.RegisterConverter("0.3.0", supportedVersions, convertFrom04x) + convert.RegisterConverter("0.3.1", supportedVersions, convertFrom04x) + convert.RegisterConverter("0.4.0", supportedVersions, convertFrom04x) + + // Down-converters + convert.RegisterConverter("1.0.0", []string{"0.3.0", "0.3.1", "0.4.0"}, convertTo04x) + convert.RegisterConverter("1.0.0", []string{"0.1.0", "0.2.0"}, convertTo02x) + + // Creator + convert.RegisterCreator(supportedVersions, NewResult) +} + +func NewResult(data []byte) (types.Result, error) { + result := &Result{} + if err := json.Unmarshal(data, result); err != nil { + return nil, err + } + for _, v := range supportedVersions { + if result.CNIVersion == v { + return result, nil + } + } + return nil, fmt.Errorf("result type supports %v but unmarshalled CNIVersion is %q", + supportedVersions, result.CNIVersion) +} + +func GetResult(r types.Result) (*Result, error) { + resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion) + if err != nil { + return nil, err + } + result, ok := resultCurrent.(*Result) + if !ok { + return nil, fmt.Errorf("failed to convert result") + } + return result, nil +} + +func NewResultFromResult(result types.Result) (*Result, error) { + newResult, err := convert.Convert(result, ImplementedSpecVersion) + if err != nil { + return nil, err + } + return newResult.(*Result), nil +} + +// Result is what gets returned from the plugin (via stdout) to the caller +type Result struct { + CNIVersion string `json:"cniVersion,omitempty"` + Interfaces []*Interface `json:"interfaces,omitempty"` + IPs []*IPConfig `json:"ips,omitempty"` + Routes []*types.Route `json:"routes,omitempty"` + DNS types.DNS `json:"dns,omitempty"` +} + +func convertFrom02x(from types.Result, toVersion string) (types.Result, error) { + result040, err := convert.Convert(from, "0.4.0") + if err != nil { + return nil, err + } + result100, err := convertFrom04x(result040, ImplementedSpecVersion) + if err != nil { + return nil, err + } + return result100, nil +} + +func convertIPConfigFrom040(from *types040.IPConfig) *IPConfig { + to := &IPConfig{ + Address: from.Address, + Gateway: from.Gateway, + } + if from.Interface != nil { + intf := *from.Interface + to.Interface = &intf + } + return to +} + +func convertInterfaceFrom040(from *types040.Interface) *Interface { + return &Interface{ + Name: from.Name, + Mac: from.Mac, + Sandbox: from.Sandbox, + } +} + +func convertFrom04x(from types.Result, toVersion string) (types.Result, error) { + fromResult := from.(*types040.Result) + toResult := &Result{ + CNIVersion: toVersion, + DNS: *fromResult.DNS.Copy(), + Routes: []*types.Route{}, + } + for _, fromIntf := range fromResult.Interfaces { + toResult.Interfaces = append(toResult.Interfaces, convertInterfaceFrom040(fromIntf)) + } + for _, fromIPC := range fromResult.IPs { + toResult.IPs = append(toResult.IPs, convertIPConfigFrom040(fromIPC)) + } + for _, fromRoute := range fromResult.Routes { + toResult.Routes = append(toResult.Routes, fromRoute.Copy()) + } + return toResult, nil +} + +func convertIPConfigTo040(from *IPConfig) *types040.IPConfig { + version := "6" + if from.Address.IP.To4() != nil { + version = "4" + } + to := &types040.IPConfig{ + Version: version, + Address: from.Address, + Gateway: from.Gateway, + } + if from.Interface != nil { + intf := *from.Interface + to.Interface = &intf + } + return to +} + +func convertInterfaceTo040(from *Interface) *types040.Interface { + return &types040.Interface{ + Name: from.Name, + Mac: from.Mac, + Sandbox: from.Sandbox, + } +} + +func convertTo04x(from types.Result, toVersion string) (types.Result, error) { + fromResult := from.(*Result) + toResult := &types040.Result{ + CNIVersion: toVersion, + DNS: *fromResult.DNS.Copy(), + Routes: []*types.Route{}, + } + for _, fromIntf := range fromResult.Interfaces { + toResult.Interfaces = append(toResult.Interfaces, convertInterfaceTo040(fromIntf)) + } + for _, fromIPC := range fromResult.IPs { + toResult.IPs = append(toResult.IPs, convertIPConfigTo040(fromIPC)) + } + for _, fromRoute := range fromResult.Routes { + toResult.Routes = append(toResult.Routes, fromRoute.Copy()) + } + return toResult, nil +} + +func convertTo02x(from types.Result, toVersion string) (types.Result, error) { + // First convert to 0.4.0 + result040, err := convertTo04x(from, "0.4.0") + if err != nil { + return nil, err + } + result02x, err := convert.Convert(result040, toVersion) + if err != nil { + return nil, err + } + return result02x, nil +} + +func (r *Result) Version() string { + return r.CNIVersion +} + +func (r *Result) GetAsVersion(version string) (types.Result, error) { + // If the creator of the result did not set the CNIVersion, assume it + // should be the highest spec version implemented by this Result + if r.CNIVersion == "" { + r.CNIVersion = ImplementedSpecVersion + } + return convert.Convert(r, version) +} + +func (r *Result) Print() error { + return r.PrintTo(os.Stdout) +} + +func (r *Result) PrintTo(writer io.Writer) error { + data, err := json.MarshalIndent(r, "", " ") + if err != nil { + return err + } + _, err = writer.Write(data) + return err +} + +// Interface contains values about the created interfaces +type Interface struct { + Name string `json:"name"` + Mac string `json:"mac,omitempty"` + Sandbox string `json:"sandbox,omitempty"` +} + +func (i *Interface) String() string { + return fmt.Sprintf("%+v", *i) +} + +func (i *Interface) Copy() *Interface { + if i == nil { + return nil + } + newIntf := *i + return &newIntf +} + +// Int returns a pointer to the int value passed in. Used to +// set the IPConfig.Interface field. +func Int(v int) *int { + return &v +} + +// IPConfig contains values necessary to configure an IP address on an interface +type IPConfig struct { + // Index into Result structs Interfaces list + Interface *int + Address net.IPNet + Gateway net.IP +} + +func (i *IPConfig) String() string { + return fmt.Sprintf("%+v", *i) +} + +func (i *IPConfig) Copy() *IPConfig { + if i == nil { + return nil + } + + ipc := &IPConfig{ + Address: i.Address, + Gateway: i.Gateway, + } + if i.Interface != nil { + intf := *i.Interface + ipc.Interface = &intf + } + return ipc +} + +// JSON (un)marshallable types +type ipConfig struct { + Interface *int `json:"interface,omitempty"` + Address types.IPNet `json:"address"` + Gateway net.IP `json:"gateway,omitempty"` +} + +func (c *IPConfig) MarshalJSON() ([]byte, error) { + ipc := ipConfig{ + Interface: c.Interface, + Address: types.IPNet(c.Address), + Gateway: c.Gateway, + } + + return json.Marshal(ipc) +} + +func (c *IPConfig) UnmarshalJSON(data []byte) error { + ipc := ipConfig{} + if err := json.Unmarshal(data, &ipc); err != nil { + return err + } + + c.Interface = ipc.Interface + c.Address = net.IPNet(ipc.Address) + c.Gateway = ipc.Gateway + return nil +} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/args.go b/vendor/github.com/containernetworking/cni/pkg/types/args.go index 4eac64899..7516f03ef 100644 --- a/vendor/github.com/containernetworking/cni/pkg/types/args.go +++ b/vendor/github.com/containernetworking/cni/pkg/types/args.go @@ -91,16 +91,26 @@ func LoadArgs(args string, container interface{}) error { unknownArgs = append(unknownArgs, pair) continue } - keyFieldIface := keyField.Addr().Interface() - u, ok := keyFieldIface.(encoding.TextUnmarshaler) + + var keyFieldInterface interface{} + switch { + case keyField.Kind() == reflect.Ptr: + keyField.Set(reflect.New(keyField.Type().Elem())) + keyFieldInterface = keyField.Interface() + case keyField.CanAddr() && keyField.Addr().CanInterface(): + keyFieldInterface = keyField.Addr().Interface() + default: + return UnmarshalableArgsError{fmt.Errorf("field '%s' has no valid interface", keyString)} + } + u, ok := keyFieldInterface.(encoding.TextUnmarshaler) if !ok { return UnmarshalableArgsError{fmt.Errorf( "ARGS: cannot unmarshal into field '%s' - type '%s' does not implement encoding.TextUnmarshaler", - keyString, reflect.TypeOf(keyFieldIface))} + keyString, reflect.TypeOf(keyFieldInterface))} } err := u.UnmarshalText([]byte(valueString)) if err != nil { - return fmt.Errorf("ARGS: error parsing value of pair %q: %v)", pair, err) + return fmt.Errorf("ARGS: error parsing value of pair %q: %w", pair, err) } } diff --git a/vendor/github.com/containernetworking/cni/pkg/types/create/create.go b/vendor/github.com/containernetworking/cni/pkg/types/create/create.go new file mode 100644 index 000000000..ed28b33e8 --- /dev/null +++ b/vendor/github.com/containernetworking/cni/pkg/types/create/create.go @@ -0,0 +1,56 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package create + +import ( + "encoding/json" + "fmt" + + "github.com/containernetworking/cni/pkg/types" + convert "github.com/containernetworking/cni/pkg/types/internal" +) + +// DecodeVersion returns the CNI version from CNI configuration or result JSON, +// or an error if the operation could not be performed. +func DecodeVersion(jsonBytes []byte) (string, error) { + var conf struct { + CNIVersion string `json:"cniVersion"` + } + err := json.Unmarshal(jsonBytes, &conf) + if err != nil { + return "", fmt.Errorf("decoding version from network config: %w", err) + } + if conf.CNIVersion == "" { + return "0.1.0", nil + } + return conf.CNIVersion, nil +} + +// Create creates a CNI Result using the given JSON with the expected +// version, or an error if the creation could not be performed +func Create(version string, bytes []byte) (types.Result, error) { + return convert.Create(version, bytes) +} + +// CreateFromBytes creates a CNI Result from the given JSON, automatically +// detecting the CNI spec version of the result. An error is returned if the +// operation could not be performed. +func CreateFromBytes(bytes []byte) (types.Result, error) { + version, err := DecodeVersion(bytes) + if err != nil { + return nil, err + } + return convert.Create(version, bytes) +} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/current/types.go b/vendor/github.com/containernetworking/cni/pkg/types/current/types.go deleted file mode 100644 index 754cc6e72..000000000 --- a/vendor/github.com/containernetworking/cni/pkg/types/current/types.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package current - -import ( - "encoding/json" - "fmt" - "io" - "net" - "os" - - "github.com/containernetworking/cni/pkg/types" - "github.com/containernetworking/cni/pkg/types/020" -) - -const ImplementedSpecVersion string = "0.4.0" - -var SupportedVersions = []string{"0.3.0", "0.3.1", ImplementedSpecVersion} - -func NewResult(data []byte) (types.Result, error) { - result := &Result{} - if err := json.Unmarshal(data, result); err != nil { - return nil, err - } - return result, nil -} - -func GetResult(r types.Result) (*Result, error) { - resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion) - if err != nil { - return nil, err - } - result, ok := resultCurrent.(*Result) - if !ok { - return nil, fmt.Errorf("failed to convert result") - } - return result, nil -} - -var resultConverters = []struct { - versions []string - convert func(types.Result) (*Result, error) -}{ - {types020.SupportedVersions, convertFrom020}, - {SupportedVersions, convertFrom030}, -} - -func convertFrom020(result types.Result) (*Result, error) { - oldResult, err := types020.GetResult(result) - if err != nil { - return nil, err - } - - newResult := &Result{ - CNIVersion: ImplementedSpecVersion, - DNS: oldResult.DNS, - Routes: []*types.Route{}, - } - - if oldResult.IP4 != nil { - newResult.IPs = append(newResult.IPs, &IPConfig{ - Version: "4", - Address: oldResult.IP4.IP, - Gateway: oldResult.IP4.Gateway, - }) - for _, route := range oldResult.IP4.Routes { - newResult.Routes = append(newResult.Routes, &types.Route{ - Dst: route.Dst, - GW: route.GW, - }) - } - } - - if oldResult.IP6 != nil { - newResult.IPs = append(newResult.IPs, &IPConfig{ - Version: "6", - Address: oldResult.IP6.IP, - Gateway: oldResult.IP6.Gateway, - }) - for _, route := range oldResult.IP6.Routes { - newResult.Routes = append(newResult.Routes, &types.Route{ - Dst: route.Dst, - GW: route.GW, - }) - } - } - - return newResult, nil -} - -func convertFrom030(result types.Result) (*Result, error) { - newResult, ok := result.(*Result) - if !ok { - return nil, fmt.Errorf("failed to convert result") - } - newResult.CNIVersion = ImplementedSpecVersion - return newResult, nil -} - -func NewResultFromResult(result types.Result) (*Result, error) { - version := result.Version() - for _, converter := range resultConverters { - for _, supportedVersion := range converter.versions { - if version == supportedVersion { - return converter.convert(result) - } - } - } - return nil, fmt.Errorf("unsupported CNI result22 version %q", version) -} - -// Result is what gets returned from the plugin (via stdout) to the caller -type Result struct { - CNIVersion string `json:"cniVersion,omitempty"` - Interfaces []*Interface `json:"interfaces,omitempty"` - IPs []*IPConfig `json:"ips,omitempty"` - Routes []*types.Route `json:"routes,omitempty"` - DNS types.DNS `json:"dns,omitempty"` -} - -// Convert to the older 0.2.0 CNI spec Result type -func (r *Result) convertTo020() (*types020.Result, error) { - oldResult := &types020.Result{ - CNIVersion: types020.ImplementedSpecVersion, - DNS: r.DNS, - } - - for _, ip := range r.IPs { - // Only convert the first IP address of each version as 0.2.0 - // and earlier cannot handle multiple IP addresses - if ip.Version == "4" && oldResult.IP4 == nil { - oldResult.IP4 = &types020.IPConfig{ - IP: ip.Address, - Gateway: ip.Gateway, - } - } else if ip.Version == "6" && oldResult.IP6 == nil { - oldResult.IP6 = &types020.IPConfig{ - IP: ip.Address, - Gateway: ip.Gateway, - } - } - - if oldResult.IP4 != nil && oldResult.IP6 != nil { - break - } - } - - for _, route := range r.Routes { - is4 := route.Dst.IP.To4() != nil - if is4 && oldResult.IP4 != nil { - oldResult.IP4.Routes = append(oldResult.IP4.Routes, types.Route{ - Dst: route.Dst, - GW: route.GW, - }) - } else if !is4 && oldResult.IP6 != nil { - oldResult.IP6.Routes = append(oldResult.IP6.Routes, types.Route{ - Dst: route.Dst, - GW: route.GW, - }) - } - } - - if oldResult.IP4 == nil && oldResult.IP6 == nil { - return nil, fmt.Errorf("cannot convert: no valid IP addresses") - } - - return oldResult, nil -} - -func (r *Result) Version() string { - return ImplementedSpecVersion -} - -func (r *Result) GetAsVersion(version string) (types.Result, error) { - switch version { - case "0.3.0", "0.3.1", ImplementedSpecVersion: - r.CNIVersion = version - return r, nil - case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]: - return r.convertTo020() - } - return nil, fmt.Errorf("cannot convert version 0.3.x to %q", version) -} - -func (r *Result) Print() error { - return r.PrintTo(os.Stdout) -} - -func (r *Result) PrintTo(writer io.Writer) error { - data, err := json.MarshalIndent(r, "", " ") - if err != nil { - return err - } - _, err = writer.Write(data) - return err -} - -// Convert this old version result to the current CNI version result -func (r *Result) Convert() (*Result, error) { - return r, nil -} - -// Interface contains values about the created interfaces -type Interface struct { - Name string `json:"name"` - Mac string `json:"mac,omitempty"` - Sandbox string `json:"sandbox,omitempty"` -} - -func (i *Interface) String() string { - return fmt.Sprintf("%+v", *i) -} - -// Int returns a pointer to the int value passed in. Used to -// set the IPConfig.Interface field. -func Int(v int) *int { - return &v -} - -// IPConfig contains values necessary to configure an IP address on an interface -type IPConfig struct { - // IP version, either "4" or "6" - Version string - // Index into Result structs Interfaces list - Interface *int - Address net.IPNet - Gateway net.IP -} - -func (i *IPConfig) String() string { - return fmt.Sprintf("%+v", *i) -} - -// JSON (un)marshallable types -type ipConfig struct { - Version string `json:"version"` - Interface *int `json:"interface,omitempty"` - Address types.IPNet `json:"address"` - Gateway net.IP `json:"gateway,omitempty"` -} - -func (c *IPConfig) MarshalJSON() ([]byte, error) { - ipc := ipConfig{ - Version: c.Version, - Interface: c.Interface, - Address: types.IPNet(c.Address), - Gateway: c.Gateway, - } - - return json.Marshal(ipc) -} - -func (c *IPConfig) UnmarshalJSON(data []byte) error { - ipc := ipConfig{} - if err := json.Unmarshal(data, &ipc); err != nil { - return err - } - - c.Version = ipc.Version - c.Interface = ipc.Interface - c.Address = net.IPNet(ipc.Address) - c.Gateway = ipc.Gateway - return nil -} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/internal/convert.go b/vendor/github.com/containernetworking/cni/pkg/types/internal/convert.go new file mode 100644 index 000000000..bdbe4b0a5 --- /dev/null +++ b/vendor/github.com/containernetworking/cni/pkg/types/internal/convert.go @@ -0,0 +1,92 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package convert + +import ( + "fmt" + + "github.com/containernetworking/cni/pkg/types" +) + +// ConvertFn should convert from the given arbitrary Result type into a +// Result implementing CNI specification version passed in toVersion. +// The function is guaranteed to be passed a Result type matching the +// fromVersion it was registered with, and is guaranteed to be +// passed a toVersion matching one of the toVersions it was registered with. +type ConvertFn func(from types.Result, toVersion string) (types.Result, error) + +type converter struct { + // fromVersion is the CNI Result spec version that convertFn accepts + fromVersion string + // toVersions is a list of versions that convertFn can convert to + toVersions []string + convertFn ConvertFn +} + +var converters []*converter + +func findConverter(fromVersion, toVersion string) *converter { + for _, c := range converters { + if c.fromVersion == fromVersion { + for _, v := range c.toVersions { + if v == toVersion { + return c + } + } + } + } + return nil +} + +// Convert converts a CNI Result to the requested CNI specification version, +// or returns an error if the conversion could not be performed or failed +func Convert(from types.Result, toVersion string) (types.Result, error) { + if toVersion == "" { + toVersion = "0.1.0" + } + + fromVersion := from.Version() + + // Shortcut for same version + if fromVersion == toVersion { + return from, nil + } + + // Otherwise find the right converter + c := findConverter(fromVersion, toVersion) + if c == nil { + return nil, fmt.Errorf("no converter for CNI result version %s to %s", + fromVersion, toVersion) + } + return c.convertFn(from, toVersion) +} + +// RegisterConverter registers a CNI Result converter. SHOULD NOT BE CALLED +// EXCEPT FROM CNI ITSELF. +func RegisterConverter(fromVersion string, toVersions []string, convertFn ConvertFn) { + // Make sure there is no converter already registered for these + // from and to versions + for _, v := range toVersions { + if findConverter(fromVersion, v) != nil { + panic(fmt.Sprintf("converter already registered for %s to %s", + fromVersion, v)) + } + } + converters = append(converters, &converter{ + fromVersion: fromVersion, + toVersions: toVersions, + convertFn: convertFn, + }) +} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/internal/create.go b/vendor/github.com/containernetworking/cni/pkg/types/internal/create.go new file mode 100644 index 000000000..963630912 --- /dev/null +++ b/vendor/github.com/containernetworking/cni/pkg/types/internal/create.go @@ -0,0 +1,66 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package convert + +import ( + "fmt" + + "github.com/containernetworking/cni/pkg/types" +) + +type ResultFactoryFunc func([]byte) (types.Result, error) + +type creator struct { + // CNI Result spec versions that createFn can create a Result for + versions []string + createFn ResultFactoryFunc +} + +var creators []*creator + +func findCreator(version string) *creator { + for _, c := range creators { + for _, v := range c.versions { + if v == version { + return c + } + } + } + return nil +} + +// Create creates a CNI Result using the given JSON, or an error if the creation +// could not be performed +func Create(version string, bytes []byte) (types.Result, error) { + if c := findCreator(version); c != nil { + return c.createFn(bytes) + } + return nil, fmt.Errorf("unsupported CNI result version %q", version) +} + +// RegisterCreator registers a CNI Result creator. SHOULD NOT BE CALLED +// EXCEPT FROM CNI ITSELF. +func RegisterCreator(versions []string, createFn ResultFactoryFunc) { + // Make sure there is no creator already registered for these versions + for _, v := range versions { + if findCreator(v) != nil { + panic(fmt.Sprintf("creator already registered for %s", v)) + } + } + creators = append(creators, &creator{ + versions: versions, + createFn: createFn, + }) +} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/types.go b/vendor/github.com/containernetworking/cni/pkg/types/types.go index 3fa757a5d..fba17dfc0 100644 --- a/vendor/github.com/containernetworking/cni/pkg/types/types.go +++ b/vendor/github.com/containernetworking/cni/pkg/types/types.go @@ -83,8 +83,6 @@ type NetConfList struct { Plugins []*NetConf `json:"plugins,omitempty"` } -type ResultFactoryFunc func([]byte) (Result, error) - // Result is an interface that provides the result of plugin execution type Result interface { // The highest CNI specification result version the result supports @@ -118,6 +116,24 @@ type DNS struct { Options []string `json:"options,omitempty"` } +func (d *DNS) Copy() *DNS { + if d == nil { + return nil + } + + to := &DNS{Domain: d.Domain} + for _, ns := range d.Nameservers { + to.Nameservers = append(to.Nameservers, ns) + } + for _, s := range d.Search { + to.Search = append(to.Search, s) + } + for _, o := range d.Options { + to.Options = append(to.Options, o) + } + return to +} + type Route struct { Dst net.IPNet GW net.IP @@ -127,6 +143,17 @@ func (r *Route) String() string { return fmt.Sprintf("%+v", *r) } +func (r *Route) Copy() *Route { + if r == nil { + return nil + } + + return &Route{ + Dst: r.Dst, + GW: r.GW, + } +} + // Well known error codes // see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes const ( diff --git a/vendor/github.com/containernetworking/cni/pkg/version/conf.go b/vendor/github.com/containernetworking/cni/pkg/version/conf.go index 3cca58bbe..808c33b83 100644 --- a/vendor/github.com/containernetworking/cni/pkg/version/conf.go +++ b/vendor/github.com/containernetworking/cni/pkg/version/conf.go @@ -15,23 +15,12 @@ package version import ( - "encoding/json" - "fmt" + "github.com/containernetworking/cni/pkg/types/create" ) // ConfigDecoder can decode the CNI version available in network config data type ConfigDecoder struct{} func (*ConfigDecoder) Decode(jsonBytes []byte) (string, error) { - var conf struct { - CNIVersion string `json:"cniVersion"` - } - err := json.Unmarshal(jsonBytes, &conf) - if err != nil { - return "", fmt.Errorf("decoding version from network config: %s", err) - } - if conf.CNIVersion == "" { - return "0.1.0", nil - } - return conf.CNIVersion, nil + return create.DecodeVersion(jsonBytes) } diff --git a/vendor/github.com/containernetworking/cni/pkg/version/plugin.go b/vendor/github.com/containernetworking/cni/pkg/version/plugin.go index 1df427243..d4bc9d169 100644 --- a/vendor/github.com/containernetworking/cni/pkg/version/plugin.go +++ b/vendor/github.com/containernetworking/cni/pkg/version/plugin.go @@ -68,7 +68,7 @@ func (*PluginDecoder) Decode(jsonBytes []byte) (PluginInfo, error) { var info pluginInfo err := json.Unmarshal(jsonBytes, &info) if err != nil { - return nil, fmt.Errorf("decoding version info: %s", err) + return nil, fmt.Errorf("decoding version info: %w", err) } if info.CNIVersion_ == "" { return nil, fmt.Errorf("decoding version info: missing field cniVersion") @@ -97,20 +97,20 @@ func ParseVersion(version string) (int, int, int, error) { major, err := strconv.Atoi(parts[0]) if err != nil { - return -1, -1, -1, fmt.Errorf("failed to convert major version part %q: %v", parts[0], err) + return -1, -1, -1, fmt.Errorf("failed to convert major version part %q: %w", parts[0], err) } if len(parts) >= 2 { minor, err = strconv.Atoi(parts[1]) if err != nil { - return -1, -1, -1, fmt.Errorf("failed to convert minor version part %q: %v", parts[1], err) + return -1, -1, -1, fmt.Errorf("failed to convert minor version part %q: %w", parts[1], err) } } if len(parts) >= 3 { micro, err = strconv.Atoi(parts[2]) if err != nil { - return -1, -1, -1, fmt.Errorf("failed to convert micro version part %q: %v", parts[2], err) + return -1, -1, -1, fmt.Errorf("failed to convert micro version part %q: %w", parts[2], err) } } diff --git a/vendor/github.com/containernetworking/cni/pkg/version/version.go b/vendor/github.com/containernetworking/cni/pkg/version/version.go index 8f3508e61..1326f8038 100644 --- a/vendor/github.com/containernetworking/cni/pkg/version/version.go +++ b/vendor/github.com/containernetworking/cni/pkg/version/version.go @@ -19,13 +19,13 @@ import ( "fmt" "github.com/containernetworking/cni/pkg/types" - "github.com/containernetworking/cni/pkg/types/020" - "github.com/containernetworking/cni/pkg/types/current" + types100 "github.com/containernetworking/cni/pkg/types/100" + "github.com/containernetworking/cni/pkg/types/create" ) // Current reports the version of the CNI spec implemented by this library func Current() string { - return "0.4.0" + return types100.ImplementedSpecVersion } // Legacy PluginInfo describes a plugin that is backwards compatible with the @@ -36,29 +36,28 @@ func Current() string { // Any future CNI spec versions which meet this definition should be added to // this list. var Legacy = PluginSupports("0.1.0", "0.2.0") -var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0") +var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0", "1.0.0") -var resultFactories = []struct { - supportedVersions []string - newResult types.ResultFactoryFunc -}{ - {current.SupportedVersions, current.NewResult}, - {types020.SupportedVersions, types020.NewResult}, +// VersionsFrom returns a list of versions starting from min, inclusive +func VersionsStartingFrom(min string) PluginInfo { + out := []string{} + // cheat, just assume ordered + ok := false + for _, v := range All.SupportedVersions() { + if !ok && v == min { + ok = true + } + if ok { + out = append(out, v) + } + } + return PluginSupports(out...) } // Finds a Result object matching the requested version (if any) and asks // that object to parse the plugin result, returning an error if parsing failed. func NewResult(version string, resultBytes []byte) (types.Result, error) { - reconciler := &Reconciler{} - for _, resultFactory := range resultFactories { - err := reconciler.CheckRaw(version, resultFactory.supportedVersions) - if err == nil { - // Result supports this version - return resultFactory.newResult(resultBytes) - } - } - - return nil, fmt.Errorf("unsupported CNI result version %q", version) + return create.Create(version, resultBytes) } // ParsePrevResult parses a prevResult in a NetConf structure and sets @@ -68,15 +67,22 @@ func ParsePrevResult(conf *types.NetConf) error { return nil } + // Prior to 1.0.0, Result types may not marshal a CNIVersion. Since the + // result version must match the config version, if the Result's version + // is empty, inject the config version. + if ver, ok := conf.RawPrevResult["CNIVersion"]; !ok || ver == "" { + conf.RawPrevResult["CNIVersion"] = conf.CNIVersion + } + resultBytes, err := json.Marshal(conf.RawPrevResult) if err != nil { - return fmt.Errorf("could not serialize prevResult: %v", err) + return fmt.Errorf("could not serialize prevResult: %w", err) } conf.RawPrevResult = nil - conf.PrevResult, err = NewResult(conf.CNIVersion, resultBytes) + conf.PrevResult, err = create.Create(conf.CNIVersion, resultBytes) if err != nil { - return fmt.Errorf("could not parse prevResult: %v", err) + return fmt.Errorf("could not parse prevResult: %w", err) } return nil diff --git a/vendor/github.com/containers/common/libimage/copier.go b/vendor/github.com/containers/common/libimage/copier.go index a44f098ad..636b97bfd 100644 --- a/vendor/github.com/containers/common/libimage/copier.go +++ b/vendor/github.com/containers/common/libimage/copier.go @@ -12,6 +12,7 @@ import ( "github.com/containers/common/pkg/retry" "github.com/containers/image/v5/copy" "github.com/containers/image/v5/docker/reference" + "github.com/containers/image/v5/pkg/compression" "github.com/containers/image/v5/signature" storageTransport "github.com/containers/image/v5/storage" "github.com/containers/image/v5/types" @@ -40,6 +41,10 @@ type CopyOptions struct { // Allows for customizing the destination reference lookup. This can // be used to use custom blob caches. DestinationLookupReferenceFunc LookupReferenceFunc + // CompressionFormat is the format to use for the compression of the blobs + CompressionFormat *compression.Algorithm + // CompressionLevel specifies what compression level is used + CompressionLevel *int // containers-auth.json(5) file to use when authenticating against // container registries. @@ -65,6 +70,8 @@ type CopyOptions struct { // types. Short forms (e.g., oci, v2s2) used by some tools are not // supported. ManifestMIMEType string + // Accept uncompressed layers when copying OCI images. + OciAcceptUncompressedLayers bool // If OciEncryptConfig is non-nil, it indicates that an image should be // encrypted. The encryption options is derived from the construction // of EncryptConfig object. Note: During initial encryption process of @@ -242,6 +249,17 @@ func (r *Runtime) newCopier(options *CopyOptions) (*copier, error) { c.systemContext.DockerCertPath = options.CertDirPath } + if options.CompressionFormat != nil { + c.systemContext.CompressionFormat = options.CompressionFormat + } + + if options.CompressionLevel != nil { + c.systemContext.CompressionLevel = options.CompressionLevel + } + + // NOTE: for the sake of consistency it's called Oci* in the CopyOptions. + c.systemContext.OCIAcceptUncompressedLayers = options.OciAcceptUncompressedLayers + policy, err := signature.DefaultPolicy(c.systemContext) if err != nil { return nil, err @@ -286,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 a3fdc9529..e72e1b3e4 100644 --- a/vendor/github.com/containers/common/pkg/config/default.go +++ b/vendor/github.com/containers/common/pkg/config/default.go @@ -198,7 +198,6 @@ func DefaultConfig() (*Config, error) { TZ: "", Umask: "0022", UTSNS: "private", - UserNS: "host", UserNSSize: DefaultUserNSSize, }, Network: NetworkConfig{ @@ -209,6 +208,7 @@ func DefaultConfig() (*Config, error) { }, Engine: *defaultEngineConfig, Secrets: defaultSecretConfig(), + Machine: defaultMachineConfig(), }, nil } @@ -220,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) { @@ -346,8 +356,6 @@ func defaultConfigFromMemory() (*EngineConfig, error) { // constants. c.LockType = "shm" c.MachineEnabled = false - c.MachineImage = "testing" - c.ChownCopiedFiles = true return c, nil @@ -567,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/secrets/secrets.go b/vendor/github.com/containers/common/pkg/secrets/secrets.go index 2e7802369..aea983cb1 100644 --- a/vendor/github.com/containers/common/pkg/secrets/secrets.go +++ b/vendor/github.com/containers/common/pkg/secrets/secrets.go @@ -24,8 +24,8 @@ const secretIDLength = 25 // errInvalidPath indicates that the secrets path is invalid var errInvalidPath = errors.New("invalid secrets path") -// errNoSuchSecret indicates that the secret does not exist -var errNoSuchSecret = errors.New("no such secret") +// ErrNoSuchSecret indicates that the secret does not exist +var ErrNoSuchSecret = errors.New("no such secret") // errSecretNameInUse indicates that the secret name is already in use var errSecretNameInUse = errors.New("secret name in use") @@ -152,7 +152,7 @@ func (s *SecretsManager) Store(name string, data []byte, driverType string, driv newID = newID[0:secretIDLength] _, err := s.lookupSecret(newID) if err != nil { - if errors.Cause(err) == errNoSuchSecret { + if errors.Cause(err) == ErrNoSuchSecret { secr.ID = newID break } else { diff --git a/vendor/github.com/containers/common/pkg/secrets/secretsdb.go b/vendor/github.com/containers/common/pkg/secrets/secretsdb.go index 1395d103c..0c4929995 100644 --- a/vendor/github.com/containers/common/pkg/secrets/secretsdb.go +++ b/vendor/github.com/containers/common/pkg/secrets/secretsdb.go @@ -71,14 +71,14 @@ func (s *SecretsManager) getNameAndID(nameOrID string) (name, id string, err err name, id, err = s.getExactNameAndID(nameOrID) if err == nil { return name, id, nil - } else if errors.Cause(err) != errNoSuchSecret { + } else if errors.Cause(err) != ErrNoSuchSecret { return "", "", err } // ID prefix may have been given, iterate through all IDs. // ID and partial ID has a max length of 25, so we return if its greater than that. if len(nameOrID) > secretIDLength { - return "", "", errors.Wrapf(errNoSuchSecret, "no secret with name or id %q", nameOrID) + return "", "", errors.Wrapf(ErrNoSuchSecret, "no secret with name or id %q", nameOrID) } exists := false var foundID, foundName string @@ -96,7 +96,7 @@ func (s *SecretsManager) getNameAndID(nameOrID string) (name, id string, err err if exists { return foundName, foundID, nil } - return "", "", errors.Wrapf(errNoSuchSecret, "no secret with name or id %q", nameOrID) + return "", "", errors.Wrapf(ErrNoSuchSecret, "no secret with name or id %q", nameOrID) } // getExactNameAndID takes a secret's name or ID and returns both its name and full ID. @@ -115,7 +115,7 @@ func (s *SecretsManager) getExactNameAndID(nameOrID string) (name, id string, er return name, id, nil } - return "", "", errors.Wrapf(errNoSuchSecret, "no secret with name or id %q", nameOrID) + return "", "", errors.Wrapf(ErrNoSuchSecret, "no secret with name or id %q", nameOrID) } // exactSecretExists checks if the secret exists, given a name or ID @@ -123,7 +123,7 @@ func (s *SecretsManager) getExactNameAndID(nameOrID string) (name, id string, er func (s *SecretsManager) exactSecretExists(nameOrID string) (bool, error) { _, _, err := s.getExactNameAndID(nameOrID) if err != nil { - if errors.Cause(err) == errNoSuchSecret { + if errors.Cause(err) == ErrNoSuchSecret { return false, nil } return false, err @@ -158,7 +158,7 @@ func (s *SecretsManager) lookupSecret(nameOrID string) (*Secret, error) { return &secret, nil } - return nil, errors.Wrapf(errNoSuchSecret, "no secret with name or id %q", nameOrID) + return nil, errors.Wrapf(ErrNoSuchSecret, "no secret with name or id %q", nameOrID) } // Store creates a new secret in the secrets database. 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/github.com/containers/psgo/.codespellrc b/vendor/github.com/containers/psgo/.codespellrc new file mode 100644 index 000000000..604bc21da --- /dev/null +++ b/vendor/github.com/containers/psgo/.codespellrc @@ -0,0 +1,2 @@ +[codespell] +skip = ./vendor,./.git diff --git a/vendor/github.com/containers/psgo/.golangci.yml b/vendor/github.com/containers/psgo/.golangci.yml new file mode 100644 index 000000000..a098068fe --- /dev/null +++ b/vendor/github.com/containers/psgo/.golangci.yml @@ -0,0 +1,6 @@ +# For documentation, see https://golangci-lint.run/usage/configuration/ + +linters: + enable: + - errorlint + - gofumpt diff --git a/vendor/github.com/containers/psgo/.travis.yml b/vendor/github.com/containers/psgo/.travis.yml deleted file mode 100644 index c07bb140b..000000000 --- a/vendor/github.com/containers/psgo/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: go - -sudo: required - -servics: - - docker - -go: - - tip - -before_install: - - sudo add-apt-repository ppa:duggan/bats --yes - - sudo apt-get update -qq - - sudo apt-get install -qq bats - -script: - - make validate - - make build - - make test diff --git a/vendor/github.com/containers/psgo/Makefile b/vendor/github.com/containers/psgo/Makefile index 831dfa31f..fb6126e7c 100644 --- a/vendor/github.com/containers/psgo/Makefile +++ b/vendor/github.com/containers/psgo/Makefile @@ -1,28 +1,25 @@ -export GO111MODULE=off -export GOPROXY=https://proxy.golang.org - SHELL= /bin/bash GO ?= go BUILD_DIR := ./bin BIN_DIR := /usr/local/bin NAME := psgo -PROJECT := github.com/containers/psgo BATS_TESTS := *.bats -GO_SRC=$(shell find . -name \*.go) -GO_BUILD=$(GO) build -# Go module support: set `-mod=vendor` to use the vendored sources -ifeq ($(shell go help mod >/dev/null 2>&1 && echo true), true) - GO_BUILD=GO111MODULE=on $(GO) build -mod=vendor +# Not all platforms support -buildmode=pie, plus it's incompatible with -race. +ifeq ($(shell $(GO) env GOOS),linux) + ifeq (,$(filter $(shell $(GO) env GOARCH),mips mipsle mips64 mips64le ppc64 riscv64)) + ifeq (,$(findstring -race,$(EXTRA_BUILD_FLAGS))) + GO_BUILDMODE := "-buildmode=pie" + endif + endif endif - -GOBIN ?= $(GO)/bin +GO_BUILD := $(GO) build $(GO_BUILDMODE) all: validate build .PHONY: build -build: $(GO_SRC) - $(GO_BUILD) -buildmode=pie -o $(BUILD_DIR)/$(NAME) $(PROJECT)/sample +build: + $(GO_BUILD) $(EXTRA_BUILD_FLAGS) -o $(BUILD_DIR)/$(NAME) ./sample .PHONY: clean clean: @@ -30,13 +27,13 @@ clean: .PHONY: vendor vendor: - GO111MODULE=on go mod tidy - GO111MODULE=on go mod vendor - GO111MODULE=on go mod verify + go mod tidy + go mod vendor + go mod verify .PHONY: validate -validate: .install.lint - $(GOBIN)/golangci-lint run +validate: + golangci-lint run .PHONY: test test: test-unit test-integration @@ -47,17 +44,12 @@ test-integration: .PHONY: test-unit test-unit: - go test -v $(PROJECT) - go test -v $(PROJECT)/internal/... + $(GO) test -v $(EXTRA_TEST_FLAGS) ./... .PHONY: install install: sudo install -D -m755 $(BUILD_DIR)/$(NAME) $(BIN_DIR) -.PHONY: .install.lint -.install.lint: - VERSION=1.24.0 GOBIN=$(GOBIN) sh ./hack/install_golangci.sh - .PHONY: uninstall uninstall: sudo rm $(BIN_DIR)/$(NAME) diff --git a/vendor/github.com/containers/psgo/README.md b/vendor/github.com/containers/psgo/README.md index fed42c683..684c80a0c 100644 --- a/vendor/github.com/containers/psgo/README.md +++ b/vendor/github.com/containers/psgo/README.md @@ -73,8 +73,12 @@ The ps library is compatible with all AIX format descriptors of the ps command-l - Set of inheritable capabilities. See capabilities(7) for more information. - **capprm** - Set of permitted capabilities. See capabilities(7) for more information. +- **groups** + - Supplmentary groups inside the container. - **hgroup** - The corresponding effective group of a container process on the host. +- **hgroups** + - Supplmentary groups on the host. - **hpid** - The corresponding host PID of a container process. - **huser** diff --git a/vendor/github.com/containers/psgo/go.mod b/vendor/github.com/containers/psgo/go.mod index 699874cf7..fd19d9b48 100644 --- a/vendor/github.com/containers/psgo/go.mod +++ b/vendor/github.com/containers/psgo/go.mod @@ -1,10 +1,9 @@ module github.com/containers/psgo -go 1.13 +go 1.14 require ( github.com/opencontainers/runc v1.0.2 - github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 ) diff --git a/vendor/github.com/containers/psgo/go.sum b/vendor/github.com/containers/psgo/go.sum index 0ba04956f..85b0f4ff7 100644 --- a/vendor/github.com/containers/psgo/go.sum +++ b/vendor/github.com/containers/psgo/go.sum @@ -39,7 +39,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= diff --git a/vendor/github.com/containers/psgo/internal/host/host.go b/vendor/github.com/containers/psgo/internal/host/host.go index 33ad67a11..3c708a2b8 100644 --- a/vendor/github.com/containers/psgo/internal/host/host.go +++ b/vendor/github.com/containers/psgo/internal/host/host.go @@ -54,7 +54,7 @@ func BootTime() (int64, error) { btimeSec, err := strconv.ParseInt(btimeStr, 10, 64) if err != nil { - return 0, fmt.Errorf("error parsing boot time from /proc/stat: %s", err) + return 0, fmt.Errorf("error parsing boot time from /proc/stat: %w", err) } bootTime = &btimeSec return btimeSec, nil diff --git a/vendor/github.com/containers/psgo/internal/proc/ns.go b/vendor/github.com/containers/psgo/internal/proc/ns.go index 4778048f2..28ee6a2c9 100644 --- a/vendor/github.com/containers/psgo/internal/proc/ns.go +++ b/vendor/github.com/containers/psgo/internal/proc/ns.go @@ -59,7 +59,7 @@ func ReadMappings(path string) ([]IDMap, error) { for { line, _, err := buf.ReadLine() if err != nil { - if err == io.EOF { + if err == io.EOF { //nolint:errorlint // False positive, see https://github.com/polyfloyd/go-errorlint/pull/12 return mappings, nil } return nil, fmt.Errorf("cannot read line from %s: %w", path, err) diff --git a/vendor/github.com/containers/psgo/internal/proc/pids.go b/vendor/github.com/containers/psgo/internal/proc/pids.go index 69e8befc1..2687396e1 100644 --- a/vendor/github.com/containers/psgo/internal/proc/pids.go +++ b/vendor/github.com/containers/psgo/internal/proc/pids.go @@ -52,7 +52,7 @@ func GetPIDs() ([]string, error) { return pids, nil } -// GetPIDsFromCgroup returns a strings slice of all pids listesd in pid's pids +// GetPIDsFromCgroup returns a strings slice of all pids listed in pid's pids // cgroup. It automatically detects if we're running in unified mode or not. func GetPIDsFromCgroup(pid string) ([]string, error) { unified, err := cgroups.IsCgroup2UnifiedMode() @@ -65,11 +65,12 @@ func GetPIDsFromCgroup(pid string) ([]string, error) { return getPIDsFromCgroupV1(pid) } -// getPIDsFromCgroupV1 returns a strings slice of all pids listesd in pid's pids +// getPIDsFromCgroupV1 returns a strings slice of all pids listed in pid's pids // cgroup. func getPIDsFromCgroupV1(pid string) ([]string, error) { // First, find the corresponding path to the PID cgroup. - f, err := os.Open(fmt.Sprintf("/proc/%s/cgroup", pid)) + pidPath := fmt.Sprintf("/proc/%s/cgroup", pid) + f, err := os.Open(pidPath) if err != nil { return nil, err } @@ -83,7 +84,8 @@ func getPIDsFromCgroupV1(pid string) ([]string, error) { continue } if fields[1] == "pids" { - cgroupPath = fmt.Sprintf("/sys/fs/cgroup/pids/%s/cgroup.procs", fields[2]) + cgroupPath = filepath.Join(cgroups.CgroupRoot, "pids", fields[2], "cgroup.procs") + break } } @@ -94,7 +96,18 @@ func getPIDsFromCgroupV1(pid string) ([]string, error) { // Second, extract the PIDs inside the cgroup. f, err = os.Open(cgroupPath) if err != nil { - return nil, err + if os.IsNotExist(err) { + // OCI runtimes might mount the container cgroup at the root, breaking what it showed + // in /proc/$PID/cgroup and the path. + // Check if the PID still exists to make sure the process is still alive. + if _, errStat := os.Stat(pidPath); errStat == nil { + cgroupPath = filepath.Join(cgroups.CgroupRoot, "pids", "cgroup.procs") + f, err = os.Open(cgroupPath) + } + } + if err != nil { + return nil, err + } } defer f.Close() @@ -107,7 +120,7 @@ func getPIDsFromCgroupV1(pid string) ([]string, error) { return pids, nil } -// getPIDsFromCgroupV2 returns a strings slice of all pids listesd in pid's pids +// getPIDsFromCgroupV2 returns a strings slice of all pids listed in pid's pids // cgroup. func getPIDsFromCgroupV2(pid string) ([]string, error) { // First, find the corresponding path to the PID cgroup. @@ -124,8 +137,10 @@ func getPIDsFromCgroupV2(pid string) ([]string, error) { if len(fields) != 3 { continue } - cgroupSlice = fields[2] - break + if fields[1] == "" { + cgroupSlice = fields[2] + break + } } if cgroupSlice == "" { diff --git a/vendor/github.com/containers/psgo/internal/proc/status.go b/vendor/github.com/containers/psgo/internal/proc/status.go index 2753915fd..1896b5c07 100644 --- a/vendor/github.com/containers/psgo/internal/proc/status.go +++ b/vendor/github.com/containers/psgo/internal/proc/status.go @@ -182,7 +182,7 @@ func readStatusUserNS(pid string) ([]string, error) { c := exec.Command(args[0], args[1:]...) output, err := c.CombinedOutput() if err != nil { - return nil, fmt.Errorf("error executing %q: %v", strings.Join(args, " "), err) + return nil, fmt.Errorf("error executing %q: %w", strings.Join(args, " "), err) } return strings.Split(string(output), "\n"), nil diff --git a/vendor/github.com/containers/psgo/internal/process/process.go b/vendor/github.com/containers/psgo/internal/process/process.go index 8fd49e416..715039610 100644 --- a/vendor/github.com/containers/psgo/internal/process/process.go +++ b/vendor/github.com/containers/psgo/internal/process/process.go @@ -215,7 +215,7 @@ func (p *Process) StartTime() (time.Time, error) { return time.Unix(sinceBoot+bootTime, 0), nil } -// CPUTime returns the cumlative CPU time of process p as a time.Duration. +// CPUTime returns the cumulative CPU time of process p as a time.Duration. func (p *Process) CPUTime() (time.Duration, error) { user, err := strconv.ParseInt(p.Stat.Utime, 10, 64) if err != nil { diff --git a/vendor/github.com/containers/psgo/psgo.go b/vendor/github.com/containers/psgo/psgo.go index b0569fa1c..ea893e7ca 100644 --- a/vendor/github.com/containers/psgo/psgo.go +++ b/vendor/github.com/containers/psgo/psgo.go @@ -175,6 +175,11 @@ var ( procFn: processGROUP, }, { + normal: "groups", + header: "GROUPS", + procFn: processGROUPS, + }, + { code: "%P", normal: "ppid", header: "PPID", @@ -306,6 +311,12 @@ var ( procFn: processHGROUP, }, { + normal: "hgroups", + header: "HGROUPS", + onHost: true, + procFn: processHGROUPS, + }, + { normal: "rss", header: "RSS", procFn: processRSS, @@ -620,14 +631,29 @@ func findHostProcess(p *process.Process, ctx *psContext) *process.Process { } // processGROUP returns the effective group ID of the process. This will be -// the textual group ID, if it can be optained, or a decimal representation +// the textual group ID, if it can be obtained, or a decimal representation // otherwise. func processGROUP(p *process.Process, ctx *psContext) (string, error) { return process.LookupGID(p.Status.Gids[1]) } +// processGROUPS returns the supplementary groups of the process separated by +// comma. This will be the textual group ID, if it can be obtained, or a +// decimal representation otherwise. +func processGROUPS(p *process.Process, ctx *psContext) (string, error) { + var err error + groups := make([]string, len(p.Status.Groups)) + for i, g := range p.Status.Groups { + groups[i], err = process.LookupGID(g) + if err != nil { + return "", err + } + } + return strings.Join(groups, ","), nil +} + // processRGROUP returns the real group ID of the process. This will be -// the textual group ID, if it can be optained, or a decimal representation +// the textual group ID, if it can be obtained, or a decimal representation // otherwise. func processRGROUP(p *process.Process, ctx *psContext) (string, error) { return process.LookupGID(p.Status.Gids[0]) @@ -639,14 +665,14 @@ func processPPID(p *process.Process, ctx *psContext) (string, error) { } // processUSER returns the effective user name of the process. This will be -// the textual user ID, if it can be optained, or a decimal representation +// the textual user ID, if it can be obtained, or a decimal representation // otherwise. func processUSER(p *process.Process, ctx *psContext) (string, error) { return process.LookupUID(p.Status.Uids[1]) } // processRUSER returns the effective user name of the process. This will be -// the textual user ID, if it can be optained, or a decimal representation +// the textual user ID, if it can be obtained, or a decimal representation // otherwise. func processRUSER(p *process.Process, ctx *psContext) (string, error) { return process.LookupUID(p.Status.Uids[0]) @@ -867,6 +893,26 @@ func processHGROUP(p *process.Process, ctx *psContext) (string, error) { return "?", nil } +// processHGROUPS returns the supplementary groups of the corresponding host +// process of the (container) or "?" if no corresponding process could be +// found. +func processHGROUPS(p *process.Process, ctx *psContext) (string, error) { + if hp := findHostProcess(p, ctx); hp != nil { + groups := hp.Status.Groups + if ctx.opts != nil && len(ctx.opts.GIDMap) > 0 { + var err error + for i, g := range groups { + groups[i], err = findID(g, ctx.opts.GIDMap, process.LookupGID, "/proc/sys/fs/overflowgid") + if err != nil { + return "", err + } + } + } + return strings.Join(groups, ","), nil + } + return "?", nil +} + // processRSS returns the resident set size of process p in KiB (1024-byte // units). func processRSS(p *process.Process, ctx *psContext) (string, error) { diff --git a/vendor/github.com/containers/storage/.cirrus.yml b/vendor/github.com/containers/storage/.cirrus.yml index 20bede452..d080d790c 100644 --- a/vendor/github.com/containers/storage/.cirrus.yml +++ b/vendor/github.com/containers/storage/.cirrus.yml @@ -20,16 +20,14 @@ env: FEDORA_NAME: "fedora-34" PRIOR_FEDORA_NAME: "fedora-33" UBUNTU_NAME: "ubuntu-2104" - PRIOR_UBUNTU_NAME: "ubuntu-2010" # GCE project where images live IMAGE_PROJECT: "libpod-218412" # VM Image built in containers/automation_images - _BUILT_IMAGE_SUFFIX: "c6248193773010944" + _BUILT_IMAGE_SUFFIX: "c6431352024203264" FEDORA_CACHE_IMAGE_NAME: "fedora-${_BUILT_IMAGE_SUFFIX}" PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${_BUILT_IMAGE_SUFFIX}" UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${_BUILT_IMAGE_SUFFIX}" - PRIOR_UBUNTU_CACHE_IMAGE_NAME: "prior-ubuntu-${_BUILT_IMAGE_SUFFIX}" #### #### Command variables to help avoid duplication @@ -115,15 +113,6 @@ ubuntu_testing_task: &ubuntu_testing TEST_DRIVER: "overlay" -prior_ubuntu_testing_task: - <<: *ubuntu_testing - alias: prior_ubuntu_testing - name: *std_test_name - env: - OS_NAME: "${PRIOR_UBUNTU_NAME}" - VM_IMAGE: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}" - - lint_task: env: CIRRUS_WORKING_DIR: "/go/src/github.com/containers/storage" @@ -153,7 +142,6 @@ meta_task: ${FEDORA_CACHE_IMAGE_NAME} ${PRIOR_FEDORA_CACHE_IMAGE_NAME} ${UBUNTU_CACHE_IMAGE_NAME} - ${PRIOR_UBUNTU_CACHE_IMAGE_NAME} BUILDID: "${CIRRUS_BUILD_ID}" REPOREF: "${CIRRUS_CHANGE_IN_REPO}" GCPJSON: ENCRYPTED[244a93fe8b386b48b96f748342bf741350e43805eee81dd04b45093bdf737e540b993fc735df41f131835fa0f9b65826] @@ -181,7 +169,6 @@ success_task: - fedora_testing - prior_fedora_testing - ubuntu_testing - - prior_ubuntu_testing - meta - vendor container: diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION index 39fc130ef..afc132ffa 100644 --- a/vendor/github.com/containers/storage/VERSION +++ b/vendor/github.com/containers/storage/VERSION @@ -1 +1 @@ -1.36.0 +1.36.0+dev diff --git a/vendor/github.com/containers/storage/drivers/aufs/aufs.go b/vendor/github.com/containers/storage/drivers/aufs/aufs.go index 76f12ec3b..a566fbffa 100644 --- a/vendor/github.com/containers/storage/drivers/aufs/aufs.go +++ b/vendor/github.com/containers/storage/drivers/aufs/aufs.go @@ -730,14 +730,14 @@ func useDirperm() bool { enableDirpermLock.Do(func() { base, err := ioutil.TempDir("", "storage-aufs-base") if err != nil { - logrus.Errorf("error checking dirperm1: %v", err) + logrus.Errorf("Checking dirperm1: %v", err) return } defer os.RemoveAll(base) union, err := ioutil.TempDir("", "storage-aufs-union") if err != nil { - logrus.Errorf("error checking dirperm1: %v", err) + logrus.Errorf("Checking dirperm1: %v", err) return } defer os.RemoveAll(union) @@ -748,7 +748,7 @@ func useDirperm() bool { } enableDirperm = true if err := Unmount(union); err != nil { - logrus.Errorf("error checking dirperm1: failed to unmount %v", err) + logrus.Errorf("Checking dirperm1: failed to unmount %v", err) } }) return enableDirperm diff --git a/vendor/github.com/containers/storage/drivers/fsdiff.go b/vendor/github.com/containers/storage/drivers/fsdiff.go index c52788509..a534630df 100644 --- a/vendor/github.com/containers/storage/drivers/fsdiff.go +++ b/vendor/github.com/containers/storage/drivers/fsdiff.go @@ -180,7 +180,7 @@ func (gdw *NaiveDiffDriver) ApplyDiff(id, parent string, options ApplyDiffOpts) start := time.Now().UTC() logrus.Debug("Start untar layer") if size, err = ApplyUncompressedLayer(layerFs, options.Diff, tarOptions); err != nil { - logrus.Errorf("Error while applying layer: %s", err) + logrus.Errorf("While applying layer: %s", err) return } logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go index f546f9b10..62130c73e 100644 --- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go +++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go @@ -174,21 +174,21 @@ func checkSupportVolatile(home, runhome string) (bool, error) { var usingVolatile bool if err == nil { if volatileCacheResult { - logrus.Debugf("cached value indicated that volatile is being used") + logrus.Debugf("Cached value indicated that volatile is being used") } else { - logrus.Debugf("cached value indicated that volatile is not being used") + logrus.Debugf("Cached value indicated that volatile is not being used") } usingVolatile = volatileCacheResult } else { usingVolatile, err = doesVolatile(home) if err == nil { if usingVolatile { - logrus.Debugf("overlay test mount indicated that volatile is being used") + logrus.Debugf("overlay: test mount indicated that volatile is being used") } else { - logrus.Debugf("overlay test mount indicated that volatile is not being used") + logrus.Debugf("overlay: test mount indicated that volatile is not being used") } if err = cachedFeatureRecord(runhome, feature, usingVolatile, ""); err != nil { - return false, errors.Wrap(err, "error recording volatile-being-used status") + return false, errors.Wrap(err, "recording volatile-being-used status") } } } @@ -206,9 +206,9 @@ func checkAndRecordOverlaySupport(fsMagic graphdriver.FsMagic, home, runhome str overlayCacheResult, overlayCacheText, err := cachedFeatureCheck(runhome, feature) if err == nil { if overlayCacheResult { - logrus.Debugf("cached value indicated that overlay is supported") + logrus.Debugf("Cached value indicated that overlay is supported") } else { - logrus.Debugf("cached value indicated that overlay is not supported") + logrus.Debugf("Cached value indicated that overlay is not supported") } supportsDType = overlayCacheResult if !supportsDType { @@ -225,12 +225,12 @@ func checkAndRecordOverlaySupport(fsMagic graphdriver.FsMagic, home, runhome str } err = errors.Wrap(err, "kernel does not support overlay fs") if err2 := cachedFeatureRecord(runhome, feature, false, err.Error()); err2 != nil { - return false, errors.Wrapf(err2, "error recording overlay not being supported (%v)", err) + return false, errors.Wrapf(err2, "recording overlay not being supported (%v)", err) } return false, err } if err = cachedFeatureRecord(runhome, feature, supportsDType, ""); err != nil { - return false, errors.Wrap(err, "error recording overlay support status") + return false, errors.Wrap(err, "recording overlay support status") } } return supportsDType, nil @@ -310,24 +310,24 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) metacopyCacheResult, _, err := cachedFeatureCheck(runhome, feature) if err == nil { if metacopyCacheResult { - logrus.Debugf("cached value indicated that metacopy is being used") + logrus.Debugf("Cached value indicated that metacopy is being used") } else { - logrus.Debugf("cached value indicated that metacopy is not being used") + logrus.Debugf("Cached value indicated that metacopy is not being used") } usingMetacopy = metacopyCacheResult } else { usingMetacopy, err = doesMetacopy(home, opts.mountOptions) if err == nil { if usingMetacopy { - logrus.Debugf("overlay test mount indicated that metacopy is being used") + logrus.Debugf("overlay: test mount indicated that metacopy is being used") } else { - logrus.Debugf("overlay test mount indicated that metacopy is not being used") + logrus.Debugf("overlay: test mount indicated that metacopy is not being used") } if err = cachedFeatureRecord(runhome, feature, usingMetacopy, ""); err != nil { - return nil, errors.Wrap(err, "error recording metacopy-being-used status") + return nil, errors.Wrap(err, "recording metacopy-being-used status") } } else { - logrus.Infof("overlay test mount did not indicate whether or not metacopy is being used: %v", err) + logrus.Infof("overlay: test mount did not indicate whether or not metacopy is being used: %v", err) return nil, err } } @@ -548,7 +548,7 @@ func SupportsNativeOverlay(graphroot, rundir string) (bool, error) { } switch contents { case "true": - logrus.Debugf("overlay storage already configured with a mount-program") + logrus.Debugf("overlay: storage already configured with a mount-program") return false, nil default: needsMountProgram, err := scanForMountProgramIndicators(home) @@ -640,17 +640,17 @@ func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGI flags = fmt.Sprintf("%s,userxattr", flags) } if err := syscall.Mknod(filepath.Join(upperDir, "whiteout"), syscall.S_IFCHR|0600, int(unix.Mkdev(0, 0))); err != nil { - logrus.Debugf("unable to create kernel-style whiteout: %v", err) + logrus.Debugf("Unable to create kernel-style whiteout: %v", err) return supportsDType, errors.Wrapf(err, "unable to create kernel-style whiteout") } if len(flags) < unix.Getpagesize() { err := unix.Mount("overlay", mergedDir, "overlay", 0, flags) if err == nil { - logrus.Debugf("overlay test mount with multiple lowers succeeded") + logrus.Debugf("overlay: test mount with multiple lowers succeeded") return supportsDType, nil } - logrus.Debugf("overlay test mount with multiple lowers failed %v", err) + logrus.Debugf("overlay: test mount with multiple lowers failed %v", err) } flags = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower1Dir, upperDir, workDir) if selinux.GetEnabled() { @@ -659,10 +659,10 @@ func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGI if len(flags) < unix.Getpagesize() { err := unix.Mount("overlay", mergedDir, "overlay", 0, flags) if err == nil { - logrus.StandardLogger().Logf(logLevel, "overlay test mount with multiple lowers failed, but succeeded with a single lower") + logrus.StandardLogger().Logf(logLevel, "overlay: test mount with multiple lowers failed, but succeeded with a single lower") return supportsDType, errors.Wrap(graphdriver.ErrNotSupported, "kernel too old to provide multiple lowers feature for overlay") } - logrus.Debugf("overlay test mount with a single lower failed %v", err) + logrus.Debugf("overlay: test mount with a single lower failed %v", err) } logrus.StandardLogger().Logf(logLevel, "'overlay' is not supported over %s at %q", backingFs, home) return supportsDType, errors.Wrapf(graphdriver.ErrIncompatibleFS, "'overlay' is not supported over %s at %q", backingFs, home) @@ -682,9 +682,9 @@ func (d *Driver) useNaiveDiff() bool { nativeDiffCacheResult, nativeDiffCacheText, err := cachedFeatureCheck(d.runhome, feature) if err == nil { if nativeDiffCacheResult { - logrus.Debugf("cached value indicated that native-diff is usable") + logrus.Debugf("Cached value indicated that native-diff is usable") } else { - logrus.Debugf("cached value indicated that native-diff is not being used") + logrus.Debugf("Cached value indicated that native-diff is not being used") logrus.Info(nativeDiffCacheText) } useNaiveDiffOnly = !nativeDiffCacheResult @@ -821,7 +821,7 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts opts.StorageOpt["inodes"] = strconv.FormatUint(d.options.quota.Inodes, 10) } - return d.create(id, parent, opts) + return d.create(id, parent, opts, false) } // Create is used to create the upper, lower, and merge directories required for overlay fs for a given id. @@ -831,15 +831,16 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr if _, ok := opts.StorageOpt["size"]; ok { return fmt.Errorf("--storage-opt size is only supported for ReadWrite Layers") } + if _, ok := opts.StorageOpt["inodes"]; ok { return fmt.Errorf("--storage-opt inodes is only supported for ReadWrite Layers") } } - return d.create(id, parent, opts) + return d.create(id, parent, opts, true) } -func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr error) { +func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disableQuota bool) (retErr error) { dir := d.dir(id) uidMaps := d.uidMaps @@ -880,7 +881,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr } }() - if d.quotaCtl != nil { + if d.quotaCtl != nil && !disableQuota { quota := quota.Quota{} if opts != nil && len(opts.StorageOpt) > 0 { driver := &Driver{} @@ -994,7 +995,7 @@ func (d *Driver) getLower(parent string) (string, error) { } logrus.Warnf("Can't read parent link %q because it does not exist. Going through storage to recreate the missing links.", path.Join(parentDir, "link")) if err := d.recreateSymlinks(); err != nil { - return "", errors.Wrap(err, "error recreating the links") + return "", errors.Wrap(err, "recreating the links") } parentLink, err = ioutil.ReadFile(path.Join(parentDir, "link")) if err != nil { @@ -1038,7 +1039,7 @@ func (d *Driver) getLowerDirs(id string) ([]string, error) { if os.IsNotExist(err) { logrus.Warnf("Can't read link %q because it does not exist. A storage corruption might have occurred, attempting to recreate the missing symlinks. It might be best wipe the storage to avoid further errors due to storage corruption.", lower) if err := d.recreateSymlinks(); err != nil { - return nil, fmt.Errorf("error recreating the missing symlinks: %v", err) + return nil, fmt.Errorf("recreating the missing symlinks: %v", err) } // let's call Readlink on lower again now that we have recreated the missing symlinks lp, err = os.Readlink(lower) @@ -1121,7 +1122,7 @@ func (d *Driver) recreateSymlinks() error { // List all the directories under the home directory dirs, err := ioutil.ReadDir(d.home) if err != nil { - return fmt.Errorf("error reading driver home directory %q: %v", d.home, err) + return fmt.Errorf("reading driver home directory %q: %v", d.home, err) } linksDir := filepath.Join(d.home, "l") // This makes the link directory if it doesn't exist @@ -1148,7 +1149,7 @@ func (d *Driver) recreateSymlinks() error { // Read the "link" file under each layer to get the name of the symlink data, err := ioutil.ReadFile(path.Join(d.dir(dir.Name()), "link")) if err != nil { - errs = multierror.Append(errs, errors.Wrapf(err, "error reading name of symlink for %q", dir)) + errs = multierror.Append(errs, errors.Wrapf(err, "reading name of symlink for %q", dir)) continue } linkPath := path.Join(d.home, linkDir, strings.Trim(string(data), "\n")) @@ -1162,7 +1163,7 @@ func (d *Driver) recreateSymlinks() error { } madeProgress = true } else if err != nil { - errs = multierror.Append(errs, errors.Wrapf(err, "error trying to stat %q", linkPath)) + errs = multierror.Append(errs, err) continue } } @@ -1170,7 +1171,7 @@ func (d *Driver) recreateSymlinks() error { // that each symlink we have corresponds to one. links, err := ioutil.ReadDir(linksDir) if err != nil { - errs = multierror.Append(errs, errors.Wrapf(err, "error reading links directory %q", linksDir)) + errs = multierror.Append(errs, err) continue } // Go through all of the symlinks in the "l" directory @@ -1178,7 +1179,7 @@ func (d *Driver) recreateSymlinks() error { // Read the symlink's target, which should be "../$layer/diff" target, err := os.Readlink(filepath.Join(linksDir, link.Name())) if err != nil { - errs = multierror.Append(errs, errors.Wrapf(err, "error reading target of link %q", link)) + errs = multierror.Append(errs, err) continue } targetComponents := strings.Split(target, string(os.PathSeparator)) @@ -1196,7 +1197,7 @@ func (d *Driver) recreateSymlinks() error { data, err := ioutil.ReadFile(linkFile) if err != nil || string(data) != link.Name() { if err := ioutil.WriteFile(linkFile, []byte(link.Name()), 0644); err != nil { - errs = multierror.Append(errs, errors.Wrapf(err, "error correcting link for layer %q", targetID)) + errs = multierror.Append(errs, errors.Wrapf(err, "correcting link for layer %s", targetID)) continue } madeProgress = true @@ -1241,7 +1242,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO if unshare.IsRootless() { logLevel = logrus.DebugLevel } - logrus.StandardLogger().Logf(logLevel, "ignoring metacopy option from storage.conf, not supported with booted kernel") + logrus.StandardLogger().Logf(logLevel, "Ignoring metacopy option from storage.conf, not supported with booted kernel") } } } @@ -1275,7 +1276,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO } logrus.Warnf("Can't read parent link %q because it does not exist. Going through storage to recreate the missing links.", path.Join(dir, "link")) if err := d.recreateSymlinks(); err != nil { - return "", errors.Wrap(err, "error recreating the links") + return "", errors.Wrap(err, "recreating the links") } link, err = ioutil.ReadFile(path.Join(dir, "link")) if err != nil { @@ -1330,7 +1331,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO if lower == "" && os.IsNotExist(err) { logrus.Warnf("Can't stat lower layer %q because it does not exist. Going through storage to recreate the missing symlinks.", newpath) if err := d.recreateSymlinks(); err != nil { - return "", fmt.Errorf("error recreating the missing symlinks: %v", err) + return "", fmt.Errorf("Recreating the missing symlinks: %v", err) } lower = newpath } else if lower == "" { @@ -1381,7 +1382,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO if retErr != nil { if c := d.ctr.Decrement(mergedDir); c <= 0 { if mntErr := unix.Unmount(mergedDir, 0); mntErr != nil { - logrus.Errorf("error unmounting %v: %v", mergedDir, mntErr) + logrus.Errorf("Unmounting %v: %v", mergedDir, mntErr) } } } @@ -1473,7 +1474,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO flags, data := mount.ParseOptions(mountData) logrus.Debugf("overlay: mount_data=%s", mountData) if err := mountFunc("overlay", mountTarget, "overlay", uintptr(flags), data); err != nil { - return "", fmt.Errorf("error creating overlay mount to %s, mount_data=%q: %v", mountTarget, mountData, err) + return "", fmt.Errorf("creating overlay mount to %s, mount_data=%q: %v", mountTarget, mountData, err) } return mergedDir, nil @@ -1820,7 +1821,7 @@ func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMapp err = graphdriver.ChownPathByMaps(layerFs, toContainer, toHost) if err != nil { if err2 := d.Put(id); err2 != nil { - logrus.Errorf("%v; error unmounting %v: %v", err, id, err2) + logrus.Errorf("%v; unmounting %v: %v", err, id, err2) } return err } @@ -1923,7 +1924,7 @@ func (d *Driver) releaseAdditionalLayerByID(id string) { if al, err := d.getAdditionalLayerPathByID(id); err == nil { notifyReleaseAdditionalLayer(al) } else if !os.IsNotExist(err) { - logrus.Warnf("unexpected error on reading Additional Layer Store pointer %v", err) + logrus.Warnf("Unexpected error on reading Additional Layer Store pointer %v", err) } } @@ -2004,10 +2005,10 @@ func notifyUseAdditionalLayer(al string) { } else if err == nil { f.Close() if err := os.Remove(useFile); err != nil { - logrus.Warnf("failed to remove use file") + logrus.Warnf("Failed to remove use file") } } - logrus.Warnf("unexpected error by Additional Layer Store %v during use; GC doesn't seem to be supported", err) + logrus.Warnf("Unexpected error by Additional Layer Store %v during use; GC doesn't seem to be supported", err) } // notifyReleaseAdditionalLayer notifies Additional Layer Store that we don't use the specified @@ -2024,7 +2025,7 @@ func notifyReleaseAdditionalLayer(al string) { if os.IsNotExist(err) { return } - logrus.Warnf("unexpected error by Additional Layer Store %v during release; GC doesn't seem to be supported", err) + logrus.Warnf("Unexpected error by Additional Layer Store %v during release; GC doesn't seem to be supported", err) } // redirectDiffIfAdditionalLayer checks if the passed diff path is Additional Layer and diff --git a/vendor/github.com/containers/storage/drivers/overlay/randomid.go b/vendor/github.com/containers/storage/drivers/overlay/randomid.go index fc565ef0b..736c48b9c 100644 --- a/vendor/github.com/containers/storage/drivers/overlay/randomid.go +++ b/vendor/github.com/containers/storage/drivers/overlay/randomid.go @@ -47,7 +47,7 @@ func generateID(l int) string { if retryOnError(err) && retries < maxretries { count += n retries++ - logrus.Errorf("error generating version 4 uuid, retrying: %v", err) + logrus.Errorf("Generating version 4 uuid, retrying: %v", err) continue } diff --git a/vendor/github.com/containers/storage/drivers/template.go b/vendor/github.com/containers/storage/drivers/template.go index 5d80b8865..d40d71cfc 100644 --- a/vendor/github.com/containers/storage/drivers/template.go +++ b/vendor/github.com/containers/storage/drivers/template.go @@ -31,7 +31,7 @@ func NaiveCreateFromTemplate(d TemplateDriver, id, template string, templateIDMa diff, err := d.Diff(template, templateIDMappings, parent, parentIDMappings, opts.MountLabel) if err != nil { if err2 := d.Remove(id); err2 != nil { - logrus.Errorf("error removing layer %q: %v", id, err2) + logrus.Errorf("Removing layer %q: %v", id, err2) } return err } @@ -44,7 +44,7 @@ func NaiveCreateFromTemplate(d TemplateDriver, id, template string, templateIDMa } if _, err = d.ApplyDiff(id, parent, applyOptions); err != nil { if err2 := d.Remove(id); err2 != nil { - logrus.Errorf("error removing layer %q: %v", id, err2) + logrus.Errorf("Removing layer %q: %v", id, err2) } return err } diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod index 911469182..ac7f45c3f 100644 --- a/vendor/github.com/containers/storage/go.mod +++ b/vendor/github.com/containers/storage/go.mod @@ -12,14 +12,13 @@ require ( github.com/google/go-intervals v0.0.2 github.com/google/uuid v1.2.0 // indirect github.com/hashicorp/go-multierror v1.1.1 - github.com/json-iterator/go v1.1.11 - github.com/klauspost/compress v1.13.5 + github.com/json-iterator/go v1.1.12 + github.com/klauspost/compress v1.13.6 github.com/klauspost/pgzip v1.2.5 github.com/mattn/go-shellwords v1.0.12 github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible github.com/moby/sys/mountinfo v0.4.1 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/runc v1.0.2 github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum index 5cc5da6d3..3da64ce8c 100644 --- a/vendor/github.com/containers/storage/go.sum +++ b/vendor/github.com/containers/storage/go.sum @@ -115,15 +115,16 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.5 h1:9O69jUPDcsT9fEm74W92rZL9FQY7rCdaXVneq+yyzl4= github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -148,9 +149,8 @@ github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2J github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go index 32ba20685..fbf6ad362 100644 --- a/vendor/github.com/containers/storage/layers.go +++ b/vendor/github.com/containers/storage/layers.go @@ -1557,7 +1557,7 @@ func (r *layerStore) applyDiffWithOptions(to string, layerOptions *LayerOptions, compressor = pgzip.NewWriter(&tsdata) } if err := compressor.SetConcurrency(1024*1024, 1); err != nil { // 1024*1024 is the hard-coded default; we're not changing that - logrus.Infof("error setting compression concurrency threads to 1: %v; ignoring", err) + logrus.Infof("Error setting compression concurrency threads to 1: %v; ignoring", err) } metadata := storage.NewJSONPacker(compressor) uncompressed, err := archive.DecompressStream(defragmented) diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go index 48e846f7c..76544ff28 100644 --- a/vendor/github.com/containers/storage/pkg/archive/archive.go +++ b/vendor/github.com/containers/storage/pkg/archive/archive.go @@ -879,7 +879,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) if include != relFilePath { matches, err := pm.IsMatch(relFilePath) if err != nil { - logrus.Errorf("Error matching %s: %v", relFilePath, err) + logrus.Errorf("Matching %s: %v", relFilePath, err) return err } skip = matches diff --git a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go index 7bd804c44..6efc6a4c8 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go +++ b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go @@ -345,6 +345,56 @@ func getFileDigest(f *os.File) (digest.Digest, error) { return digester.Digest(), nil } +// findFileInOSTreeRepos checks whether the requested file already exist in one of the OSTree repo and copies the file content from there if possible. +// file is the file to look for. +// ostreeRepos is a list of OSTree repos. +// dirfd is an open fd to the destination checkout. +// useHardLinks defines whether the deduplication can be performed using hard links. +func findFileInOSTreeRepos(file *internal.FileMetadata, ostreeRepos []string, dirfd int, useHardLinks bool) (bool, *os.File, int64, error) { + digest, err := digest.Parse(file.Digest) + if err != nil { + return false, nil, 0, nil + } + payloadLink := digest.Encoded() + ".payload-link" + if len(payloadLink) < 2 { + return false, nil, 0, nil + } + + for _, repo := range ostreeRepos { + sourceFile := filepath.Join(repo, "objects", payloadLink[:2], payloadLink[2:]) + st, err := os.Stat(sourceFile) + if err != nil || !st.Mode().IsRegular() { + continue + } + if st.Size() != file.Size { + continue + } + fd, err := unix.Open(sourceFile, unix.O_RDONLY|unix.O_NONBLOCK, 0) + if err != nil { + return false, nil, 0, nil + } + f := os.NewFile(uintptr(fd), "fd") + defer f.Close() + + // check if the open file can be deduplicated with hard links + if useHardLinks && !canDedupFileWithHardLink(file, fd, st) { + continue + } + + dstFile, written, err := copyFileContent(fd, file.Name, dirfd, 0, useHardLinks) + if err != nil { + return false, nil, 0, nil + } + return true, dstFile, written, nil + } + // If hard links deduplication was used and it has failed, try again without hard links. + if useHardLinks { + return findFileInOSTreeRepos(file, ostreeRepos, dirfd, false) + } + + return false, nil, 0, nil +} + // findFileOnTheHost checks whether the requested file already exist on the host and copies the file content from there if possible. // It is currently implemented to look only at the file with the same path. Ideally it can detect the same content also at different // paths. @@ -873,6 +923,9 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions) (gra // modifies the source file as well. useHardLinks := parseBooleanPullOption(&storeOpts, "use_hard_links", false) + // List of OSTree repositories to use for deduplication + ostreeRepos := strings.Split(storeOpts.PullOptions["ostree_repos"], ":") + // Generate the manifest var toc internal.TOC if err := json.Unmarshal(c.manifest, &toc); err != nil { @@ -1009,18 +1062,35 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions) (gra totalChunksSize += r.Size + finalizeFile := func(dstFile *os.File) error { + if dstFile != nil { + defer dstFile.Close() + if err := setFileAttrs(dstFile, mode, &r, options); err != nil { + return err + } + } + return nil + } + found, dstFile, _, err := findFileInOtherLayers(&r, dirfd, otherLayersCache, c.layersTarget, useHardLinks) if err != nil { return output, err } - if dstFile != nil { - if err := setFileAttrs(dstFile, mode, &r, options); err != nil { - dstFile.Close() + if found { + if err := finalizeFile(dstFile); err != nil { return output, err } - dstFile.Close() + continue + } + + found, dstFile, _, err = findFileInOSTreeRepos(&r, ostreeRepos, dirfd, useHardLinks) + if err != nil { + return output, err } if found { + if err := finalizeFile(dstFile); err != nil { + return output, err + } continue } @@ -1029,14 +1099,10 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions) (gra if err != nil { return output, err } - if dstFile != nil { - if err := setFileAttrs(dstFile, mode, &r, options); err != nil { - dstFile.Close() + if found { + if err := finalizeFile(dstFile); err != nil { return output, err } - dstFile.Close() - } - if found { continue } } diff --git a/vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go b/vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go index 9e0e97bd6..92056c1d5 100644 --- a/vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go +++ b/vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go @@ -14,7 +14,7 @@ import ( // reading it via /proc filesystem. func GetTotalUsedFds() int { if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil { - logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err) + logrus.Errorf("%v", err) } else { return len(fds) } diff --git a/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go b/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go index b224e7b5c..fc080acbe 100644 --- a/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go +++ b/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go @@ -36,7 +36,7 @@ type lockfile struct { // necessary. func openLock(path string, ro bool) (fd int, err error) { if ro { - fd, err = unix.Open(path, os.O_RDONLY|unix.O_CLOEXEC, 0) + fd, err = unix.Open(path, os.O_RDONLY|unix.O_CLOEXEC|os.O_CREATE, 0) } else { fd, err = unix.Open(path, os.O_RDWR|unix.O_CLOEXEC|os.O_CREATE, diff --git a/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go b/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go index e2cf30b41..6f0726505 100644 --- a/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go +++ b/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go @@ -43,7 +43,7 @@ func openNextAvailableLoopback(index int, sparseName string, sparseFile *os.File var st syscall.Stat_t err = syscall.Fstat(int(sparseFile.Fd()), &st) if err != nil { - logrus.Errorf("Error reading information about loopback file %s: %v", sparseName, err) + logrus.Errorf("Reading information about loopback file %s: %v", sparseName, err) return nil, ErrAttachLoopbackDevice } @@ -68,7 +68,7 @@ func openNextAvailableLoopback(index int, sparseName string, sparseFile *os.File // OpenFile adds O_CLOEXEC loopFile, err = os.OpenFile(target, os.O_RDWR, 0644) if err != nil { - logrus.Errorf("Error opening loopback device: %s", err) + logrus.Errorf("Opening loopback device: %s", err) return nil, ErrAttachLoopbackDevice } @@ -90,7 +90,7 @@ func openNextAvailableLoopback(index int, sparseName string, sparseFile *os.File // device and inode numbers. dev, ino, err := getLoopbackBackingFile(loopFile) if err != nil { - logrus.Errorf("Error getting loopback backing file: %s", err) + logrus.Errorf("Getting loopback backing file: %s", err) return nil, ErrGetLoopbackBackingFile } if dev != uint64(st.Dev) || ino != st.Ino { @@ -125,7 +125,7 @@ func AttachLoopDevice(sparseName string) (loop *os.File, err error) { // OpenFile adds O_CLOEXEC sparseFile, err := os.OpenFile(sparseName, os.O_RDWR, 0644) if err != nil { - logrus.Errorf("Error opening sparse file %s: %s", sparseName, err) + logrus.Errorf("Opening sparse file: %v", err) return nil, ErrAttachLoopbackDevice } defer sparseFile.Close() @@ -147,7 +147,7 @@ func AttachLoopDevice(sparseName string) (loop *os.File, err error) { // If the call failed, then free the loopback device if err := ioctlLoopClrFd(loopFile.Fd()); err != nil { - logrus.Error("Error while cleaning up the loopback device") + logrus.Error("While cleaning up the loopback device") } loopFile.Close() return nil, ErrAttachLoopbackDevice diff --git a/vendor/github.com/containers/storage/pkg/loopback/loopback.go b/vendor/github.com/containers/storage/pkg/loopback/loopback.go index f4cf2826e..c9be05776 100644 --- a/vendor/github.com/containers/storage/pkg/loopback/loopback.go +++ b/vendor/github.com/containers/storage/pkg/loopback/loopback.go @@ -13,7 +13,7 @@ import ( func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) { loopInfo, err := ioctlLoopGetStatus64(file.Fd()) if err != nil { - logrus.Errorf("Error get loopback backing file: %s", err) + logrus.Errorf("Get loopback backing file: %v", err) return 0, 0, ErrGetLoopbackBackingFile } return loopInfo.loDevice, loopInfo.loInode, nil @@ -22,7 +22,7 @@ func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) { // SetCapacity reloads the size for the loopback device. func SetCapacity(file *os.File) error { if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil { - logrus.Errorf("Error loopbackSetCapacity: %s", err) + logrus.Errorf("loopbackSetCapacity: %s", err) return ErrSetCapacity } return nil diff --git a/vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix.go b/vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix.go index 76e1e499f..7a68bc39b 100644 --- a/vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix.go +++ b/vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix.go @@ -35,7 +35,7 @@ func GetKernelVersion() (*VersionInfo, error) { // the given version. func CheckKernelVersion(k, major, minor int) bool { if v, err := GetKernelVersion(); err != nil { - logrus.Warnf("error getting kernel version: %s", err) + logrus.Warnf("Error getting kernel version: %s", err) } else { if CompareKernelVersion(*v, VersionInfo{Kernel: k, Major: major, Minor: minor}) < 0 { return false diff --git a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go index 26cd8504c..674e0a0ba 100644 --- a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go +++ b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go @@ -34,7 +34,7 @@ func NewLogger(logger func(*tar.Header)) (io.WriteCloser, error) { } // Make sure to avoid writes after the reader has been closed. if err := reader.Close(); err != nil { - logrus.Errorf("error closing tarlogger reader: %v", err) + logrus.Errorf("Closing tarlogger reader: %v", err) } // Unblock the Close(). t.closeMutex.Unlock() diff --git a/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go b/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go index 96b857543..6d351ce80 100644 --- a/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go +++ b/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go @@ -154,7 +154,7 @@ func (c *Cmd) Start() error { pidString := "" b := new(bytes.Buffer) if _, err := io.Copy(b, pidRead); err != nil { - return errors.Wrapf(err, "error reading child PID") + return errors.Wrapf(err, "Reading child PID") } pidString = b.String() pid, err := strconv.Atoi(pidString) @@ -188,8 +188,8 @@ func (c *Cmd) Start() error { if len(c.UidMappings) == 0 || len(c.GidMappings) == 0 { uidmap, gidmap, err := GetHostIDMappings("") if err != nil { - fmt.Fprintf(continueWrite, "error reading ID mappings in parent: %v", err) - return errors.Wrapf(err, "error reading ID mappings in parent") + fmt.Fprintf(continueWrite, "Reading ID mappings in parent: %v", err) + return errors.Wrapf(err, "Reading ID mappings in parent") } if len(c.UidMappings) == 0 { c.UidMappings = uidmap @@ -222,8 +222,8 @@ func (c *Cmd) Start() error { if err == nil { gidmapSet = true } else { - logrus.Warnf("error running newgidmap: %v: %s", err, g.String()) - logrus.Warnf("falling back to single mapping") + logrus.Warnf("Error running newgidmap: %v: %s", err, g.String()) + logrus.Warnf("Falling back to single mapping") g.Reset() g.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Getegid()))) } @@ -271,8 +271,8 @@ func (c *Cmd) Start() error { if err == nil { uidmapSet = true } else { - logrus.Warnf("error running newuidmap: %v: %s", err, u.String()) - logrus.Warnf("falling back to single mapping") + logrus.Warnf("Error running newuidmap: %v: %s", err, u.String()) + logrus.Warnf("Falling back to single mapping") u.Reset() u.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Geteuid()))) } @@ -407,7 +407,7 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) { // ID and a range size. uidmap, gidmap, err = GetSubIDMappings(me.Username, me.Username) if err != nil { - logrus.Warnf("error reading allowed ID mappings: %v", err) + logrus.Warnf("Reading allowed ID mappings: %v", err) } if len(uidmap) == 0 { logrus.Warnf("Found no UID ranges set aside for user %q in /etc/subuid.", me.Username) @@ -434,13 +434,13 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) { // If we have CAP_SYS_ADMIN, then we don't need to create a new namespace in order to be able // to use unshare(), so don't bother creating a new user namespace at this point. capabilities, err := capability.NewPid(0) - bailOnError(err, "error reading the current capabilities sets") + bailOnError(err, "Reading the current capabilities sets") if capabilities.Get(capability.EFFECTIVE, capability.CAP_SYS_ADMIN) { return } // Read the set of ID mappings that we're currently using. uidmap, gidmap, err = GetHostIDMappings("") - bailOnError(err, "error reading current ID mappings") + bailOnError(err, "Reading current ID mappings") // Just reuse them. for i := range uidmap { uidmap[i].HostID = uidmap[i].ContainerID @@ -463,7 +463,7 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) { if _, present := os.LookupEnv("BUILDAH_ISOLATION"); !present { if err = os.Setenv("BUILDAH_ISOLATION", "rootless"); err != nil { if err := os.Setenv("BUILDAH_ISOLATION", "rootless"); err != nil { - logrus.Errorf("error setting BUILDAH_ISOLATION=rootless in environment: %v", err) + logrus.Errorf("Setting BUILDAH_ISOLATION=rootless in environment: %v", err) os.Exit(1) } } @@ -483,7 +483,7 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) { cmd.GidMappingsEnableSetgroups = true // Finish up. - logrus.Debugf("running %+v with environment %+v, UID map %+v, and GID map %+v", cmd.Cmd.Args, os.Environ(), cmd.UidMappings, cmd.GidMappings) + logrus.Debugf("Running %+v with environment %+v, UID map %+v, and GID map %+v", cmd.Cmd.Args, os.Environ(), cmd.UidMappings, cmd.GidMappings) ExecRunnable(cmd, nil) } @@ -512,7 +512,7 @@ func ExecRunnable(cmd Runnable, cleanup func()) { } } logrus.Errorf("%v", err) - logrus.Errorf("(unable to determine exit status)") + logrus.Errorf("(Unable to determine exit status)") exit(1) } exit(0) @@ -523,7 +523,7 @@ func getHostIDMappings(path string) ([]specs.LinuxIDMapping, error) { var mappings []specs.LinuxIDMapping f, err := os.Open(path) if err != nil { - return nil, errors.Wrapf(err, "error reading ID mappings from %q", path) + return nil, errors.Wrapf(err, "Reading ID mappings from %q", path) } defer f.Close() scanner := bufio.NewScanner(f) @@ -571,7 +571,7 @@ func GetHostIDMappings(pid string) ([]specs.LinuxIDMapping, []specs.LinuxIDMappi func GetSubIDMappings(user, group string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) { mappings, err := idtools.NewIDMappings(user, group) if err != nil { - return nil, nil, errors.Wrapf(err, "error reading subuid mappings for user %q and subgid mappings for group %q", user, group) + return nil, nil, errors.Wrapf(err, "Reading subuid mappings for user %q and subgid mappings for group %q", user, group) } var uidmap, gidmap []specs.LinuxIDMapping for _, m := range mappings.UIDs() { diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go index 8d6f2c4d7..6f6f69807 100644 --- a/vendor/github.com/containers/storage/store.go +++ b/vendor/github.com/containers/storage/store.go @@ -1131,10 +1131,6 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, crea if options.HostGIDMapping && len(layer.GIDMap) != 0 { return false } - // If we don't care about the mapping, it's fine. - if len(options.UIDMap) == 0 && len(options.GIDMap) == 0 { - return true - } // Compare the maps. return reflect.DeepEqual(layer.UIDMap, options.UIDMap) && reflect.DeepEqual(layer.GIDMap, options.GIDMap) } diff --git a/vendor/github.com/containers/storage/types/utils.go b/vendor/github.com/containers/storage/types/utils.go index b7ab07342..4dd1a786e 100644 --- a/vendor/github.com/containers/storage/types/utils.go +++ b/vendor/github.com/containers/storage/types/utils.go @@ -87,7 +87,7 @@ func getRootlessRuntimeDirIsolated(env rootlessRuntimeDirEnvironment) (string, e if tmpPerUserDir != "" { if _, err := env.systemLstat(tmpPerUserDir); os.IsNotExist(err) { if err := os.Mkdir(tmpPerUserDir, 0700); err != nil { - logrus.Errorf("failed to create temp directory for user: %v", err) + logrus.Errorf("Failed to create temp directory for user: %v", err) } else { return tmpPerUserDir, nil } diff --git a/vendor/github.com/containers/storage/userns.go b/vendor/github.com/containers/storage/userns.go index 3ada41f73..523c92dc8 100644 --- a/vendor/github.com/containers/storage/userns.go +++ b/vendor/github.com/containers/storage/userns.go @@ -43,7 +43,7 @@ func getAdditionalSubIDs(username string) (*idSet, *idSet, error) { } mappings, err := idtools.NewIDMappings(username, username) if err != nil { - logrus.Errorf("cannot find mappings for user %q: %v", username, err) + logrus.Errorf("Cannot find mappings for user %q: %v", username, err) } else { uids = getHostIDs(mappings.UIDs()) gids = getHostIDs(mappings.GIDs()) diff --git a/vendor/github.com/klauspost/compress/LICENSE b/vendor/github.com/klauspost/compress/LICENSE index 6cd1e9627..87d557477 100644 --- a/vendor/github.com/klauspost/compress/LICENSE +++ b/vendor/github.com/klauspost/compress/LICENSE @@ -290,3 +290,15 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------- + +Files: s2/cmd/internal/filepathx/* + +Copyright 2016 The filepathx Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md index 235dc7cc6..3429879eb 100644 --- a/vendor/github.com/klauspost/compress/README.md +++ b/vendor/github.com/klauspost/compress/README.md @@ -17,12 +17,17 @@ This package provides various compression algorithms. # changelog
+* Aug 30, 2021 (v1.13.5)
+ * gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425)
+ * s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413)
+ * zstd: pooledZipWriter should return Writers to the same pool [#426](https://github.com/klauspost/compress/pull/426)
+ * Removed golang/snappy as external dependency for tests [#421](https://github.com/klauspost/compress/pull/421)
+
* Aug 12, 2021 (v1.13.4)
* Add [snappy replacement package](https://github.com/klauspost/compress/tree/master/snappy).
* zstd: Fix incorrect encoding in "best" mode [#415](https://github.com/klauspost/compress/pull/415)
* Aug 3, 2021 (v1.13.3)
-
* zstd: Improve Best compression [#404](https://github.com/klauspost/compress/pull/404)
* zstd: Fix WriteTo error forwarding [#411](https://github.com/klauspost/compress/pull/411)
* gzhttp: Return http.HandlerFunc instead of http.Handler. Unlikely breaking change. [#406](https://github.com/klauspost/compress/pull/406)
@@ -31,7 +36,6 @@ This package provides various compression algorithms. * zstd: use SpeedBestCompression for level >= 10 [#410](https://github.com/klauspost/compress/pull/410)
* Jun 14, 2021 (v1.13.1)
-
* s2: Add full Snappy output support [#396](https://github.com/klauspost/compress/pull/396)
* zstd: Add configurable [Decoder window](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithDecoderMaxWindow) size [#394](https://github.com/klauspost/compress/pull/394)
* gzhttp: Add header to skip compression [#389](https://github.com/klauspost/compress/pull/389)
@@ -64,6 +68,9 @@ This package provides various compression algorithms. * zstd: Reduce memory usage further when using [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) [#346](https://github.com/klauspost/compress/pull/346)
* s2: Fix potential problem with amd64 assembly and profilers [#349](https://github.com/klauspost/compress/pull/349)
+<details>
+ <summary>See changes prior to v1.12.1</summary>
+
* Mar 26, 2021 (v1.11.13)
* zstd: Big speedup on small dictionary encodes [#344](https://github.com/klauspost/compress/pull/344) [#345](https://github.com/klauspost/compress/pull/345)
* zstd: Add [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) encoder option [#336](https://github.com/klauspost/compress/pull/336)
@@ -118,6 +125,7 @@ This package provides various compression algorithms. * zstd: Add experimental compression [dictionaries](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) [#281](https://github.com/klauspost/compress/pull/281)
* zstd: Fix mixed Write and ReadFrom calls [#282](https://github.com/klauspost/compress/pull/282)
* inflate/gz: Limit variable shifts, ~5% faster decompression [#274](https://github.com/klauspost/compress/pull/274)
+</details>
<details>
<summary>See changes prior to v1.11.0</summary>
diff --git a/vendor/github.com/klauspost/compress/flate/fast_encoder.go b/vendor/github.com/klauspost/compress/flate/fast_encoder.go index 347ac2c90..a746eb733 100644 --- a/vendor/github.com/klauspost/compress/flate/fast_encoder.go +++ b/vendor/github.com/klauspost/compress/flate/fast_encoder.go @@ -215,24 +215,15 @@ func (e *fastGen) Reset() { func matchLen(a, b []byte) int { b = b[:len(a)] var checked int - if len(a) >= 4 { - // Try 4 bytes first - if diff := binary.LittleEndian.Uint32(a) ^ binary.LittleEndian.Uint32(b); diff != 0 { - return bits.TrailingZeros32(diff) >> 3 - } - // Switch to 8 byte matching. - checked = 4 - a = a[4:] - b = b[4:] - for len(a) >= 8 { - b = b[:len(a)] - if diff := binary.LittleEndian.Uint64(a) ^ binary.LittleEndian.Uint64(b); diff != 0 { - return checked + (bits.TrailingZeros64(diff) >> 3) - } - checked += 8 - a = a[8:] - b = b[8:] + + for len(a) >= 8 { + b = b[:len(a)] + if diff := binary.LittleEndian.Uint64(a) ^ binary.LittleEndian.Uint64(b); diff != 0 { + return checked + (bits.TrailingZeros64(diff) >> 3) } + checked += 8 + a = a[8:] + b = b[8:] } b = b[:len(a)] for i := range a { diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go index 41703bba4..9b7cc8e97 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress.go @@ -344,35 +344,241 @@ func (d *Decoder) decompress1X8Bit(dst, src []byte) ([]byte, error) { var buf [256]byte var off uint8 - shift := (8 - d.actualTableLog) & 7 - - //fmt.Printf("mask: %b, tl:%d\n", mask, d.actualTableLog) - for br.off >= 4 { - br.fillFast() - v := dt[br.peekByteFast()>>shift] - br.advance(uint8(v.entry)) - buf[off+0] = uint8(v.entry >> 8) - - v = dt[br.peekByteFast()>>shift] - br.advance(uint8(v.entry)) - buf[off+1] = uint8(v.entry >> 8) - - v = dt[br.peekByteFast()>>shift] - br.advance(uint8(v.entry)) - buf[off+2] = uint8(v.entry >> 8) - - v = dt[br.peekByteFast()>>shift] - br.advance(uint8(v.entry)) - buf[off+3] = uint8(v.entry >> 8) - - off += 4 - if off == 0 { - if len(dst)+256 > maxDecodedSize { - br.close() - return nil, ErrMaxDecodedSizeExceeded + switch d.actualTableLog { + case 8: + const shift = 8 - 8 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 7: + const shift = 8 - 7 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 6: + const shift = 8 - 6 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 5: + const shift = 8 - 5 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 4: + const shift = 8 - 4 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 3: + const shift = 8 - 3 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 2: + const shift = 8 - 2 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 1: + const shift = 8 - 1 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) } - dst = append(dst, buf[:]...) } + default: + return nil, fmt.Errorf("invalid tablelog: %d", d.actualTableLog) } if len(dst)+int(off) > maxDecodedSize { @@ -383,6 +589,8 @@ func (d *Decoder) decompress1X8Bit(dst, src []byte) ([]byte, error) { // br < 4, so uint8 is fine bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead)) + shift := (8 - d.actualTableLog) & 7 + for bitsLeft > 0 { if br.bitsRead >= 64-8 { for br.off > 0 { @@ -423,24 +631,24 @@ func (d *Decoder) decompress1X8BitExactly(dst, src []byte) ([]byte, error) { var buf [256]byte var off uint8 - const shift = 0 + const shift = 56 //fmt.Printf("mask: %b, tl:%d\n", mask, d.actualTableLog) for br.off >= 4 { br.fillFast() - v := dt[br.peekByteFast()>>shift] + v := dt[uint8(br.value>>shift)] br.advance(uint8(v.entry)) buf[off+0] = uint8(v.entry >> 8) - v = dt[br.peekByteFast()>>shift] + v = dt[uint8(br.value>>shift)] br.advance(uint8(v.entry)) buf[off+1] = uint8(v.entry >> 8) - v = dt[br.peekByteFast()>>shift] + v = dt[uint8(br.value>>shift)] br.advance(uint8(v.entry)) buf[off+2] = uint8(v.entry >> 8) - v = dt[br.peekByteFast()>>shift] + v = dt[uint8(br.value>>shift)] br.advance(uint8(v.entry)) buf[off+3] = uint8(v.entry >> 8) @@ -474,7 +682,7 @@ func (d *Decoder) decompress1X8BitExactly(dst, src []byte) ([]byte, error) { br.close() return nil, ErrMaxDecodedSizeExceeded } - v := dt[br.peekByteFast()>>shift] + v := dt[br.peekByteFast()] nBits := uint8(v.entry) br.advance(nBits) bitsLeft -= int8(nBits) @@ -709,7 +917,6 @@ func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) { shift := (8 - d.actualTableLog) & 7 const tlSize = 1 << 8 - const tlMask = tlSize - 1 single := d.dt.single[:tlSize] // Use temp table to avoid bound checks/append penalty. diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go index 426b9cac7..2c112a0ab 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go @@ -195,7 +195,6 @@ func (d *Digest) UnmarshalBinary(b []byte) error { b, d.v4 = consumeUint64(b) b, d.total = consumeUint64(b) copy(d.mem[:], b) - b = b[len(d.mem):] d.n = int(d.total % uint64(len(d.mem))) return nil } diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go index 3ddbd5c0b..0ae847f75 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go @@ -9,4 +9,4 @@ package xxhash func Sum64(b []byte) uint64 //go:noescape -func writeBlocks(*Digest, []byte) int +func writeBlocks(d *Digest, b []byte) int diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s index 2c9c5357a..be8db5bf7 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s @@ -6,7 +6,7 @@ // Register allocation: // AX h -// CX pointer to advance through b +// SI pointer to advance through b // DX n // BX loop end // R8 v1, k1 @@ -16,39 +16,39 @@ // R12 tmp // R13 prime1v // R14 prime2v -// R15 prime4v +// DI prime4v -// round reads from and advances the buffer pointer in CX. +// round reads from and advances the buffer pointer in SI. // It assumes that R13 has prime1v and R14 has prime2v. #define round(r) \ - MOVQ (CX), R12 \ - ADDQ $8, CX \ + MOVQ (SI), R12 \ + ADDQ $8, SI \ IMULQ R14, R12 \ ADDQ R12, r \ ROLQ $31, r \ IMULQ R13, r // mergeRound applies a merge round on the two registers acc and val. -// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v. +// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v. #define mergeRound(acc, val) \ IMULQ R14, val \ ROLQ $31, val \ IMULQ R13, val \ XORQ val, acc \ IMULQ R13, acc \ - ADDQ R15, acc + ADDQ DI, acc // func Sum64(b []byte) uint64 TEXT ·Sum64(SB), NOSPLIT, $0-32 // Load fixed primes. MOVQ ·prime1v(SB), R13 MOVQ ·prime2v(SB), R14 - MOVQ ·prime4v(SB), R15 + MOVQ ·prime4v(SB), DI // Load slice. - MOVQ b_base+0(FP), CX + MOVQ b_base+0(FP), SI MOVQ b_len+8(FP), DX - LEAQ (CX)(DX*1), BX + LEAQ (SI)(DX*1), BX // The first loop limit will be len(b)-32. SUBQ $32, BX @@ -65,14 +65,14 @@ TEXT ·Sum64(SB), NOSPLIT, $0-32 XORQ R11, R11 SUBQ R13, R11 - // Loop until CX > BX. + // Loop until SI > BX. blockLoop: round(R8) round(R9) round(R10) round(R11) - CMPQ CX, BX + CMPQ SI, BX JLE blockLoop MOVQ R8, AX @@ -100,16 +100,16 @@ noBlocks: afterBlocks: ADDQ DX, AX - // Right now BX has len(b)-32, and we want to loop until CX > len(b)-8. + // Right now BX has len(b)-32, and we want to loop until SI > len(b)-8. ADDQ $24, BX - CMPQ CX, BX + CMPQ SI, BX JG fourByte wordLoop: // Calculate k1. - MOVQ (CX), R8 - ADDQ $8, CX + MOVQ (SI), R8 + ADDQ $8, SI IMULQ R14, R8 ROLQ $31, R8 IMULQ R13, R8 @@ -117,18 +117,18 @@ wordLoop: XORQ R8, AX ROLQ $27, AX IMULQ R13, AX - ADDQ R15, AX + ADDQ DI, AX - CMPQ CX, BX + CMPQ SI, BX JLE wordLoop fourByte: ADDQ $4, BX - CMPQ CX, BX + CMPQ SI, BX JG singles - MOVL (CX), R8 - ADDQ $4, CX + MOVL (SI), R8 + ADDQ $4, SI IMULQ R13, R8 XORQ R8, AX @@ -138,19 +138,19 @@ fourByte: singles: ADDQ $4, BX - CMPQ CX, BX + CMPQ SI, BX JGE finalize singlesLoop: - MOVBQZX (CX), R12 - ADDQ $1, CX + MOVBQZX (SI), R12 + ADDQ $1, SI IMULQ ·prime5v(SB), R12 XORQ R12, AX ROLQ $11, AX IMULQ R13, AX - CMPQ CX, BX + CMPQ SI, BX JL singlesLoop finalize: @@ -179,13 +179,13 @@ TEXT ·writeBlocks(SB), NOSPLIT, $0-40 MOVQ ·prime2v(SB), R14 // Load slice. - MOVQ arg1_base+8(FP), CX - MOVQ arg1_len+16(FP), DX - LEAQ (CX)(DX*1), BX + MOVQ b_base+8(FP), SI + MOVQ b_len+16(FP), DX + LEAQ (SI)(DX*1), BX SUBQ $32, BX // Load vN from d. - MOVQ arg+0(FP), AX + MOVQ d+0(FP), AX MOVQ 0(AX), R8 // v1 MOVQ 8(AX), R9 // v2 MOVQ 16(AX), R10 // v3 @@ -199,7 +199,7 @@ blockLoop: round(R10) round(R11) - CMPQ CX, BX + CMPQ SI, BX JLE blockLoop // Copy vN back to d. @@ -208,8 +208,8 @@ blockLoop: MOVQ R10, 16(AX) MOVQ R11, 24(AX) - // The number of bytes written is CX minus the old base pointer. - SUBQ arg1_base+8(FP), CX - MOVQ CX, ret+32(FP) + // The number of bytes written is SI minus the old base pointer. + SUBQ b_base+8(FP), SI + MOVQ SI, ret+32(FP) RET diff --git a/vendor/github.com/mattn/go-isatty/.travis.yml b/vendor/github.com/mattn/go-isatty/.travis.yml deleted file mode 100644 index 604314dd4..000000000 --- a/vendor/github.com/mattn/go-isatty/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: go -sudo: false -go: - - 1.13.x - - tip - -before_install: - - go get -t -v ./... - -script: - - ./go.test.sh - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/mattn/go-isatty/go.mod b/vendor/github.com/mattn/go-isatty/go.mod index 605c4c221..c9a20b7f3 100644 --- a/vendor/github.com/mattn/go-isatty/go.mod +++ b/vendor/github.com/mattn/go-isatty/go.mod @@ -2,4 +2,4 @@ module github.com/mattn/go-isatty go 1.12 -require golang.org/x/sys v0.0.0-20200116001909-b77594299b42 +require golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go index 711f28808..39bbcf00f 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -1,3 +1,4 @@ +//go:build (darwin || freebsd || openbsd || netbsd || dragonfly) && !appengine // +build darwin freebsd openbsd netbsd dragonfly // +build !appengine diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go index ff714a376..31503226f 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_others.go +++ b/vendor/github.com/mattn/go-isatty/isatty_others.go @@ -1,4 +1,5 @@ -// +build appengine js nacl +//go:build appengine || js || nacl || wasm +// +build appengine js nacl wasm package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_plan9.go b/vendor/github.com/mattn/go-isatty/isatty_plan9.go index c5b6e0c08..bae7f9bb3 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_plan9.go +++ b/vendor/github.com/mattn/go-isatty/isatty_plan9.go @@ -1,3 +1,4 @@ +//go:build plan9 // +build plan9 package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go index bdd5c79a0..0c3acf2dc 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_solaris.go +++ b/vendor/github.com/mattn/go-isatty/isatty_solaris.go @@ -1,5 +1,5 @@ -// +build solaris -// +build !appengine +//go:build solaris && !appengine +// +build solaris,!appengine package isatty @@ -8,10 +8,9 @@ import ( ) // IsTerminal returns true if the given file descriptor is a terminal. -// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c +// see: https://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libc/port/gen/isatty.c func IsTerminal(fd uintptr) bool { - var termio unix.Termio - err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) + _, err := unix.IoctlGetTermio(int(fd), unix.TCGETA) return err == nil } diff --git a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go index 31a1ca973..67787657f 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go +++ b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go @@ -1,4 +1,5 @@ -// +build linux aix +//go:build (linux || aix || zos) && !appengine +// +build linux aix zos // +build !appengine package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go index 1fa869154..8e3c99171 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_windows.go +++ b/vendor/github.com/mattn/go-isatty/isatty_windows.go @@ -1,5 +1,5 @@ -// +build windows -// +build !appengine +//go:build windows && !appengine +// +build windows,!appengine package isatty @@ -76,7 +76,7 @@ func isCygwinPipeName(name string) bool { } // getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler -// since GetFileInformationByHandleEx is not avilable under windows Vista and still some old fashion +// since GetFileInformationByHandleEx is not available under windows Vista and still some old fashion // guys are using Windows XP, this is a workaround for those guys, it will also work on system from // Windows vista to 10 // see https://stackoverflow.com/a/18792477 for details diff --git a/vendor/github.com/mattn/go-isatty/renovate.json b/vendor/github.com/mattn/go-isatty/renovate.json deleted file mode 100644 index 5ae9d96b7..000000000 --- a/vendor/github.com/mattn/go-isatty/renovate.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": [ - "config:base" - ], - "postUpdateOptions": [ - "gomodTidy" - ] -} diff --git a/vendor/github.com/vishvananda/netlink/class_linux.go b/vendor/github.com/vishvananda/netlink/class_linux.go index e664ade7f..029568a3f 100644 --- a/vendor/github.com/vishvananda/netlink/class_linux.go +++ b/vendor/github.com/vishvananda/netlink/class_linux.go @@ -176,6 +176,12 @@ func classPayload(req *nl.NetlinkRequest, class Class) error { options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize()) options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab)) options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab)) + if htb.Rate >= uint64(1<<32) { + options.AddRtAttr(nl.TCA_HTB_RATE64, nl.Uint64Attr(htb.Rate)) + } + if htb.Ceil >= uint64(1<<32) { + options.AddRtAttr(nl.TCA_HTB_CEIL64, nl.Uint64Attr(htb.Ceil)) + } case "hfsc": hfsc := class.(*HfscClass) opt := nl.HfscCopt{} @@ -306,6 +312,10 @@ func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, erro htb.Quantum = opt.Quantum htb.Level = opt.Level htb.Prio = opt.Prio + case nl.TCA_HTB_RATE64: + htb.Rate = native.Uint64(datum.Value[0:8]) + case nl.TCA_HTB_CEIL64: + htb.Ceil = native.Uint64(datum.Value[0:8]) } } return detailed, nil diff --git a/vendor/github.com/vishvananda/netlink/devlink_linux.go b/vendor/github.com/vishvananda/netlink/devlink_linux.go index 29b3f8ec1..7d57080e8 100644 --- a/vendor/github.com/vishvananda/netlink/devlink_linux.go +++ b/vendor/github.com/vishvananda/netlink/devlink_linux.go @@ -27,6 +27,18 @@ type DevlinkDevice struct { Attrs DevlinkDevAttrs } +// DevlinkPort represents port and its attributes +type DevlinkPort struct { + BusName string + DeviceName string + PortIndex uint32 + PortType uint16 + NetdeviceName string + NetdevIfIndex uint32 + RdmaDeviceName string + PortFlavour uint16 +} + func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) { devices := make([]*DevlinkDevice, 0, len(msgs)) for _, m := range msgs { @@ -270,3 +282,112 @@ func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error { return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode) } + +func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error { + for _, a := range attrs { + switch a.Attr.Type { + case nl.DEVLINK_ATTR_BUS_NAME: + port.BusName = string(a.Value) + case nl.DEVLINK_ATTR_DEV_NAME: + port.DeviceName = string(a.Value) + case nl.DEVLINK_ATTR_PORT_INDEX: + port.PortIndex = native.Uint32(a.Value) + case nl.DEVLINK_ATTR_PORT_TYPE: + port.PortType = native.Uint16(a.Value) + case nl.DEVLINK_ATTR_PORT_NETDEV_NAME: + port.NetdeviceName = string(a.Value) + case nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX: + port.NetdevIfIndex = native.Uint32(a.Value) + case nl.DEVLINK_ATTR_PORT_IBDEV_NAME: + port.RdmaDeviceName = string(a.Value) + case nl.DEVLINK_ATTR_PORT_FLAVOUR: + port.PortFlavour = native.Uint16(a.Value) + } + } + return nil +} + +func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) { + ports := make([]*DevlinkPort, 0, len(msgs)) + for _, m := range msgs { + attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) + if err != nil { + return nil, err + } + port := &DevlinkPort{} + if err = port.parseAttributes(attrs); err != nil { + return nil, err + } + ports = append(ports, port) + } + return ports, nil +} + +// DevLinkGetPortList provides a pointer to devlink ports and nil error, +// otherwise returns an error code. +func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) { + f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME) + if err != nil { + return nil, err + } + msg := &nl.Genlmsg{ + Command: nl.DEVLINK_CMD_PORT_GET, + Version: nl.GENL_DEVLINK_VERSION, + } + req := h.newNetlinkRequest(int(f.ID), + unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP) + req.AddData(msg) + msgs, err := req.Execute(unix.NETLINK_GENERIC, 0) + if err != nil { + return nil, err + } + ports, err := parseDevLinkAllPortList(msgs) + if err != nil { + return nil, err + } + return ports, nil +} + +// DevLinkGetPortList provides a pointer to devlink ports and nil error, +// otherwise returns an error code. +func DevLinkGetAllPortList() ([]*DevlinkPort, error) { + return pkgHandle.DevLinkGetAllPortList() +} + +func parseDevlinkPortMsg(msgs [][]byte) (*DevlinkPort, error) { + m := msgs[0] + attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) + if err != nil { + return nil, err + } + port := &DevlinkPort{} + if err = port.parseAttributes(attrs); err != nil { + return nil, err + } + return port, nil +} + +// DevLinkGetPortByIndexprovides a pointer to devlink device and nil error, +// otherwise returns an error code. +func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) { + + _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_GET, Bus, Device) + if err != nil { + return nil, err + } + + req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex))) + + respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0) + if err != nil { + return nil, err + } + port, err := parseDevlinkPortMsg(respmsg) + return port, err +} + +// DevLinkGetPortByIndex provides a pointer to devlink portand nil error, +// otherwise returns an error code. +func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) { + return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex) +} diff --git a/vendor/github.com/vishvananda/netlink/filter_linux.go b/vendor/github.com/vishvananda/netlink/filter_linux.go index ef6fabe81..2cd46266c 100644 --- a/vendor/github.com/vishvananda/netlink/filter_linux.go +++ b/vendor/github.com/vishvananda/netlink/filter_linux.go @@ -36,6 +36,7 @@ type U32 struct { ClassId uint32 Divisor uint32 // Divisor MUST be power of 2. Hash uint32 + Link uint32 RedirIndex int Sel *TcU32Sel Actions []Action @@ -225,6 +226,9 @@ func (h *Handle) filterModify(filter Filter, flags int) error { if filter.Hash != 0 { options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash)) } + if filter.Link != 0 { + options.AddRtAttr(nl.TCA_U32_LINK, nl.Uint32Attr(filter.Link)) + } actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil) // backwards compatibility if filter.RedirIndex != 0 { @@ -666,6 +670,8 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) u32.Divisor = native.Uint32(datum.Value) case nl.TCA_U32_HASH: u32.Hash = native.Uint32(datum.Value) + case nl.TCA_U32_LINK: + u32.Link = native.Uint32(datum.Value) } } return detailed, nil diff --git a/vendor/github.com/vishvananda/netlink/handle_linux.go b/vendor/github.com/vishvananda/netlink/handle_linux.go index 26887b759..65356679d 100644 --- a/vendor/github.com/vishvananda/netlink/handle_linux.go +++ b/vendor/github.com/vishvananda/netlink/handle_linux.go @@ -21,6 +21,22 @@ type Handle struct { lookupByDump bool } +// SetSocketTimeout configures timeout for default netlink sockets +func SetSocketTimeout(to time.Duration) error { + if to < time.Microsecond { + return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond) + } + + nl.SocketTimeoutTv = unix.NsecToTimeval(to.Nanoseconds()) + return nil +} + +// GetSocketTimeout returns the timeout value used by default netlink sockets +func GetSocketTimeout() time.Duration { + nsec := unix.TimevalToNsec(nl.SocketTimeoutTv) + return time.Duration(nsec) * time.Nanosecond +} + // SupportsNetlinkFamily reports whether the passed netlink family is supported by this Handle func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool { _, ok := h.sockets[nlFamily] diff --git a/vendor/github.com/vishvananda/netlink/handle_unspecified.go b/vendor/github.com/vishvananda/netlink/handle_unspecified.go index df341f706..3a6db8137 100644 --- a/vendor/github.com/vishvananda/netlink/handle_unspecified.go +++ b/vendor/github.com/vishvananda/netlink/handle_unspecified.go @@ -237,6 +237,10 @@ func (h *Handle) RouteAdd(route *Route) error { return ErrNotImplemented } +func (h *Handle) RouteAppend(route *Route) error { + return ErrNotImplemented +} + func (h *Handle) RouteDel(route *Route) error { return ErrNotImplemented } diff --git a/vendor/github.com/vishvananda/netlink/inet_diag.go b/vendor/github.com/vishvananda/netlink/inet_diag.go index 72c1fcb59..bee391a80 100644 --- a/vendor/github.com/vishvananda/netlink/inet_diag.go +++ b/vendor/github.com/vishvananda/netlink/inet_diag.go @@ -27,4 +27,5 @@ const ( type InetDiagTCPInfoResp struct { InetDiagMsg *Socket TCPInfo *TCPInfo + TCPBBRInfo *TCPBBRInfo } diff --git a/vendor/github.com/vishvananda/netlink/ipset_linux.go b/vendor/github.com/vishvananda/netlink/ipset_linux.go index 5487fc1cc..2adc2440a 100644 --- a/vendor/github.com/vishvananda/netlink/ipset_linux.go +++ b/vendor/github.com/vishvananda/netlink/ipset_linux.go @@ -23,13 +23,15 @@ type IPSetEntry struct { // IPSetResult is the result of a dump request for a set type IPSetResult struct { - Nfgenmsg *nl.Nfgenmsg - Protocol uint8 - Revision uint8 - Family uint8 - Flags uint8 - SetName string - TypeName string + Nfgenmsg *nl.Nfgenmsg + Protocol uint8 + ProtocolMinVersion uint8 + Revision uint8 + Family uint8 + Flags uint8 + SetName string + TypeName string + Comment string HashSize uint32 NumEntries uint32 @@ -38,6 +40,7 @@ type IPSetResult struct { SizeInMemory uint32 CadtFlags uint32 Timeout *uint32 + LineNo uint32 Entries []IPSetEntry } @@ -52,7 +55,7 @@ type IpsetCreateOptions struct { } // IpsetProtocol returns the ipset protocol version from the kernel -func IpsetProtocol() (uint8, error) { +func IpsetProtocol() (uint8, uint8, error) { return pkgHandle.IpsetProtocol() } @@ -86,20 +89,20 @@ func IpsetAdd(setname string, entry *IPSetEntry) error { return pkgHandle.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry) } -// IpsetDele deletes an entry from an existing ipset. +// IpsetDel deletes an entry from an existing ipset. func IpsetDel(setname string, entry *IPSetEntry) error { return pkgHandle.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry) } -func (h *Handle) IpsetProtocol() (uint8, error) { +func (h *Handle) IpsetProtocol() (protocol uint8, minVersion uint8, err error) { req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL) msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0) if err != nil { - return 0, err + return 0, 0, err } - - return ipsetUnserialize(msgs).Protocol, nil + response := ipsetUnserialize(msgs) + return response.Protocol, response.ProtocolMinVersion, nil } func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error { @@ -112,7 +115,7 @@ func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOption req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(0))) - req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(0))) + req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(2))) // 2 == inet data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil) @@ -187,6 +190,11 @@ func (h *Handle) IpsetListAll() ([]IPSetResult, error) { func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error { req := h.newIpsetRequest(nlCmd) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname))) + + if entry.Comment != "" { + req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_COMMENT, nl.ZeroTerminated(entry.Comment))) + } + data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil) if !entry.Replace { @@ -197,7 +205,12 @@ func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout}) } if entry.MAC != nil { - data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER, entry.MAC)) + nestedData := nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NET_BYTEORDER), entry.MAC) + data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NESTED), nestedData.Serialize())) + } + if entry.IP != nil { + nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP) + data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NESTED), nestedData.Serialize())) } data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0}) @@ -249,6 +262,8 @@ func (result *IPSetResult) unserialize(msg []byte) { result.Protocol = attr.Value[0] case nl.IPSET_ATTR_SETNAME: result.SetName = nl.BytesToString(attr.Value) + case nl.IPSET_ATTR_COMMENT: + result.Comment = nl.BytesToString(attr.Value) case nl.IPSET_ATTR_TYPENAME: result.TypeName = nl.BytesToString(attr.Value) case nl.IPSET_ATTR_REVISION: @@ -261,6 +276,8 @@ func (result *IPSetResult) unserialize(msg []byte) { result.parseAttrData(attr.Value) case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED: result.parseAttrADT(attr.Value) + case nl.IPSET_ATTR_PROTOCOL_MIN: + result.ProtocolMinVersion = attr.Value[0] default: log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK) } @@ -285,6 +302,17 @@ func (result *IPSetResult) parseAttrData(data []byte) { result.SizeInMemory = attr.Uint32() case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER: result.CadtFlags = attr.Uint32() + case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED: + for nested := range nl.ParseAttributes(attr.Value) { + switch nested.Type { + case nl.IPSET_ATTR_IP | nl.NLA_F_NET_BYTEORDER: + result.Entries = append(result.Entries, IPSetEntry{IP: nested.Value}) + } + } + case nl.IPSET_ATTR_CADT_LINENO | nl.NLA_F_NET_BYTEORDER: + result.LineNo = attr.Uint32() + case nl.IPSET_ATTR_COMMENT: + result.Comment = nl.BytesToString(attr.Value) default: log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK) } @@ -316,6 +344,8 @@ func parseIPSetEntry(data []byte) (entry IPSetEntry) { entry.Packets = &val case nl.IPSET_ATTR_ETHER: entry.MAC = net.HardwareAddr(attr.Value) + case nl.IPSET_ATTR_IP: + entry.IP = net.IP(attr.Value) case nl.IPSET_ATTR_COMMENT: entry.Comment = nl.BytesToString(attr.Value) case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED: diff --git a/vendor/github.com/vishvananda/netlink/link.go b/vendor/github.com/vishvananda/netlink/link.go index e2441bd71..32ca7cd64 100644 --- a/vendor/github.com/vishvananda/netlink/link.go +++ b/vendor/github.com/vishvananda/netlink/link.go @@ -555,6 +555,27 @@ const ( BOND_ARP_VALIDATE_ALL ) +var bondArpValidateToString = map[BondArpValidate]string{ + BOND_ARP_VALIDATE_NONE: "none", + BOND_ARP_VALIDATE_ACTIVE: "active", + BOND_ARP_VALIDATE_BACKUP: "backup", + BOND_ARP_VALIDATE_ALL: "none", +} +var StringToBondArpValidateMap = map[string]BondArpValidate{ + "none": BOND_ARP_VALIDATE_NONE, + "active": BOND_ARP_VALIDATE_ACTIVE, + "backup": BOND_ARP_VALIDATE_BACKUP, + "all": BOND_ARP_VALIDATE_ALL, +} + +func (b BondArpValidate) String() string { + s, ok := bondArpValidateToString[b] + if !ok { + return fmt.Sprintf("BondArpValidate(%d)", b) + } + return s +} + // BondPrimaryReselect type type BondPrimaryReselect int @@ -565,6 +586,25 @@ const ( BOND_PRIMARY_RESELECT_FAILURE ) +var bondPrimaryReselectToString = map[BondPrimaryReselect]string{ + BOND_PRIMARY_RESELECT_ALWAYS: "always", + BOND_PRIMARY_RESELECT_BETTER: "better", + BOND_PRIMARY_RESELECT_FAILURE: "failure", +} +var StringToBondPrimaryReselectMap = map[string]BondPrimaryReselect{ + "always": BOND_PRIMARY_RESELECT_ALWAYS, + "better": BOND_PRIMARY_RESELECT_BETTER, + "failure": BOND_PRIMARY_RESELECT_FAILURE, +} + +func (b BondPrimaryReselect) String() string { + s, ok := bondPrimaryReselectToString[b] + if !ok { + return fmt.Sprintf("BondPrimaryReselect(%d)", b) + } + return s +} + // BondArpAllTargets type type BondArpAllTargets int @@ -574,6 +614,23 @@ const ( BOND_ARP_ALL_TARGETS_ALL ) +var bondArpAllTargetsToString = map[BondArpAllTargets]string{ + BOND_ARP_ALL_TARGETS_ANY: "any", + BOND_ARP_ALL_TARGETS_ALL: "all", +} +var StringToBondArpAllTargetsMap = map[string]BondArpAllTargets{ + "any": BOND_ARP_ALL_TARGETS_ANY, + "all": BOND_ARP_ALL_TARGETS_ALL, +} + +func (b BondArpAllTargets) String() string { + s, ok := bondArpAllTargetsToString[b] + if !ok { + return fmt.Sprintf("BondArpAllTargets(%d)", b) + } + return s +} + // BondFailOverMac type type BondFailOverMac int @@ -584,6 +641,25 @@ const ( BOND_FAIL_OVER_MAC_FOLLOW ) +var bondFailOverMacToString = map[BondFailOverMac]string{ + BOND_FAIL_OVER_MAC_NONE: "none", + BOND_FAIL_OVER_MAC_ACTIVE: "active", + BOND_FAIL_OVER_MAC_FOLLOW: "follow", +} +var StringToBondFailOverMacMap = map[string]BondFailOverMac{ + "none": BOND_FAIL_OVER_MAC_NONE, + "active": BOND_FAIL_OVER_MAC_ACTIVE, + "follow": BOND_FAIL_OVER_MAC_FOLLOW, +} + +func (b BondFailOverMac) String() string { + s, ok := bondFailOverMacToString[b] + if !ok { + return fmt.Sprintf("BondFailOverMac(%d)", b) + } + return s +} + // BondXmitHashPolicy type type BondXmitHashPolicy int @@ -675,6 +751,25 @@ const ( BOND_AD_SELECT_COUNT ) +var bondAdSelectToString = map[BondAdSelect]string{ + BOND_AD_SELECT_STABLE: "stable", + BOND_AD_SELECT_BANDWIDTH: "bandwidth", + BOND_AD_SELECT_COUNT: "count", +} +var StringToBondAdSelectMap = map[string]BondAdSelect{ + "stable": BOND_AD_SELECT_STABLE, + "bandwidth": BOND_AD_SELECT_BANDWIDTH, + "count": BOND_AD_SELECT_COUNT, +} + +func (b BondAdSelect) String() string { + s, ok := bondAdSelectToString[b] + if !ok { + return fmt.Sprintf("BondAdSelect(%d)", b) + } + return s +} + // BondAdInfo represents ad info for bond type BondAdInfo struct { AggregatorId int @@ -706,7 +801,7 @@ type Bond struct { AllSlavesActive int MinLinks int LpInterval int - PackersPerSlave int + PacketsPerSlave int LacpRate BondLacpRate AdSelect BondAdSelect // looking at iproute tool AdInfo can only be retrived. It can't be set. @@ -739,7 +834,7 @@ func NewLinkBond(atr LinkAttrs) *Bond { AllSlavesActive: -1, MinLinks: -1, LpInterval: -1, - PackersPerSlave: -1, + PacketsPerSlave: -1, LacpRate: -1, AdSelect: -1, AdActorSysPrio: -1, @@ -789,8 +884,10 @@ func (bond *Bond) Type() string { type BondSlaveState uint8 const ( - BondStateActive = iota // Link is active. - BondStateBackup // Link is backup. + //BondStateActive Link is active. + BondStateActive BondSlaveState = iota + //BondStateBackup Link is backup. + BondStateBackup ) func (s BondSlaveState) String() string { @@ -804,15 +901,19 @@ func (s BondSlaveState) String() string { } } -// BondSlaveState represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave +// BondSlaveMiiStatus represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave // attribute, which contains the status of MII link monitoring type BondSlaveMiiStatus uint8 const ( - BondLinkUp = iota // link is up and running. - BondLinkFail // link has just gone down. - BondLinkDown // link has been down for too long time. - BondLinkBack // link is going back. + //BondLinkUp link is up and running. + BondLinkUp BondSlaveMiiStatus = iota + //BondLinkFail link has just gone down. + BondLinkFail + //BondLinkDown link has been down for too long time. + BondLinkDown + //BondLinkBack link is going back. + BondLinkBack ) func (s BondSlaveMiiStatus) String() string { @@ -845,6 +946,30 @@ func (b *BondSlave) SlaveType() string { return "bond" } +// Geneve devices must specify RemoteIP and ID (VNI) on create +// https://github.com/torvalds/linux/blob/47ec5303d73ea344e84f46660fff693c57641386/drivers/net/geneve.c#L1209-L1223 +type Geneve struct { + LinkAttrs + ID uint32 // vni + Remote net.IP + Ttl uint8 + Tos uint8 + Dport uint16 + UdpCsum uint8 + UdpZeroCsum6Tx uint8 + UdpZeroCsum6Rx uint8 + Link uint32 + FlowBased bool +} + +func (geneve *Geneve) Attrs() *LinkAttrs { + return &geneve.LinkAttrs +} + +func (geneve *Geneve) Type() string { + return "geneve" +} + // Gretap devices must specify LocalIP and RemoteIP on create type Gretap struct { LinkAttrs @@ -1068,6 +1193,58 @@ var StringToIPoIBMode = map[string]IPoIBMode{ "connected": IPOIB_MODE_CONNECTED, } +const ( + CAN_STATE_ERROR_ACTIVE = iota + CAN_STATE_ERROR_WARNING + CAN_STATE_ERROR_PASSIVE + CAN_STATE_BUS_OFF + CAN_STATE_STOPPED + CAN_STATE_SLEEPING +) + +type Can struct { + LinkAttrs + + BitRate uint32 + SamplePoint uint32 + TimeQuanta uint32 + PropagationSegment uint32 + PhaseSegment1 uint32 + PhaseSegment2 uint32 + SyncJumpWidth uint32 + BitRatePreScaler uint32 + + Name string + TimeSegment1Min uint32 + TimeSegment1Max uint32 + TimeSegment2Min uint32 + TimeSegment2Max uint32 + SyncJumpWidthMax uint32 + BitRatePreScalerMin uint32 + BitRatePreScalerMax uint32 + BitRatePreScalerInc uint32 + + ClockFrequency uint32 + + State uint32 + + Mask uint32 + Flags uint32 + + TxError uint16 + RxError uint16 + + RestartMs uint32 +} + +func (can *Can) Attrs() *LinkAttrs { + return &can.LinkAttrs +} + +func (can *Can) Type() string { + return "can" +} + type IPoIB struct { LinkAttrs Pkey uint16 diff --git a/vendor/github.com/vishvananda/netlink/link_linux.go b/vendor/github.com/vishvananda/netlink/link_linux.go index c02fa63b8..3b959299c 100644 --- a/vendor/github.com/vishvananda/netlink/link_linux.go +++ b/vendor/github.com/vishvananda/netlink/link_linux.go @@ -34,6 +34,21 @@ const ( TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI ) +var StringToTuntapModeMap = map[string]TuntapMode{ + "tun": TUNTAP_MODE_TUN, + "tap": TUNTAP_MODE_TAP, +} + +func (ttm TuntapMode) String() string { + switch ttm { + case TUNTAP_MODE_TUN: + return "tun" + case TUNTAP_MODE_TAP: + return "tap" + } + return "unknown" +} + const ( VF_LINK_STATE_AUTO uint32 = 0 VF_LINK_STATE_ENABLE uint32 = 1 @@ -1046,8 +1061,8 @@ func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) { if bond.LpInterval >= 0 { data.AddRtAttr(nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval))) } - if bond.PackersPerSlave >= 0 { - data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PackersPerSlave))) + if bond.PacketsPerSlave >= 0 { + data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PacketsPerSlave))) } if bond.LacpRate >= 0 { data.AddRtAttr(nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate))) @@ -1404,6 +1419,8 @@ func (h *Handle) linkModify(link Link, flags int) error { data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) } + case *Geneve: + addGeneveAttrs(link, linkInfo) case *Gretap: addGretapAttrs(link, linkInfo) case *Iptun: @@ -1667,6 +1684,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { link = &Macvlan{} case "macvtap": link = &Macvtap{} + case "geneve": + link = &Geneve{} case "gretap": link = &Gretap{} case "ip6gretap": @@ -1693,6 +1712,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { link = &Tuntap{} case "ipoib": link = &IPoIB{} + case "can": + link = &Can{} default: link = &GenericLink{LinkType: linkType} } @@ -1714,6 +1735,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { parseMacvlanData(link, data) case "macvtap": parseMacvtapData(link, data) + case "geneve": + parseGeneveData(link, data) case "gretap": parseGretapData(link, data) case "ip6gretap": @@ -1742,6 +1765,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { parseTuntapData(link, data) case "ipoib": parseIPoIBData(link, data) + case "can": + parseCanData(link, data) } case nl.IFLA_INFO_SLAVE_KIND: slaveType = string(info.Value[:len(info.Value)-1]) @@ -2299,7 +2324,7 @@ func parseBondData(link Link, data []syscall.NetlinkRouteAttr) { case nl.IFLA_BOND_LP_INTERVAL: bond.LpInterval = int(native.Uint32(data[i].Value[0:4])) case nl.IFLA_BOND_PACKETS_PER_SLAVE: - bond.PackersPerSlave = int(native.Uint32(data[i].Value[0:4])) + bond.PacketsPerSlave = int(native.Uint32(data[i].Value[0:4])) case nl.IFLA_BOND_AD_LACP_RATE: bond.LacpRate = BondLacpRate(data[i].Value[0]) case nl.IFLA_BOND_AD_SELECT: @@ -2448,6 +2473,58 @@ func linkFlags(rawFlags uint32) net.Flags { return f } +func addGeneveAttrs(geneve *Geneve, linkInfo *nl.RtAttr) { + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + + if geneve.FlowBased { + // In flow based mode, no other attributes need to be configured + linkInfo.AddRtAttr(nl.IFLA_GENEVE_COLLECT_METADATA, boolAttr(geneve.FlowBased)) + return + } + + if ip := geneve.Remote; ip != nil { + if ip4 := ip.To4(); ip4 != nil { + data.AddRtAttr(nl.IFLA_GENEVE_REMOTE, ip.To4()) + } else { + data.AddRtAttr(nl.IFLA_GENEVE_REMOTE6, []byte(ip)) + } + } + + if geneve.ID != 0 { + data.AddRtAttr(nl.IFLA_GENEVE_ID, nl.Uint32Attr(geneve.ID)) + } + + if geneve.Dport != 0 { + data.AddRtAttr(nl.IFLA_GENEVE_PORT, htons(geneve.Dport)) + } + + if geneve.Ttl != 0 { + data.AddRtAttr(nl.IFLA_GENEVE_TTL, nl.Uint8Attr(geneve.Ttl)) + } + + if geneve.Tos != 0 { + data.AddRtAttr(nl.IFLA_GENEVE_TOS, nl.Uint8Attr(geneve.Tos)) + } +} + +func parseGeneveData(link Link, data []syscall.NetlinkRouteAttr) { + geneve := link.(*Geneve) + for _, datum := range data { + switch datum.Attr.Type { + case nl.IFLA_GENEVE_ID: + geneve.ID = native.Uint32(datum.Value[0:4]) + case nl.IFLA_GENEVE_REMOTE, nl.IFLA_GENEVE_REMOTE6: + geneve.Remote = datum.Value + case nl.IFLA_GENEVE_PORT: + geneve.Dport = ntohs(datum.Value[0:2]) + case nl.IFLA_GENEVE_TTL: + geneve.Ttl = uint8(datum.Value[0]) + case nl.IFLA_GENEVE_TOS: + geneve.Tos = uint8(datum.Value[0]) + } + } +} + func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) { data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) @@ -3172,6 +3249,54 @@ func parseIPoIBData(link Link, data []syscall.NetlinkRouteAttr) { } } +func parseCanData(link Link, data []syscall.NetlinkRouteAttr) { + can := link.(*Can) + for _, datum := range data { + + switch datum.Attr.Type { + case nl.IFLA_CAN_BITTIMING: + can.BitRate = native.Uint32(datum.Value) + can.SamplePoint = native.Uint32(datum.Value[4:]) + can.TimeQuanta = native.Uint32(datum.Value[8:]) + can.PropagationSegment = native.Uint32(datum.Value[12:]) + can.PhaseSegment1 = native.Uint32(datum.Value[16:]) + can.PhaseSegment2 = native.Uint32(datum.Value[20:]) + can.SyncJumpWidth = native.Uint32(datum.Value[24:]) + can.BitRatePreScaler = native.Uint32(datum.Value[28:]) + case nl.IFLA_CAN_BITTIMING_CONST: + can.Name = string(datum.Value[:16]) + can.TimeSegment1Min = native.Uint32(datum.Value[16:]) + can.TimeSegment1Max = native.Uint32(datum.Value[20:]) + can.TimeSegment2Min = native.Uint32(datum.Value[24:]) + can.TimeSegment2Max = native.Uint32(datum.Value[28:]) + can.SyncJumpWidthMax = native.Uint32(datum.Value[32:]) + can.BitRatePreScalerMin = native.Uint32(datum.Value[36:]) + can.BitRatePreScalerMax = native.Uint32(datum.Value[40:]) + can.BitRatePreScalerInc = native.Uint32(datum.Value[44:]) + case nl.IFLA_CAN_CLOCK: + can.ClockFrequency = native.Uint32(datum.Value) + case nl.IFLA_CAN_STATE: + can.State = native.Uint32(datum.Value) + case nl.IFLA_CAN_CTRLMODE: + can.Mask = native.Uint32(datum.Value) + can.Flags = native.Uint32(datum.Value[4:]) + case nl.IFLA_CAN_BERR_COUNTER: + can.TxError = native.Uint16(datum.Value) + can.RxError = native.Uint16(datum.Value[2:]) + case nl.IFLA_CAN_RESTART_MS: + can.RestartMs = native.Uint32(datum.Value) + case nl.IFLA_CAN_DATA_BITTIMING_CONST: + case nl.IFLA_CAN_RESTART: + case nl.IFLA_CAN_DATA_BITTIMING: + case nl.IFLA_CAN_TERMINATION: + case nl.IFLA_CAN_TERMINATION_CONST: + case nl.IFLA_CAN_BITRATE_CONST: + case nl.IFLA_CAN_DATA_BITRATE_CONST: + case nl.IFLA_CAN_BITRATE_MAX: + } + } +} + func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) { data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data.AddRtAttr(nl.IFLA_IPOIB_PKEY, nl.Uint16Attr(uint16(ipoib.Pkey))) diff --git a/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go b/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go index db66faaad..aa6155e21 100644 --- a/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go @@ -10,6 +10,7 @@ const ( const ( DEVLINK_CMD_GET = 1 + DEVLINK_CMD_PORT_GET = 5 DEVLINK_CMD_ESWITCH_GET = 29 DEVLINK_CMD_ESWITCH_SET = 30 ) @@ -17,9 +18,15 @@ const ( const ( DEVLINK_ATTR_BUS_NAME = 1 DEVLINK_ATTR_DEV_NAME = 2 + DEVLINK_ATTR_PORT_INDEX = 3 + DEVLINK_ATTR_PORT_TYPE = 4 + DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6 + DEVLINK_ATTR_PORT_NETDEV_NAME = 7 + DEVLINK_ATTR_PORT_IBDEV_NAME = 8 DEVLINK_ATTR_ESWITCH_MODE = 25 DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26 DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62 + DEVLINK_ATTR_PORT_FLAVOUR = 77 ) const ( @@ -38,3 +45,19 @@ const ( DEVLINK_ESWITCH_ENCAP_MODE_NONE = 0 DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1 ) + +const ( + DEVLINK_PORT_FLAVOUR_PHYSICAL = 0 + DEVLINK_PORT_FLAVOUR_CPU = 1 + DEVLINK_PORT_FLAVOUR_DSA = 2 + DEVLINK_PORT_FLAVOUR_PCI_PF = 3 + DEVLINK_PORT_FLAVOUR_PCI_VF = 4 + DEVLINK_PORT_FLAVOUR_VIRTUAL = 5 +) + +const ( + DEVLINK_PORT_TYPE_NOTSET = 0 + DEVLINK_PORT_TYPE_AUTO = 1 + DEVLINK_PORT_TYPE_ETH = 2 + DEVLINK_PORT_TYPE_IB = 3 +) diff --git a/vendor/github.com/vishvananda/netlink/nl/link_linux.go b/vendor/github.com/vishvananda/netlink/nl/link_linux.go index faee2fa03..c72cc436e 100644 --- a/vendor/github.com/vishvananda/netlink/nl/link_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/link_linux.go @@ -174,6 +174,22 @@ const ( ) const ( + IFLA_GENEVE_UNSPEC = iota + IFLA_GENEVE_ID // vni + IFLA_GENEVE_REMOTE + IFLA_GENEVE_TTL + IFLA_GENEVE_TOS + IFLA_GENEVE_PORT // destination port + IFLA_GENEVE_COLLECT_METADATA + IFLA_GENEVE_REMOTE6 + IFLA_GENEVE_UDP_CSUM + IFLA_GENEVE_UDP_ZERO_CSUM6_TX + IFLA_GENEVE_UDP_ZERO_CSUM6_RX + IFLA_GENEVE_LABEL + IFLA_GENEVE_MAX = IFLA_GENEVE_LABEL +) + +const ( IFLA_GRE_UNSPEC = iota IFLA_GRE_LINK IFLA_GRE_IFLAGS @@ -673,3 +689,23 @@ const ( IFLA_IPOIB_UMCAST IFLA_IPOIB_MAX = IFLA_IPOIB_UMCAST ) + +const ( + IFLA_CAN_UNSPEC = iota + IFLA_CAN_BITTIMING + IFLA_CAN_BITTIMING_CONST + IFLA_CAN_CLOCK + IFLA_CAN_STATE + IFLA_CAN_CTRLMODE + IFLA_CAN_RESTART_MS + IFLA_CAN_RESTART + IFLA_CAN_BERR_COUNTER + IFLA_CAN_DATA_BITTIMING + IFLA_CAN_DATA_BITTIMING_CONST + IFLA_CAN_TERMINATION + IFLA_CAN_TERMINATION_CONST + IFLA_CAN_BITRATE_CONST + IFLA_CAN_DATA_BITRATE_CONST + IFLA_CAN_BITRATE_MAX + IFLA_CAN_MAX = IFLA_CAN_BITRATE_MAX +) diff --git a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go index cef64b82e..dcd4b9469 100644 --- a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go @@ -35,6 +35,9 @@ var SupportedNlFamilies = []int{unix.NETLINK_ROUTE, unix.NETLINK_XFRM, unix.NETL var nextSeqNr uint32 +// Default netlink socket timeout, 60s +var SocketTimeoutTv = unix.Timeval{Sec: 60, Usec: 0} + // GetIPFamily returns the family type of a net.IP. func GetIPFamily(ip net.IP) int { if len(ip) <= net.IPv4len { @@ -426,6 +429,14 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro if err != nil { return nil, err } + + if err := s.SetSendTimeout(&SocketTimeoutTv); err != nil { + return nil, err + } + if err := s.SetReceiveTimeout(&SocketTimeoutTv); err != nil { + return nil, err + } + defer s.Close() } else { s.Lock() diff --git a/vendor/github.com/vishvananda/netlink/nl/parse_attr.go b/vendor/github.com/vishvananda/netlink/nl/parse_attr_linux.go index 19eb8f28e..7f49125cf 100644 --- a/vendor/github.com/vishvananda/netlink/nl/parse_attr.go +++ b/vendor/github.com/vishvananda/netlink/nl/parse_attr_linux.go @@ -3,6 +3,7 @@ package nl import ( "encoding/binary" "fmt" + "log" ) type Attribute struct { @@ -18,9 +19,20 @@ func ParseAttributes(data []byte) <-chan Attribute { i := 0 for i+4 < len(data) { length := int(native.Uint16(data[i : i+2])) + attrType := native.Uint16(data[i+2 : i+4]) + + if length < 4 { + log.Printf("attribute 0x%02x has invalid length of %d bytes", attrType, length) + break + } + + if len(data) < i+length { + log.Printf("attribute 0x%02x of length %d is truncated, only %d bytes remaining", attrType, length, len(data)-i) + break + } result <- Attribute{ - Type: native.Uint16(data[i+2 : i+4]), + Type: attrType, Value: data[i+4 : i+length], } i += rtaAlignOf(length) diff --git a/vendor/github.com/vishvananda/netlink/qdisc.go b/vendor/github.com/vishvananda/netlink/qdisc.go index 8418569ee..f594c9c21 100644 --- a/vendor/github.com/vishvananda/netlink/qdisc.go +++ b/vendor/github.com/vishvananda/netlink/qdisc.go @@ -308,13 +308,15 @@ func (qdisc *Fq) Type() string { // FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair Queuing with the CoDel AQM scheme. type FqCodel struct { QdiscAttrs - Target uint32 - Limit uint32 - Interval uint32 - ECN uint32 - Flows uint32 - Quantum uint32 - // There are some more attributes here, but support for them seems not ubiquitous + Target uint32 + Limit uint32 + Interval uint32 + ECN uint32 + Flows uint32 + Quantum uint32 + CEThreshold uint32 + DropBatchSize uint32 + MemoryLimit uint32 } func (fqcodel *FqCodel) String() string { diff --git a/vendor/github.com/vishvananda/netlink/qdisc_linux.go b/vendor/github.com/vishvananda/netlink/qdisc_linux.go index d0e1ca194..edc4b726a 100644 --- a/vendor/github.com/vishvananda/netlink/qdisc_linux.go +++ b/vendor/github.com/vishvananda/netlink/qdisc_linux.go @@ -250,7 +250,15 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error { if qdisc.Quantum > 0 { options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum)))) } - + if qdisc.CEThreshold > 0 { + options.AddRtAttr(nl.TCA_FQ_CODEL_CE_THRESHOLD, nl.Uint32Attr(qdisc.CEThreshold)) + } + if qdisc.DropBatchSize > 0 { + options.AddRtAttr(nl.TCA_FQ_CODEL_DROP_BATCH_SIZE, nl.Uint32Attr(qdisc.DropBatchSize)) + } + if qdisc.MemoryLimit > 0 { + options.AddRtAttr(nl.TCA_FQ_CODEL_MEMORY_LIMIT, nl.Uint32Attr(qdisc.MemoryLimit)) + } case *Fq: options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing)))) @@ -497,6 +505,12 @@ func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error { fqCodel.Flows = native.Uint32(datum.Value) case nl.TCA_FQ_CODEL_QUANTUM: fqCodel.Quantum = native.Uint32(datum.Value) + case nl.TCA_FQ_CODEL_CE_THRESHOLD: + fqCodel.CEThreshold = native.Uint32(datum.Value) + case nl.TCA_FQ_CODEL_DROP_BATCH_SIZE: + fqCodel.DropBatchSize = native.Uint32(datum.Value) + case nl.TCA_FQ_CODEL_MEMORY_LIMIT: + fqCodel.MemoryLimit = native.Uint32(datum.Value) } } return nil diff --git a/vendor/github.com/vishvananda/netlink/route.go b/vendor/github.com/vishvananda/netlink/route.go index b16254174..845f41808 100644 --- a/vendor/github.com/vishvananda/netlink/route.go +++ b/vendor/github.com/vishvananda/netlink/route.go @@ -27,6 +27,9 @@ type Encap interface { Equal(Encap) bool } +//Protocol describe what was the originator of the route +type RouteProtocol int + // Route represents a netlink route. type Route struct { LinkIndex int @@ -36,7 +39,7 @@ type Route struct { Src net.IP Gw net.IP MultiPath []*NexthopInfo - Protocol int + Protocol RouteProtocol Priority int Table int Type int @@ -45,6 +48,7 @@ type Route struct { MPLSDst *int NewDst Destination Encap Encap + Via Destination MTU int Window int Rtt int @@ -79,6 +83,9 @@ func (r Route) String() string { if r.Encap != nil { elems = append(elems, fmt.Sprintf("Encap: %s", r.Encap)) } + if r.Via != nil { + elems = append(elems, fmt.Sprintf("Via: %s", r.Via)) + } elems = append(elems, fmt.Sprintf("Src: %s", r.Src)) if len(r.MultiPath) > 0 { elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath)) @@ -107,6 +114,7 @@ func (r Route) Equal(x Route) bool { r.Flags == x.Flags && (r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) && (r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) && + (r.Via == x.Via || (r.Via != nil && r.Via.Equal(x.Via))) && (r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap))) } @@ -136,6 +144,7 @@ type NexthopInfo struct { Flags int NewDst Destination Encap Encap + Via Destination } func (n *NexthopInfo) String() string { @@ -147,6 +156,9 @@ func (n *NexthopInfo) String() string { if n.Encap != nil { elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap)) } + if n.Via != nil { + elems = append(elems, fmt.Sprintf("Via: %s", n.Via)) + } elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1)) elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw)) elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags())) diff --git a/vendor/github.com/vishvananda/netlink/route_linux.go b/vendor/github.com/vishvananda/netlink/route_linux.go index 4e778a417..32641cb0d 100644 --- a/vendor/github.com/vishvananda/netlink/route_linux.go +++ b/vendor/github.com/vishvananda/netlink/route_linux.go @@ -1,8 +1,11 @@ package netlink import ( + "bytes" + "encoding/binary" "fmt" "net" + "strconv" "strings" "syscall" @@ -21,6 +24,23 @@ const ( SCOPE_NOWHERE Scope = unix.RT_SCOPE_NOWHERE ) +func (s Scope) String() string { + switch s { + case SCOPE_UNIVERSE: + return "universe" + case SCOPE_SITE: + return "site" + case SCOPE_LINK: + return "link" + case SCOPE_HOST: + return "host" + case SCOPE_NOWHERE: + return "nowhere" + default: + return "unknown" + } +} + const ( RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota) RT_FILTER_SCOPE @@ -446,6 +466,62 @@ func (e *SEG6LocalEncap) Equal(x Encap) bool { return true } +type Via struct { + AddrFamily int + Addr net.IP +} + +func (v *Via) Equal(x Destination) bool { + o, ok := x.(*Via) + if !ok { + return false + } + if v.AddrFamily == x.Family() && v.Addr.Equal(o.Addr) { + return true + } + return false +} + +func (v *Via) String() string { + return fmt.Sprintf("Family: %d, Address: %s", v.AddrFamily, v.Addr.String()) +} + +func (v *Via) Family() int { + return v.AddrFamily +} + +func (v *Via) Encode() ([]byte, error) { + buf := &bytes.Buffer{} + err := binary.Write(buf, native, uint16(v.AddrFamily)) + if err != nil { + return nil, err + } + err = binary.Write(buf, native, v.Addr) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func (v *Via) Decode(b []byte) error { + native := nl.NativeEndian() + if len(b) < 6 { + return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b)) + } + v.AddrFamily = int(native.Uint16(b[0:2])) + if v.AddrFamily == nl.FAMILY_V4 { + v.Addr = net.IP(b[2:6]) + return nil + } else if v.AddrFamily == nl.FAMILY_V6 { + if len(b) < 18 { + return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b)) + } + v.Addr = net.IP(b[2:]) + return nil + } + return fmt.Errorf("decoding failed: address family %d unknown", v.AddrFamily) +} + // RouteAdd will add a route to the system. // Equivalent to: `ip route add $route` func RouteAdd(route *Route) error { @@ -460,6 +536,32 @@ func (h *Handle) RouteAdd(route *Route) error { return h.routeHandle(route, req, nl.NewRtMsg()) } +// RouteAppend will append a route to the system. +// Equivalent to: `ip route append $route` +func RouteAppend(route *Route) error { + return pkgHandle.RouteAppend(route) +} + +// RouteAppend will append a route to the system. +// Equivalent to: `ip route append $route` +func (h *Handle) RouteAppend(route *Route) error { + flags := unix.NLM_F_CREATE | unix.NLM_F_APPEND | unix.NLM_F_ACK + req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags) + return h.routeHandle(route, req, nl.NewRtMsg()) +} + +// RouteAddEcmp will add a route to the system. +func RouteAddEcmp(route *Route) error { + return pkgHandle.RouteAddEcmp(route) +} + +// RouteAddEcmp will add a route to the system. +func (h *Handle) RouteAddEcmp(route *Route) error { + flags := unix.NLM_F_CREATE | unix.NLM_F_ACK + req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags) + return h.routeHandle(route, req, nl.NewRtMsg()) +} + // RouteReplace will add a route to the system. // Equivalent to: `ip route replace $route` func RouteReplace(route *Route) error { @@ -567,6 +669,14 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData)) } + if route.Via != nil { + buf, err := route.Via.Encode() + if err != nil { + return fmt.Errorf("failed to encode RTA_VIA: %v", err) + } + rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_VIA, buf)) + } + if len(route.MultiPath) > 0 { buf := []byte{} for _, nh := range route.MultiPath { @@ -609,6 +719,13 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg } children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf)) } + if nh.Via != nil { + buf, err := nh.Via.Encode() + if err != nil { + return err + } + children = append(children, nl.NewRtAttr(unix.RTA_VIA, buf)) + } rtnh.Children = children buf = append(buf, rtnh.Serialize()...) } @@ -834,7 +951,7 @@ func deserializeRoute(m []byte) (Route, error) { } route := Route{ Scope: Scope(msg.Scope), - Protocol: int(msg.Protocol), + Protocol: RouteProtocol(int(msg.Protocol)), Table: int(msg.Table), Type: int(msg.Type), Tos: int(msg.Tos), @@ -907,6 +1024,12 @@ func deserializeRoute(m []byte) (Route, error) { encapType = attr case unix.RTA_ENCAP: encap = attr + case unix.RTA_VIA: + d := &Via{} + if err := d.Decode(attr.Value); err != nil { + return nil, nil, err + } + info.Via = d } } @@ -944,6 +1067,12 @@ func deserializeRoute(m []byte) (Route, error) { return route, err } route.NewDst = d + case unix.RTA_VIA: + v := &Via{} + if err := v.Decode(attr.Value); err != nil { + return route, err + } + route.Via = v case unix.RTA_ENCAP_TYPE: encapType = attr case unix.RTA_ENCAP: @@ -1022,6 +1151,7 @@ func deserializeRoute(m []byte) (Route, error) { // RouteGetWithOptions type RouteGetOptions struct { VrfName string + SrcAddr net.IP } // RouteGetWithOptions gets a route to a specific destination from the host system. @@ -1053,23 +1183,40 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption msg := &nl.RtMsg{} msg.Family = uint8(family) msg.Dst_len = bitlen + if options != nil && options.SrcAddr != nil { + msg.Src_len = bitlen + } + msg.Flags = unix.RTM_F_LOOKUP_TABLE req.AddData(msg) rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData) req.AddData(rtaDst) if options != nil { - link, err := LinkByName(options.VrfName) - if err != nil { - return nil, err + if options.VrfName != "" { + link, err := LinkByName(options.VrfName) + if err != nil { + return nil, err + } + var ( + b = make([]byte, 4) + native = nl.NativeEndian() + ) + native.PutUint32(b, uint32(link.Attrs().Index)) + + req.AddData(nl.NewRtAttr(unix.RTA_OIF, b)) } - var ( - b = make([]byte, 4) - native = nl.NativeEndian() - ) - native.PutUint32(b, uint32(link.Attrs().Index)) - req.AddData(nl.NewRtAttr(unix.RTA_OIF, b)) + if options.SrcAddr != nil { + var srcAddr []byte + if family == FAMILY_V4 { + srcAddr = options.SrcAddr.To4() + } else { + srcAddr = options.SrcAddr.To16() + } + + req.AddData(nl.NewRtAttr(unix.RTA_SRC, srcAddr)) + } } msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE) @@ -1190,3 +1337,54 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done < return nil } + +func (p RouteProtocol) String() string { + switch int(p) { + case unix.RTPROT_BABEL: + return "babel" + case unix.RTPROT_BGP: + return "bgp" + case unix.RTPROT_BIRD: + return "bird" + case unix.RTPROT_BOOT: + return "boot" + case unix.RTPROT_DHCP: + return "dhcp" + case unix.RTPROT_DNROUTED: + return "dnrouted" + case unix.RTPROT_EIGRP: + return "eigrp" + case unix.RTPROT_GATED: + return "gated" + case unix.RTPROT_ISIS: + return "isis" + //case unix.RTPROT_KEEPALIVED: + // return "keepalived" + case unix.RTPROT_KERNEL: + return "kernel" + case unix.RTPROT_MROUTED: + return "mrouted" + case unix.RTPROT_MRT: + return "mrt" + case unix.RTPROT_NTK: + return "ntk" + case unix.RTPROT_OSPF: + return "ospf" + case unix.RTPROT_RA: + return "ra" + case unix.RTPROT_REDIRECT: + return "redirect" + case unix.RTPROT_RIP: + return "rip" + case unix.RTPROT_STATIC: + return "static" + case unix.RTPROT_UNSPEC: + return "unspec" + case unix.RTPROT_XORP: + return "xorp" + case unix.RTPROT_ZEBRA: + return "zebra" + default: + return strconv.Itoa(int(p)) + } +} diff --git a/vendor/github.com/vishvananda/netlink/route_unspecified.go b/vendor/github.com/vishvananda/netlink/route_unspecified.go index 2701862b4..db7372689 100644 --- a/vendor/github.com/vishvananda/netlink/route_unspecified.go +++ b/vendor/github.com/vishvananda/netlink/route_unspecified.go @@ -2,6 +2,8 @@ package netlink +import "strconv" + func (r *Route) ListFlags() []string { return []string{} } @@ -9,3 +11,11 @@ func (r *Route) ListFlags() []string { func (n *NexthopInfo) ListFlags() []string { return []string{} } + +func (s Scope) String() string { + return "unknown" +} + +func (p RouteProtocol) String() string { + return strconv.Itoa(int(p)) +} diff --git a/vendor/github.com/vishvananda/netlink/socket_linux.go b/vendor/github.com/vishvananda/netlink/socket_linux.go index e4e7f7ac3..9b0f4a081 100644 --- a/vendor/github.com/vishvananda/netlink/socket_linux.go +++ b/vendor/github.com/vishvananda/netlink/socket_linux.go @@ -184,7 +184,7 @@ func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) { req.AddData(&socketRequest{ Family: family, Protocol: unix.IPPROTO_TCP, - Ext: INET_DIAG_INFO, + Ext: (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)), States: uint32(0xfff), // All TCP states }) s.Send(req) @@ -220,19 +220,42 @@ loop: if err != nil { return nil, err } - var tcpInfo *TCPInfo - for _, a := range attrs { - if a.Attr.Type == INET_DIAG_INFO { - tcpInfo = &TCPInfo{} - if err := tcpInfo.deserialize(a.Value); err != nil { - return nil, err - } - break - } + + res, err := attrsToInetDiagTCPInfoResp(attrs, sockInfo) + if err != nil { + return nil, err } - r := &InetDiagTCPInfoResp{InetDiagMsg: sockInfo, TCPInfo: tcpInfo} - result = append(result, r) + + result = append(result, res) } } return result, nil } + +func attrsToInetDiagTCPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagTCPInfoResp, error) { + var tcpInfo *TCPInfo + var tcpBBRInfo *TCPBBRInfo + for _, a := range attrs { + if a.Attr.Type == INET_DIAG_INFO { + tcpInfo = &TCPInfo{} + if err := tcpInfo.deserialize(a.Value); err != nil { + return nil, err + } + continue + } + + if a.Attr.Type == INET_DIAG_BBRINFO { + tcpBBRInfo = &TCPBBRInfo{} + if err := tcpBBRInfo.deserialize(a.Value); err != nil { + return nil, err + } + continue + } + } + + return &InetDiagTCPInfoResp{ + InetDiagMsg: sockInfo, + TCPInfo: tcpInfo, + TCPBBRInfo: tcpBBRInfo, + }, nil +} diff --git a/vendor/github.com/vishvananda/netlink/tcp.go b/vendor/github.com/vishvananda/netlink/tcp.go index 4a42ee5a6..23ca014d4 100644 --- a/vendor/github.com/vishvananda/netlink/tcp.go +++ b/vendor/github.com/vishvananda/netlink/tcp.go @@ -16,3 +16,69 @@ const ( TCP_NEW_SYN_REC TCP_MAX_STATES ) + +type TCPInfo struct { + State uint8 + Ca_state uint8 + Retransmits uint8 + Probes uint8 + Backoff uint8 + Options uint8 + Snd_wscale uint8 // no uint4 + Rcv_wscale uint8 + Delivery_rate_app_limited uint8 + Fastopen_client_fail uint8 + Rto uint32 + Ato uint32 + Snd_mss uint32 + Rcv_mss uint32 + Unacked uint32 + Sacked uint32 + Lost uint32 + Retrans uint32 + Fackets uint32 + Last_data_sent uint32 + Last_ack_sent uint32 + Last_data_recv uint32 + Last_ack_recv uint32 + Pmtu uint32 + Rcv_ssthresh uint32 + Rtt uint32 + Rttvar uint32 + Snd_ssthresh uint32 + Snd_cwnd uint32 + Advmss uint32 + Reordering uint32 + Rcv_rtt uint32 + Rcv_space uint32 + Total_retrans uint32 + Pacing_rate uint64 + Max_pacing_rate uint64 + Bytes_acked uint64 /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ + Bytes_received uint64 /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ + Segs_out uint32 /* RFC4898 tcpEStatsPerfSegsOut */ + Segs_in uint32 /* RFC4898 tcpEStatsPerfSegsIn */ + Notsent_bytes uint32 + Min_rtt uint32 + Data_segs_in uint32 /* RFC4898 tcpEStatsDataSegsIn */ + Data_segs_out uint32 /* RFC4898 tcpEStatsDataSegsOut */ + Delivery_rate uint64 + Busy_time uint64 /* Time (usec) busy sending data */ + Rwnd_limited uint64 /* Time (usec) limited by receive window */ + Sndbuf_limited uint64 /* Time (usec) limited by send buffer */ + Delivered uint32 + Delivered_ce uint32 + Bytes_sent uint64 /* RFC4898 tcpEStatsPerfHCDataOctetsOut */ + Bytes_retrans uint64 /* RFC4898 tcpEStatsPerfOctetsRetrans */ + Dsack_dups uint32 /* RFC4898 tcpEStatsStackDSACKDups */ + Reord_seen uint32 /* reordering events seen */ + Rcv_ooopack uint32 /* Out-of-order packets received */ + Snd_wnd uint32 /* peer's advertised receive window after * scaling (bytes) */ +} + +type TCPBBRInfo struct { + BBRBW uint64 + BBRMinRTT uint32 + BBRPacingGain uint32 + BBRCwndGain uint32 +} diff --git a/vendor/github.com/vishvananda/netlink/tcp_linux.go b/vendor/github.com/vishvananda/netlink/tcp_linux.go index 741ea1655..293858738 100644 --- a/vendor/github.com/vishvananda/netlink/tcp_linux.go +++ b/vendor/github.com/vishvananda/netlink/tcp_linux.go @@ -2,67 +2,13 @@ package netlink import ( "bytes" + "errors" "io" ) -type TCPInfo struct { - State uint8 - Ca_state uint8 - Retransmits uint8 - Probes uint8 - Backoff uint8 - Options uint8 - Snd_wscale uint8 // no uint4 - Rcv_wscale uint8 - Delivery_rate_app_limited uint8 - Fastopen_client_fail uint8 - Rto uint32 - Ato uint32 - Snd_mss uint32 - Rcv_mss uint32 - Unacked uint32 - Sacked uint32 - Lost uint32 - Retrans uint32 - Fackets uint32 - Last_data_sent uint32 - Last_ack_sent uint32 - Last_data_recv uint32 - Last_ack_recv uint32 - Pmtu uint32 - Rcv_ssthresh uint32 - Rtt uint32 - Rttvar uint32 - Snd_ssthresh uint32 - Snd_cwnd uint32 - Advmss uint32 - Reordering uint32 - Rcv_rtt uint32 - Rcv_space uint32 - Total_retrans uint32 - Pacing_rate uint64 - Max_pacing_rate uint64 - Bytes_acked uint64 /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ - Bytes_received uint64 /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ - Segs_out uint32 /* RFC4898 tcpEStatsPerfSegsOut */ - Segs_in uint32 /* RFC4898 tcpEStatsPerfSegsIn */ - Notsent_bytes uint32 - Min_rtt uint32 - Data_segs_in uint32 /* RFC4898 tcpEStatsDataSegsIn */ - Data_segs_out uint32 /* RFC4898 tcpEStatsDataSegsOut */ - Delivery_rate uint64 - Busy_time uint64 /* Time (usec) busy sending data */ - Rwnd_limited uint64 /* Time (usec) limited by receive window */ - Sndbuf_limited uint64 /* Time (usec) limited by send buffer */ - Delivered uint32 - Delivered_ce uint32 - Bytes_sent uint64 /* RFC4898 tcpEStatsPerfHCDataOctetsOut */ - Bytes_retrans uint64 /* RFC4898 tcpEStatsPerfOctetsRetrans */ - Dsack_dups uint32 /* RFC4898 tcpEStatsStackDSACKDups */ - Reord_seen uint32 /* reordering events seen */ - Rcv_ooopack uint32 /* Out-of-order packets received */ - Snd_wnd uint32 /* peer's advertised receive window after * scaling (bytes) */ -} +const ( + tcpBBRInfoLen = 20 +) func checkDeserErr(err error) error { if err == io.EOF { @@ -391,3 +337,17 @@ func (t *TCPInfo) deserialize(b []byte) error { t.Snd_wnd = native.Uint32(next) return nil } + +func (t *TCPBBRInfo) deserialize(b []byte) error { + if len(b) != tcpBBRInfoLen { + return errors.New("Invalid length") + } + + rb := bytes.NewBuffer(b) + t.BBRBW = native.Uint64(rb.Next(8)) + t.BBRMinRTT = native.Uint32(rb.Next(4)) + t.BBRPacingGain = native.Uint32(rb.Next(4)) + t.BBRCwndGain = native.Uint32(rb.Next(4)) + + return nil +} diff --git a/vendor/github.com/vishvananda/netlink/xfrm_policy.go b/vendor/github.com/vishvananda/netlink/xfrm_policy.go index 6219d2772..b7532b092 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_policy.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_policy.go @@ -58,12 +58,13 @@ func (a PolicyAction) String() string { // policy. These rules are matched with XfrmState to determine encryption // and authentication algorithms. type XfrmPolicyTmpl struct { - Dst net.IP - Src net.IP - Proto Proto - Mode Mode - Spi int - Reqid int + Dst net.IP + Src net.IP + Proto Proto + Mode Mode + Spi int + Reqid int + Optional int } func (t XfrmPolicyTmpl) String() string { diff --git a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go index a4e132ef5..694bd74e6 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go @@ -79,6 +79,7 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error { userTmpl.XfrmId.Spi = nl.Swap32(uint32(tmpl.Spi)) userTmpl.Mode = uint8(tmpl.Mode) userTmpl.Reqid = uint32(tmpl.Reqid) + userTmpl.Optional = uint8(tmpl.Optional) userTmpl.Aalgos = ^uint32(0) userTmpl.Ealgos = ^uint32(0) userTmpl.Calgos = ^uint32(0) @@ -247,6 +248,7 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) { resTmpl.Mode = Mode(tmpl.Mode) resTmpl.Spi = int(nl.Swap32(tmpl.XfrmId.Spi)) resTmpl.Reqid = int(tmpl.Reqid) + resTmpl.Optional = int(tmpl.Optional) policy.Tmpls = append(policy.Tmpls, resTmpl) } case nl.XFRMA_MARK: diff --git a/vendor/github.com/vishvananda/netlink/xfrm_state.go b/vendor/github.com/vishvananda/netlink/xfrm_state.go index 483d8934a..19df82c76 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_state.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_state.go @@ -94,7 +94,7 @@ type XfrmState struct { Limits XfrmStateLimits Statistics XfrmStateStats Mark *XfrmMark - OutputMark int + OutputMark *XfrmMark Ifid int Auth *XfrmStateAlgo Crypt *XfrmStateAlgo @@ -104,7 +104,7 @@ type XfrmState struct { } func (sa XfrmState) String() string { - return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, OutputMark: %d, Ifid: %d, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t", + return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, OutputMark: %v, Ifid: %d, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t", sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.OutputMark, sa.Ifid, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN) } func (sa XfrmState) Print(stats bool) string { diff --git a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go index 66c99423c..5b1b6c31a 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go @@ -158,9 +158,13 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error { out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow)) req.AddData(out) } - if state.OutputMark != 0 { - out := nl.NewRtAttr(nl.XFRMA_OUTPUT_MARK, nl.Uint32Attr(uint32(state.OutputMark))) + if state.OutputMark != nil { + out := nl.NewRtAttr(nl.XFRMA_SET_MARK, nl.Uint32Attr(state.OutputMark.Value)) req.AddData(out) + if state.OutputMark.Mask != 0 { + out = nl.NewRtAttr(nl.XFRMA_SET_MARK_MASK, nl.Uint32Attr(state.OutputMark.Mask)) + req.AddData(out) + } } ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid))) @@ -377,8 +381,19 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) { state.Mark = new(XfrmMark) state.Mark.Value = mark.Value state.Mark.Mask = mark.Mask - case nl.XFRMA_OUTPUT_MARK: - state.OutputMark = int(native.Uint32(attr.Value)) + case nl.XFRMA_SET_MARK: + if state.OutputMark == nil { + state.OutputMark = new(XfrmMark) + } + state.OutputMark.Value = native.Uint32(attr.Value) + case nl.XFRMA_SET_MARK_MASK: + if state.OutputMark == nil { + state.OutputMark = new(XfrmMark) + } + state.OutputMark.Mask = native.Uint32(attr.Value) + if state.OutputMark.Mask == 0xffffffff { + state.OutputMark.Mask = 0 + } case nl.XFRMA_IF_ID: state.Ifid = int(native.Uint32(attr.Value)) } diff --git a/vendor/github.com/vishvananda/netns/README.md b/vendor/github.com/vishvananda/netns/README.md index 6b45cfb89..1fdb2d3e4 100644 --- a/vendor/github.com/vishvananda/netns/README.md +++ b/vendor/github.com/vishvananda/netns/README.md @@ -48,3 +48,14 @@ func main() { } ``` + +## NOTE + +The library can be safely used only with Go >= 1.10 due to [golang/go#20676](https://github.com/golang/go/issues/20676). + +After locking a goroutine to its current OS thread with `runtime.LockOSThread()` +and changing its network namespace, any new subsequent goroutine won't be +scheduled on that thread while it's locked. Therefore, the new goroutine +will run in a different namespace leading to unexpected results. + +See [here](https://www.weave.works/blog/linux-namespaces-golang-followup) for more details. diff --git a/vendor/github.com/vishvananda/netns/netns_linux.go b/vendor/github.com/vishvananda/netns/netns_linux.go index c76acd087..36e64906b 100644 --- a/vendor/github.com/vishvananda/netns/netns_linux.go +++ b/vendor/github.com/vishvananda/netns/netns_linux.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,go1.10 package netns @@ -218,12 +218,18 @@ func getPidForContainer(id string) (int, error) { filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"), // Even more recent docker versions under cgroup/systemd/docker/<id>/ filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"), - // Kubernetes with docker and CNI is even more different + // Kubernetes with docker and CNI is even more different. Works for BestEffort and Burstable QoS filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, "tasks"), - // Another flavor of containers location in recent kubernetes 1.11+ - filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"), - // When runs inside of a container with recent kubernetes 1.11+ - filepath.Join(cgroupRoot, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"), + // Same as above but for Guaranteed QoS + filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "pod*", id, "tasks"), + // Another flavor of containers location in recent kubernetes 1.11+. Works for BestEffort and Burstable QoS + filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", "tasks"), + // Same as above but for Guaranteed QoS + filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "*", "docker-"+id+".scope", "tasks"), + // When runs inside of a container with recent kubernetes 1.11+. Works for BestEffort and Burstable QoS + filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", "tasks"), + // Same as above but for Guaranteed QoS + filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", "tasks"), } var filename string diff --git a/vendor/k8s.io/apimachinery/third_party/forked/golang/LICENSE b/vendor/k8s.io/apimachinery/third_party/forked/golang/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/vendor/k8s.io/apimachinery/third_party/forked/golang/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/k8s.io/apimachinery/third_party/forked/golang/PATENTS b/vendor/k8s.io/apimachinery/third_party/forked/golang/PATENTS new file mode 100644 index 000000000..733099041 --- /dev/null +++ b/vendor/k8s.io/apimachinery/third_party/forked/golang/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/modules.txt b/vendor/modules.txt index 5e82b9977..1927f8285 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -45,7 +45,7 @@ github.com/blang/semver github.com/buger/goterm # github.com/cespare/xxhash/v2 v2.1.1 github.com/cespare/xxhash/v2 -# github.com/checkpoint-restore/checkpointctl v0.0.0-20210301084134-a2024f5584e7 +# github.com/checkpoint-restore/checkpointctl v0.0.0-20210922093614-c31748bec9f2 github.com/checkpoint-restore/checkpointctl/lib # github.com/checkpoint-restore/go-criu/v5 v5.1.0 github.com/checkpoint-restore/go-criu/v5 @@ -66,15 +66,18 @@ github.com/containerd/containerd/sys # github.com/containerd/stargz-snapshotter/estargz v0.8.0 github.com/containerd/stargz-snapshotter/estargz github.com/containerd/stargz-snapshotter/estargz/errorutil -# github.com/containernetworking/cni v0.8.1 +# github.com/containernetworking/cni v1.0.1 github.com/containernetworking/cni/libcni github.com/containernetworking/cni/pkg/invoke github.com/containernetworking/cni/pkg/types github.com/containernetworking/cni/pkg/types/020 -github.com/containernetworking/cni/pkg/types/current +github.com/containernetworking/cni/pkg/types/040 +github.com/containernetworking/cni/pkg/types/100 +github.com/containernetworking/cni/pkg/types/create +github.com/containernetworking/cni/pkg/types/internal github.com/containernetworking/cni/pkg/utils github.com/containernetworking/cni/pkg/version -# github.com/containernetworking/plugins v0.9.1 +# github.com/containernetworking/plugins v1.0.1 github.com/containernetworking/plugins/pkg/ns # github.com/containers/buildah v1.23.0 github.com/containers/buildah @@ -94,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.20210920093543-bf187ada7d0e +# 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 @@ -191,7 +194,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7 github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils/keyprovider -# github.com/containers/psgo v1.6.0 +# github.com/containers/psgo v1.7.1 github.com/containers/psgo github.com/containers/psgo/internal/capabilities github.com/containers/psgo/internal/cgroups @@ -199,7 +202,7 @@ github.com/containers/psgo/internal/dev github.com/containers/psgo/internal/host github.com/containers/psgo/internal/proc github.com/containers/psgo/internal/process -# github.com/containers/storage v1.36.0 +# github.com/containers/storage v1.36.1-0.20210929132900-162a0bf730ce github.com/containers/storage github.com/containers/storage/drivers github.com/containers/storage/drivers/aufs @@ -402,7 +405,7 @@ github.com/json-iterator/go # github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a github.com/juju/ansiterm github.com/juju/ansiterm/tabwriter -# github.com/klauspost/compress v1.13.5 +# github.com/klauspost/compress v1.13.6 github.com/klauspost/compress github.com/klauspost/compress/flate github.com/klauspost/compress/fse @@ -420,7 +423,7 @@ github.com/manifoldco/promptui/list github.com/manifoldco/promptui/screenbuf # github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-colorable -# github.com/mattn/go-isatty v0.0.12 +# github.com/mattn/go-isatty v0.0.14 github.com/mattn/go-isatty # github.com/mattn/go-runewidth v0.0.13 github.com/mattn/go-runewidth @@ -614,10 +617,10 @@ github.com/vbauerster/mpb/v7 github.com/vbauerster/mpb/v7/cwriter github.com/vbauerster/mpb/v7/decor github.com/vbauerster/mpb/v7/internal -# github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 +# github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 github.com/vishvananda/netlink github.com/vishvananda/netlink/nl -# github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae +# github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f github.com/vishvananda/netns # github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b github.com/xeipuuv/gojsonpointer @@ -797,10 +800,10 @@ gopkg.in/tomb.v1 gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 -# k8s.io/api v0.22.1 +# k8s.io/api v0.22.2 k8s.io/api/apps/v1 k8s.io/api/core/v1 -# k8s.io/apimachinery v0.22.1 +# k8s.io/apimachinery v0.22.2 k8s.io/apimachinery/pkg/api/resource k8s.io/apimachinery/pkg/apis/meta/v1 k8s.io/apimachinery/pkg/conversion |