diff options
204 files changed, 4241 insertions, 2012 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 324fd32f6..fe00974b3 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -7,9 +7,11 @@ env: #### # Name of the ultimate destination branch for this CI run, PR or post-merge. DEST_BRANCH: "main" + # Sane (default) value for GOPROXY and GOSUMDB. + GOPROXY: "https://proxy.golang.org,direct" + GOSUMDB: "sum.golang.org" # Overrides default location (/tmp/cirrus) for repo clone GOPATH: &gopath "/var/tmp/go" - GOBIN: "${GOPATH}/bin" GOCACHE: "${GOPATH}/cache" GOSRC: &gosrc "/var/tmp/go/src/github.com/containers/podman" CIRRUS_WORKING_DIR: *gosrc @@ -695,7 +697,7 @@ image_build_task: &image-build # this task to a specific Cirrus-Cron entry with this name. only_if: $CIRRUS_CRON == 'multiarch' depends_on: - - ext_svc_check + - build timeout_in: 120m # emulation is sssllllooooowwww gce_instance: <<: *standardvm @@ -712,22 +714,24 @@ image_build_task: &image-build - env: CTXDIR: contrib/hello env: + DISTRO_NV: "${FEDORA_NAME}" # Required for repo cache extraction PODMAN_USERNAME: ENCRYPTED[b9f0f2550029dd2196e086d9dd6c2d1fec7e328630b15990d9bb610f9fcccb5baab8b64a8c3e72b0c1d0f5917cf65aa1] PODMAN_PASSWORD: ENCRYPTED[e3444f6072853f0c8db7f964ead5e2204116af485469fa0de367f26b9316b460fd842a9882f552b9e9a83bbaf650d8b4] CONTAINERS_USERNAME: ENCRYPTED[54a372d5f22f424173c114c6fb25c3214956cad323d5b285c7393a71041884ce96471d0ff733774e5dab9fa5a3c8795c] CONTAINERS_PASSWORD: ENCRYPTED[4ecc3fb534935095a99fb1f2e320ac6bc87f3e7e186746e41cbcc4b5f5379a014b9fc8cc90e1f3d5abdbaf31580a4ab9] - clone_script: &noop mkdir -p $CIRRUS_WORKING_DIR - script: + main_script: - set -a; source /etc/automation_environment; set +a - main.sh $CIRRUS_REPO_CLONE_URL $CTXDIR test_image_build_task: <<: *image-build - # Allow this to run inside a PR w/ [CI:BUILD] - only_if: $CIRRUS_PR != '' && $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' + alias: test_image_build + # Allow this to run inside a PR w/ [CI:BUILD] only. + only_if: $CIRRUS_PR != '' && $CIRRUS_CHANGE_TITLE =~ '.*CI:BUILD.*' # This takes a LONG time, only run when requested. N/B: Any task # made to depend on this one will block FOREVER unless triggered. + # DO NOT ADD THIS TASK AS DEPENDENCY FOR `success_task`. trigger_type: manual # Overwrite all 'env', don't push anything, just do the build. env: @@ -756,7 +760,7 @@ meta_task: GCPJSON: ENCRYPTED[3a198350077849c8df14b723c0f4c9fece9ebe6408d35982e7adf2105a33f8e0e166ed3ed614875a0887e1af2b8775f4] GCPNAME: ENCRYPTED[2f9738ef295a706f66a13891b40e8eaa92a89e0e87faf8bed66c41eca72bf76cfd190a6f2d0e8444c631fdf15ed32ef6] GCPPROJECT: libpod-218412 - clone_script: *noop + clone_script: &noop mkdir -p $CIRRUS_WORKING_DIR script: /usr/local/bin/entrypoint.sh diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ec3a8a984..af957ffdd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,16 +4,22 @@ updates: directory: "/" schedule: interval: daily + labels: + - "release-note-none" open-pull-requests-limit: 10 - package-ecosystem: gomod directory: "test/tools" schedule: interval: daily + labels: + - "release-note-none" open-pull-requests-limit: 10 - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" + labels: + - "release-note-none" open-pull-requests-limit: 10 diff --git a/.gitignore b/.gitignore index f6eee2fe0..b8059e69a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /build/ /conmon/ contrib/spec/podman.spec +contrib/systemd/*/*.service *.coverprofile coverprofile /.coverage @@ -39,5 +40,4 @@ tags result # Necessary to prevent hack/tree-status.sh false-positive /*runner_stats.log -.install.goimports .generate-bindings diff --git a/.golangci.yml b/.golangci.yml index 7eb6ea57e..15700cee7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -44,7 +44,6 @@ linters: - goconst - gocyclo - lll - - unconvert - gosec - maligned - gomoddirectives diff --git a/.ubuntu_prepare.sh b/.ubuntu_prepare.sh index 1a5d1140f..1a5d1140f 100644..100755 --- a/.ubuntu_prepare.sh +++ b/.ubuntu_prepare.sh @@ -20,8 +20,6 @@ ### Variables & Definitions ### -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) @@ -29,8 +27,6 @@ COVERAGE_PATH ?= .coverage DESTDIR ?= EPOCH_TEST_COMMIT ?= $(shell git merge-base $${DEST_BRANCH:-main} HEAD) HEAD ?= HEAD -CHANGELOG_BASE ?= HEAD~ -CHANGELOG_TARGET ?= HEAD PROJECT := github.com/containers/podman GIT_BASE_BRANCH ?= origin/main GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null) @@ -69,8 +65,6 @@ PRE_COMMIT = $(shell command -v bin/venv/bin/pre-commit ~/.local/bin/pre-commit # triggered. SOURCES = $(shell find . -path './.*' -prune -o \( \( -name '*.go' -o -name '*.c' \) -a ! -name '*_test.go' \) -print) -BUILDFLAGS := -mod=vendor $(BUILDFLAGS) - BUILDTAGS_CROSS ?= containers_image_openpgp exclude_graphdriver_btrfs exclude_graphdriver_devicemapper exclude_graphdriver_overlay CONTAINER_RUNTIME := $(shell command -v podman 2> /dev/null || echo docker) OCI_RUNTIME ?= "" @@ -90,10 +84,8 @@ GIT_COMMIT ?= $(if $(shell git status --porcelain --untracked-files=no),${COMMIT DATE_FMT = %s ifdef SOURCE_DATE_EPOCH BUILD_INFO ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+$(DATE_FMT)" 2>/dev/null || date -u "+$(DATE_FMT)") - ISODATE ?= $(shell date -d "@$(SOURCE_DATE_EPOCH)" --iso-8601) else BUILD_INFO ?= $(shell date "+$(DATE_FMT)") - ISODATE ?= $(shell date --iso-8601) endif LIBPOD := ${PROJECT}/v4/libpod GOFLAGS ?= -trimpath @@ -120,22 +112,10 @@ RELEASE_NUMBER = $(shell echo "$(RELEASE_VERSION)" | sed -e 's/^v\(.*\)/\1/') # If non-empty, logs all output from server during remote system testing PODMAN_SERVER_LOG ?= -# If GOPATH not specified, use one in the local directory -ifeq ($(GOPATH),) -export GOPATH := $(HOME)/go -unexport GOBIN -endif -FIRST_GOPATH := $(firstword $(subst :, ,$(GOPATH))) -GOPKGDIR := $(FIRST_GOPATH)/src/$(PROJECT) -GOPKGBASEDIR ?= $(shell dirname "$(GOPKGDIR)") - -GOBIN := $(shell $(GO) env GOBIN) -ifeq ($(GOBIN),) -GOBIN := $(FIRST_GOPATH)/bin -endif - +# Ensure GOBIN is not set so the default (`go env GOPATH`/bin) is used. +override undefine GOBIN # This must never include the 'hack' directory -export PATH := $(PATH):$(GOBIN) +export PATH := $(shell $(GO) env GOPATH)/bin:$(PATH) GOMD2MAN ?= $(shell command -v go-md2man || echo './test/tools/build/go-md2man') @@ -223,15 +203,8 @@ help: ## (Default) Print listing of key targets with their descriptions ### Linting/Formatting/Code Validation targets ### -.gopathok: -ifeq ("$(wildcard $(GOPKGDIR))","") - mkdir -p "$(GOPKGBASEDIR)" - ln -sfn "$(CURDIR)" "$(GOPKGDIR)" -endif - touch $@ - .PHONY: .gitvalidation -.gitvalidation: .gopathok +.gitvalidation: @echo "Validating vs commit '$(call err_if_empty,EPOCH_TEST_COMMIT)'" GIT_CHECK_EXCLUDE="./vendor:./test/tools/vendor:docs/make.bat:test/buildah-bud/buildah-tests.diff" ./test/tools/build/git-validation -run DCO,short-subject,dangling-whitespace -range $(EPOCH_TEST_COMMIT)..$(HEAD) @@ -245,27 +218,15 @@ endif $(PRE_COMMIT) run -a .PHONY: golangci-lint -golangci-lint: .gopathok .install.golangci-lint +golangci-lint: .install.golangci-lint hack/golangci-lint.sh run -.PHONY: gofmt -gofmt: ## Verify the source code gofmt - find . -name '*.go' -type f \ - -not \( \ - -name '.golangci.yml' -o \ - -name 'Makefile' -o \ - -path './vendor/*' -prune -o \ - -path './test/tools/vendor/*' -prune -o \ - -path './contrib/*' -prune \ - \) -exec gofmt -d -e -s -w {} \+ - git diff --exit-code - .PHONY: test/checkseccomp/checkseccomp -test/checkseccomp/checkseccomp: .gopathok $(wildcard test/checkseccomp/*.go) +test/checkseccomp/checkseccomp: $(wildcard test/checkseccomp/*.go) $(GOCMD) build $(BUILDFLAGS) $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ ./test/checkseccomp .PHONY: test/testvol/testvol -test/testvol/testvol: .gopathok $(wildcard test/testvol/*.go) +test/testvol/testvol: $(wildcard test/testvol/*.go) $(GOCMD) build $(BUILDFLAGS) $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' -o $@ ./test/testvol .PHONY: volume-plugin-test-image @@ -273,10 +234,10 @@ volume-plugin-test-img: podman build -t quay.io/libpod/volume-plugin-test-img -f Containerfile-testvol . .PHONY: test/goecho/goecho -test/goecho/goecho: .gopathok $(wildcard test/goecho/*.go) +test/goecho/goecho: $(wildcard test/goecho/*.go) $(GOCMD) build $(BUILDFLAGS) $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' -o $@ ./test/goecho -test/version/version: .gopathok version/version.go +test/version/version: version/version.go $(GO) build -o $@ ./test/version/ .PHONY: codespell @@ -284,7 +245,7 @@ codespell: codespell -S bin,vendor,.git,go.sum,.cirrus.yml,"RELEASE_NOTES.md,*.xz,*.gz,*.ps1,*.tar,swagger.yaml,*.tgz,bin2img,*ico,*.png,*.1,*.5,copyimg,*.orig,apidoc.go" -L uint,iff,od,seeked,splitted,marge,ERRO,hist,ether -w .PHONY: validate -validate: gofmt lint .gitvalidation validate.completions man-page-check swagger-check tests-included tests-expect-exit +validate: lint .gitvalidation validate.completions man-page-check swagger-check tests-included tests-expect-exit .PHONY: build-all-new-commits build-all-new-commits: @@ -293,9 +254,9 @@ build-all-new-commits: .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: vendor-in-container vendor-in-container: @@ -309,7 +270,7 @@ vendor-in-container: ### # Make sure to warn in case we're building without the systemd buildtag. -bin/podman: .gopathok $(SOURCES) go.mod go.sum +bin/podman: $(SOURCES) go.mod go.sum ifeq (,$(findstring systemd,$(BUILDTAGS))) @echo "Podman is being compiled without the systemd build tag. \ Install libsystemd on Ubuntu or systemd-devel on rpm based \ @@ -325,14 +286,14 @@ endif $(SRCBINDIR): mkdir -p $(SRCBINDIR) -$(SRCBINDIR)/podman$(BINSFX): $(SRCBINDIR) .gopathok $(SOURCES) go.mod go.sum +$(SRCBINDIR)/podman$(BINSFX): $(SRCBINDIR) $(SOURCES) go.mod go.sum $(GOCMD) build \ $(BUILDFLAGS) \ $(GO_LDFLAGS) '$(LDFLAGS_PODMAN)' \ -tags "${REMOTETAGS}" \ -o $@ ./cmd/podman -$(SRCBINDIR)/podman-remote-static: $(SRCBINDIR) .gopathok $(SOURCES) go.mod go.sum +$(SRCBINDIR)/podman-remote-static: $(SRCBINDIR) $(SOURCES) go.mod go.sum CGO_ENABLED=0 \ GOOS=$(GOOS) \ GOARCH=$(GOARCH) \ @@ -368,7 +329,7 @@ podman-remote-windows: ## Build podman-remote for Windows bin/windows/podman.exe .PHONY: podman-winpath -podman-winpath: .gopathok $(SOURCES) go.mod go.sum +podman-winpath: $(SOURCES) go.mod go.sum CGO_ENABLED=0 \ GOOS=windows \ $(GO) build \ @@ -395,7 +356,7 @@ podman-mac-helper: ## Build podman-mac-helper for macOS -o bin/darwin/podman-mac-helper \ ./cmd/podman-mac-helper -bin/rootlessport: .gopathok $(SOURCES) go.mod go.sum +bin/rootlessport: $(SOURCES) go.mod go.sum CGO_ENABLED=$(CGO_ENABLED) \ $(GO) build \ $(BUILDFLAGS) \ @@ -411,11 +372,11 @@ rootlessport: bin/rootlessport .PHONY: generate-bindings generate-bindings: ifneq ($(GOOS),darwin) - GO111MODULE=off $(GOCMD) generate ./pkg/bindings/... ; + $(GOCMD) generate ./pkg/bindings/... ; endif # DO NOT USE: use local-cross instead -bin/podman.cross.%: .gopathok +bin/podman.cross.%: TARGET="$*"; \ GOOS="$${TARGET%%.*}"; \ GOARCH="$${TARGET##*.}"; \ @@ -455,7 +416,7 @@ completions: podman podman-remote ### Documentation targets ### -pkg/api/swagger.yaml: .gopathok +pkg/api/swagger.yaml: make -C pkg/api $(MANPAGES): %: %.md .install.md2man docdir @@ -531,7 +492,7 @@ run-docker-py-tests: .PHONY: localunit localunit: test/goecho/goecho test/version/version rm -rf ${COVERAGE_PATH} && mkdir -p ${COVERAGE_PATH} - UNIT=1 $(GOBIN)/ginkgo \ + UNIT=1 ginkgo \ -r \ $(TESTFLAGS) \ --skipPackage test/e2e,pkg/apparmor,pkg/bindings,hack,pkg/machine/e2e \ @@ -550,8 +511,8 @@ test: localunit localintegration remoteintegration localsystem remotesystem ## .PHONY: ginkgo-run ginkgo-run: - ACK_GINKGO_RC=true $(GOBIN)/ginkgo version - ACK_GINKGO_RC=true $(GOBIN)/ginkgo -v $(TESTFLAGS) -tags "$(TAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -nodes 3 -debug test/e2e/. $(HACK) + ACK_GINKGO_RC=true ginkgo version + ACK_GINKGO_RC=true ginkgo -v $(TESTFLAGS) -tags "$(TAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -nodes 3 -debug test/e2e/. $(HACK) .PHONY: ginkgo ginkgo: @@ -569,7 +530,7 @@ remoteintegration: test-binaries ginkgo-remote .PHONY: localbenchmarks localbenchmarks: test-binaries - PATH=$(PATH):$(shell PWD)/hack ACK_GINKGO_RC=true $(GOBIN)/ginkgo \ + PATH=$(PATH):$(shell pwd)/hack ACK_GINKGO_RC=true ginkgo \ -focus "Podman Benchmark Suite" \ -tags "$(BUILDTAGS) benchmarks" -noColor \ -noisySkippings=false -noisyPendings=false \ @@ -759,7 +720,7 @@ package-install: package ## Install rpm packages /usr/bin/podman info # will catch a broken conmon .PHONY: install -install: .gopathok install.bin install.remote install.man install.systemd ## Install binaries to system locations +install: install.bin install.remote install.man install.systemd ## Install binaries to system locations .PHONY: install.catatonit install.catatonit: @@ -832,7 +793,8 @@ install.docker-full: install.docker install.docker-docs ifneq (,$(findstring systemd,$(BUILDTAGS))) PODMAN_UNIT_FILES = contrib/systemd/auto-update/podman-auto-update.service \ contrib/systemd/system/podman.service \ - contrib/systemd/system/podman-restart.service + contrib/systemd/system/podman-restart.service \ + contrib/systemd/system/podman-play-kube@.service %.service: %.service.in sed -e 's;@@PODMAN@@;$(BINDIR)/podman;g' $< >$@.tmp.$$ \ @@ -846,12 +808,14 @@ install.systemd: $(PODMAN_UNIT_FILES) install ${SELINUXOPT} -m 644 contrib/systemd/system/podman.socket ${DESTDIR}${USERSYSTEMDDIR}/podman.socket install ${SELINUXOPT} -m 644 contrib/systemd/system/podman.service ${DESTDIR}${USERSYSTEMDDIR}/podman.service install ${SELINUXOPT} -m 644 contrib/systemd/system/podman-restart.service ${DESTDIR}${USERSYSTEMDDIR}/podman-restart.service + install ${SELINUXOPT} -m 644 contrib/systemd/system/podman-play-kube@.service ${DESTDIR}${USERSYSTEMDDIR}/podman-play-kube@.service # System services install ${SELINUXOPT} -m 644 contrib/systemd/auto-update/podman-auto-update.service ${DESTDIR}${SYSTEMDDIR}/podman-auto-update.service install ${SELINUXOPT} -m 644 contrib/systemd/auto-update/podman-auto-update.timer ${DESTDIR}${SYSTEMDDIR}/podman-auto-update.timer install ${SELINUXOPT} -m 644 contrib/systemd/system/podman.socket ${DESTDIR}${SYSTEMDDIR}/podman.socket install ${SELINUXOPT} -m 644 contrib/systemd/system/podman.service ${DESTDIR}${SYSTEMDDIR}/podman.service install ${SELINUXOPT} -m 644 contrib/systemd/system/podman-restart.service ${DESTDIR}${SYSTEMDDIR}/podman-restart.service + install ${SELINUXOPT} -m 644 contrib/systemd/system/podman-play-kube@.service ${DESTDIR}${SYSTEMDDIR}/podman-play-kube@.service rm -f $(PODMAN_UNIT_FILES) else install.systemd: @@ -862,14 +826,12 @@ install.tools: .install.ginkgo .install.golangci-lint .install.bats ## Install n make -C test/tools .PHONY: .install.ginkgo -.install.ginkgo: .gopathok - if [ ! -x "$(GOBIN)/ginkgo" ]; then \ - $(GO) install $(BUILDFLAGS) ./vendor/github.com/onsi/ginkgo/ginkgo ; \ - fi +.install.ginkgo: + $(GO) install $(BUILDFLAGS) ./vendor/github.com/onsi/ginkgo/ginkgo .PHONY: .install.golangci-lint -.install.golangci-lint: .gopathok - VERSION=1.45.2 GOBIN=$(GOBIN) ./hack/install_golangci.sh +.install.golangci-lint: + VERSION=1.45.2 ./hack/install_golangci.sh .PHONY: .install.md2man .install.md2man: @@ -878,7 +840,7 @@ install.tools: .install.ginkgo .install.golangci-lint .install.bats ## Install n fi .PHONY: .install.bats -.install.bats: .gopathok +.install.bats: VERSION=v1.1.0 ./hack/install_bats.sh .PHONY: .install.pre-commit @@ -887,13 +849,6 @@ install.tools: .install.ginkgo .install.golangci-lint .install.bats ## Install n python3 -m pip install --user pre-commit; \ fi -# $BUILD_TAGS variable is used in hack/golangci-lint.sh -.PHONY: install.libseccomp.sudo -install.libseccomp.sudo: - rm -rf ../../seccomp/libseccomp - git clone https://github.com/seccomp/libseccomp ../../seccomp/libseccomp - cd ../../seccomp/libseccomp && git checkout --detach $(LIBSECCOMP_COMMIT) && ./autogen.sh && ./configure --prefix=/usr && make all && make install - .PHONY: uninstall uninstall: for i in $(filter %.1,$(MANPAGES_DEST)); do \ @@ -924,7 +879,6 @@ clean-binaries: ## Remove platform/architecture specific binary files .PHONY: clean clean: clean-binaries ## Clean all make artifacts rm -rf \ - .gopathok \ _output \ $(wildcard podman-*.msi) \ $(wildcard podman-remote*.zip) \ @@ -940,7 +894,6 @@ clean: clean-binaries ## Clean all make artifacts libpod/pod_ffjson.go \ libpod/container_easyjson.go \ libpod/pod_easyjson.go \ - .install.goimports \ docs/build \ .venv make -C docs clean diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index 6149a4465..58dff3578 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -12,6 +12,7 @@ import ( "github.com/containers/image/v5/pkg/sysregistriesv2" "github.com/containers/podman/v4/cmd/podman/registry" "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/libpod/events" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/rootless" systemdDefine "github.com/containers/podman/v4/pkg/systemd/define" @@ -24,6 +25,8 @@ var ( ChangeCmds = []string{"CMD", "ENTRYPOINT", "ENV", "EXPOSE", "LABEL", "ONBUILD", "STOPSIGNAL", "USER", "VOLUME", "WORKDIR"} // LogLevels supported by podman LogLevels = []string{"trace", "debug", "info", "warn", "warning", "error", "fatal", "panic"} + // ValidSaveFormats is the list of support podman save formats + ValidSaveFormats = []string{define.OCIManifestDir, define.OCIArchive, define.V2s2ManifestDir, define.V2s2Archive} ) type completeType int @@ -992,13 +995,6 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t fields := strings.Split(field[len(field)-1], ".") f := reflect.ValueOf(o) for i := 1; i < len(fields); i++ { - val := getActualStructType(f) - if val == nil { - // no struct return nothing to complete - return nil, cobra.ShellCompDirectiveNoFileComp - } - f = *val - // last field get all names to suggest if i == len(fields)-1 { suggestions := getStructFields(f, fields[i]) @@ -1008,6 +1004,14 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t toComplete = strings.Join(toCompArr, ".") return prefixSlice(toComplete, suggestions), cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp } + + val := getActualStructType(f) + if val == nil { + // no struct return nothing to complete + return nil, cobra.ShellCompDirectiveNoFileComp + } + f = *val + // set the next struct field f = f.FieldByName(fields[i]) } @@ -1038,12 +1042,15 @@ func getActualStructType(f reflect.Value) *reflect.Value { // getStructFields reads all struct field names and method names and returns them. func getStructFields(f reflect.Value, prefix string) []string { - suggestions := []string{} + var suggestions []string + if f.IsValid() { + suggestions = append(suggestions, getMethodNames(f, prefix)...) + } val := getActualStructType(f) if val == nil { // no struct return nothing to complete - return nil + return suggestions } f = *val @@ -1069,7 +1076,11 @@ func getStructFields(f reflect.Value, prefix string) []string { suggestions = append(suggestions, fname+suffix) } } + return suggestions +} +func getMethodNames(f reflect.Value, prefix string) []string { + suggestions := make([]string, 0, f.NumMethod()) for j := 0; j < f.NumMethod(); j++ { fname := f.Type().Method(j).Name if strings.HasPrefix(fname, prefix) { @@ -1077,18 +1088,27 @@ func getStructFields(f reflect.Value, prefix string) []string { suggestions = append(suggestions, fname+"}}") } } - return suggestions } // AutocompleteEventFilter - Autocomplete event filter flag options. // -> "container=", "event=", "image=", "pod=", "volume=", "type=" func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + event := func(_ string) ([]string, cobra.ShellCompDirective) { + return []string{events.Attach.String(), events.AutoUpdate.String(), events.Checkpoint.String(), events.Cleanup.String(), + events.Commit.String(), events.Create.String(), events.Exec.String(), events.ExecDied.String(), + events.Exited.String(), events.Export.String(), events.Import.String(), events.Init.String(), events.Kill.String(), + events.LoadFromArchive.String(), events.Mount.String(), events.NetworkConnect.String(), + events.NetworkDisconnect.String(), events.Pause.String(), events.Prune.String(), events.Pull.String(), + events.Push.String(), events.Refresh.String(), events.Remove.String(), events.Rename.String(), + events.Renumber.String(), events.Restart.String(), events.Restore.String(), events.Save.String(), + events.Start.String(), events.Stop.String(), events.Sync.String(), events.Tag.String(), events.Unmount.String(), + events.Unpause.String(), events.Untag.String(), + }, cobra.ShellCompDirectiveNoFileComp + } eventTypes := func(_ string) ([]string, cobra.ShellCompDirective) { - return []string{"attach", "checkpoint", "cleanup", "commit", "connect", "create", "disconnect", "exec", - "exec_died", "exited", "export", "import", "init", "kill", "loadFromArchive", "mount", "pause", - "prune", "pull", "push", "refresh", "remove", "rename", "renumber", "restart", "restore", "save", - "start", "stop", "sync", "tag", "unmount", "unpause", "untag", + return []string{events.Container.String(), events.Image.String(), events.Network.String(), + events.Pod.String(), events.System.String(), events.Volume.String(), }, cobra.ShellCompDirectiveNoFileComp } kv := keyValueCompletion{ @@ -1096,7 +1116,7 @@ func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete strin "image=": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }, "pod=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeDefault) }, "volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) }, - "event=": eventTypes, + "event=": event, "type=": eventTypes, } return completeKeyValues(toComplete, kv) @@ -1123,9 +1143,8 @@ func AutocompleteImageSort(cmd *cobra.Command, args []string, toComplete string) } // AutocompleteInspectType - Autocomplete inspect type options. -// -> "container", "image", "all" func AutocompleteInspectType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - types := []string{"container", "image", "all"} + types := []string{AllType, ContainerType, ImageType, NetworkType, PodType, VolumeType} return types, cobra.ShellCompDirectiveNoFileComp } @@ -1175,10 +1194,8 @@ func AutocompletePsSort(cmd *cobra.Command, args []string, toComplete string) ([ } // AutocompleteImageSaveFormat - Autocomplete image save format options. -// -> "oci-archive", "oci-dir", "docker-dir" func AutocompleteImageSaveFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - formats := []string{"oci-archive", "oci-dir", "docker-dir"} - return formats, cobra.ShellCompDirectiveNoFileComp + return ValidSaveFormats, cobra.ShellCompDirectiveNoFileComp } // AutocompleteWaitCondition - Autocomplete wait condition options. @@ -1191,21 +1208,21 @@ func AutocompleteWaitCondition(cmd *cobra.Command, args []string, toComplete str // AutocompleteCgroupManager - Autocomplete cgroup manager options. // -> "cgroupfs", "systemd" func AutocompleteCgroupManager(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - types := []string{"cgroupfs", "systemd"} + types := []string{config.CgroupfsCgroupsManager, config.SystemdCgroupsManager} return types, cobra.ShellCompDirectiveNoFileComp } // AutocompleteEventBackend - Autocomplete event backend options. // -> "file", "journald", "none" func AutocompleteEventBackend(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - types := []string{"file", "journald", "none"} + types := []string{events.LogFile.String(), events.Journald.String(), events.Null.String()} return types, cobra.ShellCompDirectiveNoFileComp } // AutocompleteNetworkBackend - Autocomplete network backend options. // -> "cni", "netavark" func AutocompleteNetworkBackend(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - types := []string{"cni", "netavark"} + types := []string{string(types.CNI), string(types.Netavark)} return types, cobra.ShellCompDirectiveNoFileComp } @@ -1218,7 +1235,7 @@ func AutocompleteLogLevel(cmd *cobra.Command, args []string, toComplete string) // AutocompleteSDNotify - Autocomplete sdnotify options. // -> "container", "conmon", "ignore" func AutocompleteSDNotify(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - types := []string{"container", "conmon", "ignore"} + types := []string{define.SdNotifyModeContainer, define.SdNotifyModeContainer, define.SdNotifyModeIgnore} return types, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/podman/common/completion_test.go b/cmd/podman/common/completion_test.go index ae117a173..13f45a662 100644 --- a/cmd/podman/common/completion_test.go +++ b/cmd/podman/common/completion_test.go @@ -25,7 +25,9 @@ func (c Car) Type() string { return "" } -func (c Car) Color() string { +// Note: It is important that this function is *Car and the Type one is just Car. +// The reflect logic behaves differently for these cases so we have to test both. +func (c *Car) Color() string { return "" } @@ -94,7 +96,7 @@ func TestAutocompleteFormat(t *testing.T) { { "second level struct field name", "{{ .Car.", - []string{"{{ .Car.Brand}}", "{{ .Car.Stats.", "{{ .Car.Extras}}", "{{ .Car.Color}}", "{{ .Car.Type}}"}, + []string{"{{ .Car.Color}}", "{{ .Car.Type}}", "{{ .Car.Brand}}", "{{ .Car.Stats.", "{{ .Car.Extras}}"}, }, { "second level struct field name", @@ -104,7 +106,7 @@ func TestAutocompleteFormat(t *testing.T) { { "second level nil struct field name", "{{ .Car2.", - []string{"{{ .Car2.Brand}}", "{{ .Car2.Stats.", "{{ .Car2.Extras}}", "{{ .Car2.Color}}", "{{ .Car2.Type}}"}, + []string{"{{ .Car2.Color}}", "{{ .Car2.Type}}", "{{ .Car2.Brand}}", "{{ .Car2.Stats.", "{{ .Car2.Extras}}"}, }, { "three level struct field name", @@ -134,8 +136,8 @@ func TestAutocompleteFormat(t *testing.T) { { "two variables struct field name", "{{ .Car.Brand }} {{ .Car.", - []string{"{{ .Car.Brand }} {{ .Car.Brand}}", "{{ .Car.Brand }} {{ .Car.Stats.", "{{ .Car.Brand }} {{ .Car.Extras}}", - "{{ .Car.Brand }} {{ .Car.Color}}", "{{ .Car.Brand }} {{ .Car.Type}}"}, + []string{"{{ .Car.Brand }} {{ .Car.Color}}", "{{ .Car.Brand }} {{ .Car.Type}}", "{{ .Car.Brand }} {{ .Car.Brand}}", + "{{ .Car.Brand }} {{ .Car.Stats.", "{{ .Car.Brand }} {{ .Car.Extras}}"}, }, { "only dot without variable", diff --git a/cmd/podman/common/create_test.go b/cmd/podman/common/create_test.go index ab41f81ad..80e6cbf54 100644 --- a/cmd/podman/common/create_test.go +++ b/cmd/podman/common/create_test.go @@ -28,8 +28,8 @@ func TestPodOptions(t *testing.T) { for j := 0; j < cc.NumField(); j++ { containerField := cc.FieldByIndex([]int{j}) containerType := reflect.TypeOf(exampleOptions).Field(j) - tagPod := strings.Split(string(podType.Tag.Get("json")), ",")[0] - tagContainer := strings.Split(string(containerType.Tag.Get("json")), ",")[0] + tagPod := strings.Split(podType.Tag.Get("json"), ",")[0] + tagContainer := strings.Split(containerType.Tag.Get("json"), ",")[0] if tagPod == tagContainer && (tagPod != "" && tagContainer != "") { areEqual := true if containerField.Kind() == podField.Kind() { diff --git a/cmd/podman/common/inspect.go b/cmd/podman/common/inspect.go new file mode 100644 index 000000000..12a5af5a9 --- /dev/null +++ b/cmd/podman/common/inspect.go @@ -0,0 +1,16 @@ +package common + +const ( + // AllType can be of type ImageType or ContainerType. + AllType = "all" + // ContainerType is the container type. + ContainerType = "container" + // ImageType is the image type. + ImageType = "image" + // NetworkType is the network type + NetworkType = "network" + // PodType is the pod type. + PodType = "pod" + // VolumeType is the volume type + VolumeType = "volume" +) diff --git a/cmd/podman/containers/inspect.go b/cmd/podman/containers/inspect.go index 03e6411a1..4195cf020 100644 --- a/cmd/podman/containers/inspect.go +++ b/cmd/podman/containers/inspect.go @@ -42,6 +42,6 @@ func init() { func inspectExec(cmd *cobra.Command, args []string) error { // Force container type - inspectOpts.Type = inspect.ContainerType + inspectOpts.Type = common.ContainerType return inspect.Inspect(args, *inspectOpts) } diff --git a/cmd/podman/containers/kill.go b/cmd/podman/containers/kill.go index 32f9899cd..e994fbf2c 100644 --- a/cmd/podman/containers/kill.go +++ b/cmd/podman/containers/kill.go @@ -95,7 +95,7 @@ func kill(_ *cobra.Command, args []string) error { return errors.New("valid signals are 1 through 64") } for _, cidFile := range cidFiles { - content, err := ioutil.ReadFile(string(cidFile)) + content, err := ioutil.ReadFile(cidFile) if err != nil { return errors.Wrap(err, "error reading CIDFile") } diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go index 7e0955863..420e3c38d 100644 --- a/cmd/podman/containers/rm.go +++ b/cmd/podman/containers/rm.go @@ -102,7 +102,7 @@ func rm(cmd *cobra.Command, args []string) error { rmOptions.Timeout = &stopTimeout } for _, cidFile := range cidFiles { - content, err := ioutil.ReadFile(string(cidFile)) + content, err := ioutil.ReadFile(cidFile) if err != nil { return errors.Wrap(err, "error reading CIDFile") } diff --git a/cmd/podman/containers/stop.go b/cmd/podman/containers/stop.go index 381997fee..af2250abb 100644 --- a/cmd/podman/containers/stop.go +++ b/cmd/podman/containers/stop.go @@ -100,7 +100,7 @@ func stop(cmd *cobra.Command, args []string) error { } for _, cidFile := range cidFiles { - content, err := ioutil.ReadFile(string(cidFile)) + content, err := ioutil.ReadFile(cidFile) if err != nil { return errors.Wrap(err, "error reading CIDFile") } diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go index 22c404b3f..310f8cda8 100644 --- a/cmd/podman/images/inspect.go +++ b/cmd/podman/images/inspect.go @@ -38,6 +38,6 @@ func init() { } func inspectExec(cmd *cobra.Command, args []string) error { - inspectOpts.Type = inspect.ImageType + inspectOpts.Type = common.ImageType return inspect.Inspect(args, *inspectOpts) } diff --git a/cmd/podman/images/save.go b/cmd/podman/images/save.go index fb642bafd..3394c2e99 100644 --- a/cmd/podman/images/save.go +++ b/cmd/podman/images/save.go @@ -18,7 +18,6 @@ import ( ) var ( - validFormats = []string{define.OCIManifestDir, define.OCIArchive, define.V2s2ManifestDir, define.V2s2Archive} containerConfig = registry.PodmanConfig() ) @@ -38,8 +37,8 @@ var ( if err != nil { return err } - if !util.StringInSlice(format, validFormats) { - return errors.Errorf("format value must be one of %s", strings.Join(validFormats, " ")) + if !util.StringInSlice(format, common.ValidSaveFormats) { + return errors.Errorf("format value must be one of %s", strings.Join(common.ValidSaveFormats, " ")) } return nil }, diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go index b26b2d667..f6e3fca06 100644 --- a/cmd/podman/inspect/inspect.go +++ b/cmd/podman/inspect/inspect.go @@ -21,21 +21,6 @@ import ( "github.com/spf13/cobra" ) -const ( - // AllType can be of type ImageType or ContainerType. - AllType = "all" - // ContainerType is the container type. - ContainerType = "container" - // ImageType is the image type. - ImageType = "image" - // NetworkType is the network type - NetworkType = "network" - // PodType is the pod type. - PodType = "pod" - // VolumeType is the volume type - VolumeType = "volume" -) - // AddInspectFlagSet takes a command and adds the inspect flags and returns an // InspectOptions object. func AddInspectFlagSet(cmd *cobra.Command) *entities.InspectOptions { @@ -49,7 +34,7 @@ func AddInspectFlagSet(cmd *cobra.Command) *entities.InspectOptions { _ = cmd.RegisterFlagCompletionFunc(formatFlagName, completion.AutocompleteNone) typeFlagName := "type" - flags.StringVarP(&opts.Type, typeFlagName, "t", AllType, fmt.Sprintf("Specify inspect-object type (%q, %q or %q)", ImageType, ContainerType, AllType)) + flags.StringVarP(&opts.Type, typeFlagName, "t", common.AllType, "Specify inspect-object type") _ = cmd.RegisterFlagCompletionFunc(typeFlagName, common.AutocompleteInspectType) validate.AddLatestFlag(cmd, &opts.Latest) @@ -76,21 +61,22 @@ type inspector struct { // newInspector creates a new inspector based on the specified options. func newInspector(options entities.InspectOptions) (*inspector, error) { switch options.Type { - case ImageType, ContainerType, AllType, PodType, NetworkType, VolumeType: + case common.ImageType, common.ContainerType, common.AllType, common.PodType, common.NetworkType, common.VolumeType: // Valid types. default: - return nil, errors.Errorf("invalid type %q: must be %q, %q, %q, %q, %q, or %q", options.Type, ImageType, ContainerType, PodType, NetworkType, VolumeType, AllType) + return nil, errors.Errorf("invalid type %q: must be %q, %q, %q, %q, %q, or %q", options.Type, + common.ImageType, common.ContainerType, common.PodType, common.NetworkType, common.VolumeType, common.AllType) } - if options.Type == ImageType { + if options.Type == common.ImageType { if options.Latest { - return nil, errors.Errorf("latest is not supported for type %q", ImageType) + return nil, errors.Errorf("latest is not supported for type %q", common.ImageType) } if options.Size { - return nil, errors.Errorf("size is not supported for type %q", ImageType) + return nil, errors.Errorf("size is not supported for type %q", common.ImageType) } } - if options.Type == PodType && options.Size { - return nil, errors.Errorf("size is not supported for type %q", PodType) + if options.Type == common.PodType && options.Size { + return nil, errors.Errorf("size is not supported for type %q", common.PodType) } podOpts := entities.PodInspectOptions{ Latest: options.Latest, @@ -122,21 +108,21 @@ func (i *inspector) inspect(namesOrIDs []string) error { if len(namesOrIDs) > 0 { return errors.New("--latest and arguments cannot be used together") } - if i.options.Type == AllType { - tmpType = ContainerType // -l works with --type=all, defaults to containertype + if i.options.Type == common.AllType { + tmpType = common.ContainerType // -l works with --type=all, defaults to containertype } } // Inspect - note that AllType requires us to expensively query one-by-one. switch tmpType { - case AllType: + case common.AllType: allData, allErrs, err := i.inspectAll(ctx, namesOrIDs) if err != nil { return err } data = allData errs = allErrs - case ImageType: + case common.ImageType: imgData, allErrs, err := i.imageEngine.Inspect(ctx, namesOrIDs, i.options) if err != nil { return err @@ -145,7 +131,7 @@ func (i *inspector) inspect(namesOrIDs []string) error { for i := range imgData { data = append(data, imgData[i]) } - case ContainerType: + case common.ContainerType: ctrData, allErrs, err := i.containerEngine.ContainerInspect(ctx, namesOrIDs, i.options) if err != nil { return err @@ -154,7 +140,7 @@ func (i *inspector) inspect(namesOrIDs []string) error { for i := range ctrData { data = append(data, ctrData[i]) } - case PodType: + case common.PodType: for _, pod := range namesOrIDs { i.podOptions.NameOrID = pod podData, err := i.containerEngine.PodInspect(ctx, i.podOptions) @@ -184,7 +170,7 @@ func (i *inspector) inspect(namesOrIDs []string) error { data = append(data, podData) } } - case NetworkType: + case common.NetworkType: networkData, allErrs, err := registry.ContainerEngine().NetworkInspect(ctx, namesOrIDs, i.options) if err != nil { return err @@ -193,7 +179,7 @@ func (i *inspector) inspect(namesOrIDs []string) error { for i := range networkData { data = append(data, networkData[i]) } - case VolumeType: + case common.VolumeType: volumeData, allErrs, err := i.containerEngine.VolumeInspect(ctx, namesOrIDs, i.options) if err != nil { return err @@ -203,7 +189,8 @@ func (i *inspector) inspect(namesOrIDs []string) error { data = append(data, volumeData[i]) } default: - return errors.Errorf("invalid type %q: must be %q, %q, %q, %q, %q, or %q", i.options.Type, ImageType, ContainerType, PodType, NetworkType, VolumeType, AllType) + return errors.Errorf("invalid type %q: must be %q, %q, %q, %q, %q, or %q", i.options.Type, + common.ImageType, common.ContainerType, common.PodType, common.NetworkType, common.VolumeType, common.AllType) } // Always print an empty array if data == nil { diff --git a/cmd/podman/machine/machine.go b/cmd/podman/machine/machine.go index 553f1ef7a..5a8a06b9d 100644 --- a/cmd/podman/machine/machine.go +++ b/cmd/podman/machine/machine.go @@ -115,7 +115,7 @@ func resolveEventSock() ([]string, error) { return err case info.IsDir(): return nil - case info.Type() != os.ModeSocket: + case !isUnixSocket(info): return nil case !re.MatchString(info.Name()): return nil diff --git a/cmd/podman/machine/machine_unix.go b/cmd/podman/machine/machine_unix.go new file mode 100644 index 000000000..b56d081ec --- /dev/null +++ b/cmd/podman/machine/machine_unix.go @@ -0,0 +1,12 @@ +//go:build linux || aix || android || darwin || dragonfly || freebsd || hurd || illumos || ios || netbsd || openbsd || solaris +// +build linux aix android darwin dragonfly freebsd hurd illumos ios netbsd openbsd solaris + +package machine + +import ( + "os" +) + +func isUnixSocket(file os.DirEntry) bool { + return file.Type()&os.ModeSocket != 0 +} diff --git a/cmd/podman/machine/machine_windows.go b/cmd/podman/machine/machine_windows.go new file mode 100644 index 000000000..ffd5d8827 --- /dev/null +++ b/cmd/podman/machine/machine_windows.go @@ -0,0 +1,11 @@ +package machine + +import ( + "os" + "strings" +) + +func isUnixSocket(file os.DirEntry) bool { + // Assume a socket on Windows, since sock mode is not supported yet https://github.com/golang/go/issues/33357 + return !file.Type().IsDir() && strings.HasSuffix(file.Name(), ".sock") +} diff --git a/cmd/podman/networks/inspect.go b/cmd/podman/networks/inspect.go index 8f39ec395..1a8444147 100644 --- a/cmd/podman/networks/inspect.go +++ b/cmd/podman/networks/inspect.go @@ -37,6 +37,6 @@ func init() { } func networkInspect(_ *cobra.Command, args []string) error { - inspectOpts.Type = inspect.NetworkType + inspectOpts.Type = common.NetworkType return inspect.Inspect(args, *inspectOpts) } diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go index 5fe059139..f5b121009 100644 --- a/cmd/podman/play/kube.go +++ b/cmd/podman/play/kube.go @@ -139,6 +139,15 @@ func init() { flags.StringVar(&kubeOptions.ContextDir, contextDirFlagName, "", "Path to top level of context directory") _ = kubeCmd.RegisterFlagCompletionFunc(contextDirFlagName, completion.AutocompleteDefault) + // NOTE: The service-container flag is marked as hidden as it + // is purely designed for running play-kube in systemd units. + // It is not something users should need to know or care about. + // + // Having a flag rather than an env variable is cleaner. + serviceFlagName := "service-container" + flags.BoolVar(&kubeOptions.ServiceContainer, serviceFlagName, false, "Starts a service container before all pods") + _ = flags.MarkHidden("service-container") + flags.StringVar(&kubeOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") _ = flags.MarkHidden("signature-policy") diff --git a/cmd/podman/volumes/export.go b/cmd/podman/volumes/export.go index 1011604de..5086323f9 100644 --- a/cmd/podman/volumes/export.go +++ b/cmd/podman/volumes/export.go @@ -6,7 +6,6 @@ import ( "github.com/containers/common/pkg/completion" "github.com/containers/podman/v4/cmd/podman/common" - "github.com/containers/podman/v4/cmd/podman/inspect" "github.com/containers/podman/v4/cmd/podman/registry" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/utils" @@ -58,7 +57,7 @@ func export(cmd *cobra.Command, args []string) error { if cliExportOpts.Output == "" { return errors.New("expects output path, use --output=[path]") } - inspectOpts.Type = inspect.VolumeType + inspectOpts.Type = common.VolumeType volumeData, _, err := containerEngine.VolumeInspect(ctx, args, inspectOpts) if err != nil { return err diff --git a/cmd/podman/volumes/import.go b/cmd/podman/volumes/import.go index 9ff17e5b1..988c5536d 100644 --- a/cmd/podman/volumes/import.go +++ b/cmd/podman/volumes/import.go @@ -5,7 +5,6 @@ import ( "os" "github.com/containers/podman/v4/cmd/podman/common" - "github.com/containers/podman/v4/cmd/podman/inspect" "github.com/containers/podman/v4/cmd/podman/parse" "github.com/containers/podman/v4/cmd/podman/registry" "github.com/containers/podman/v4/pkg/domain/entities" @@ -60,7 +59,7 @@ func importVol(cmd *cobra.Command, args []string) error { tarFile = os.Stdin } - inspectOpts.Type = inspect.VolumeType + inspectOpts.Type = common.VolumeType volumeData, _, err := containerEngine.VolumeInspect(ctx, volumes, inspectOpts) if err != nil { return err diff --git a/cmd/podman/volumes/inspect.go b/cmd/podman/volumes/inspect.go index f21f9c233..7cf363f36 100644 --- a/cmd/podman/volumes/inspect.go +++ b/cmd/podman/volumes/inspect.go @@ -48,6 +48,6 @@ func volumeInspect(cmd *cobra.Command, args []string) error { if (inspectOpts.All && len(args) > 0) || (!inspectOpts.All && len(args) < 1) { return errors.New("provide one or more volume names or use --all") } - inspectOpts.Type = inspect.VolumeType + inspectOpts.Type = common.VolumeType return inspect.Inspect(args, *inspectOpts) } diff --git a/contrib/cirrus/pr-should-include-tests b/contrib/cirrus/pr-should-include-tests index 57ca39d9b..9409a1d49 100755 --- a/contrib/cirrus/pr-should-include-tests +++ b/contrib/cirrus/pr-should-include-tests @@ -34,9 +34,11 @@ filtered_changes=$(git diff --name-only $base $head | fgrep -vx .cirrus.yml | fgrep -vx .pre-commit-config.yaml | fgrep -vx .gitignore | - fgrep -vx Makefile | fgrep -vx go.mod | fgrep -vx go.sum | + fgrep -vx podman.spec.rpkg | + fgrep -vx .golangci.yml | + egrep -v '/*Makefile$' | egrep -v '^[^/]+\.md$' | egrep -v '^.github' | egrep -v '^contrib/' | diff --git a/contrib/systemd/system/podman-play-kube@.service.in b/contrib/systemd/system/podman-play-kube@.service.in new file mode 100644 index 000000000..824f71eb0 --- /dev/null +++ b/contrib/systemd/system/podman-play-kube@.service.in @@ -0,0 +1,18 @@ +[Unit] +Description=A template for running K8s workloads via podman-play-kube +Documentation=man:podman-play-kube(1) +Wants=network-online.target +After=network-online.target +RequiresMountsFor=%t/containers + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=never +TimeoutStopSec=70 +ExecStart=@@PODMAN@@ play kube --replace --service-container=true %I +ExecStop=@@PODMAN@@ play kube --down %I +Type=notify +NotifyAccess=all + +[Install] +WantedBy=default.target diff --git a/docs/source/Tutorials.rst b/docs/source/Tutorials.rst index 34a029484..c2cbcb8a9 100644 --- a/docs/source/Tutorials.rst +++ b/docs/source/Tutorials.rst @@ -6,7 +6,8 @@ Here are a number of useful tutorials to get you up and running with Podman. If * `Basic Setup and Use of Podman <https://github.com/containers/podman/blob/main/docs/tutorials/podman_tutorial.md>`_: Learn how to setup Podman and perform some basic commands with the utility. * `Basic Setup and Use of Podman in a Rootless environment <https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md>`_: The steps required to setup rootless Podman are enumerated. -* `Podman Mac/Windows tutorial <https://github.com/containers/podman/blob/main/docs/tutorials/mac_win_client.md>`_: Special setup for running the Podman remote client on a Mac or Windows PC and connecting to Podman running on a Linux VM are documented. +* `Podman for Windows <https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md>`_: A guide to installing and using Podman on Windows. +* `Podman Remote Clients on Mac/Windows <https://github.com/containers/podman/blob/main/docs/tutorials/mac_win_client.md>`_: Advanced setup for connecting to a remote Linux system using the Podman remote client on Mac and Windows. * `How to sign and distribute container images using Podman <https://github.com/containers/podman/blob/main/docs/tutorials/image_signing.md>`_: Learn how to setup and use image signing with Podman. * `Podman remote-client tutorial <https://github.com/containers/podman/blob/main/docs/tutorials/remote_client.md>`_: A brief how-to on using the Podman remote-client. * `How to use libpod for custom/derivative projects <https://github.com/containers/podman/blob/main/docs/tutorials/podman-derivative-api.md>`_: How the libpod API can be used within your own project. diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index c63e8814b..009209343 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -460,6 +460,8 @@ content that disappears when the container is stopped. #### **--init** Run an init inside the container that forwards signals and reaps processes. +The container-init binary is mounted at `/run/podman-init`. +Mounting over `/run` will hence break container execution. #### **--init-ctr**=*type* (pods only) diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md index 5c4bdc8c4..08bb2a5bc 100644 --- a/docs/source/markdown/podman-play-kube.1.md +++ b/docs/source/markdown/podman-play-kube.1.md @@ -20,7 +20,7 @@ Currently, the supported Kubernetes kinds are: `Kubernetes Pods or Deployments` -Only two volume types are supported by play kube, the *hostPath* and *persistentVolumeClaim* volume types. For the *hostPath* volume type, only the *default (empty)*, *DirectoryOrCreate*, *Directory*, *FileOrCreate*, *File*, and *Socket* subtypes are supported. The *CharDevice* and *BlockDevice* subtypes are not supported. Podman interprets the value of *hostPath* *path* as a file path when it contains at least one forward slash, otherwise Podman treats the value as the name of a named volume. When using a *persistentVolumeClaim*, the value for *claimName* is the name for the Podman named volume. +Only two volume types are supported by play kube, the *hostPath* and *persistentVolumeClaim* volume types. For the *hostPath* volume type, only the *default (empty)*, *DirectoryOrCreate*, *Directory*, *FileOrCreate*, *File*, *Socket*, *CharDevice* and *BlockDevice* subtypes are supported. Podman interprets the value of *hostPath* *path* as a file path when it contains at least one forward slash, otherwise Podman treats the value as the name of a named volume. When using a *persistentVolumeClaim*, the value for *claimName* is the name for the Podman named volume. Note: When playing a kube YAML with init containers, the init container will be created with init type value `always`. diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 9d9394020..a16ee9394 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -498,6 +498,8 @@ content that disappears when the container is stopped. #### **--init** Run an init inside the container that forwards signals and reaps processes. +The container-init binary is mounted at `/run/podman-init`. +Mounting over `/run` will hence break container execution. #### **--init-path**=*path* diff --git a/docs/tutorials/mac_win_client.md b/docs/tutorials/mac_win_client.md index 159296d5e..553a38394 100644 --- a/docs/tutorials/mac_win_client.md +++ b/docs/tutorials/mac_win_client.md @@ -1,5 +1,9 @@ # Podman Remote clients for macOS and Windows +*** +**_NOTE:_** For running Podman on Windows, refer to the [Podman for Windows](podman-for-windows.md) guide, which uses the recommended approach of a Podman-managed Linux backend. For Mac, see the [Podman installation instructions](https://podman.io/getting-started/installation). This guide covers the advanced usage of Podman with a custom Linux VM or a remote external Linux system. +*** + ## Introduction The core Podman runtime environment can only run on Linux operating systems. But other operating systems can use the “remote client” to manage their containers to a Linux backend. This remote client is nearly identical to the standard Podman program. Certain functions that do not make sense for remote clients have been removed. For example, the “--latest” switch for container commands has been removed. diff --git a/docs/tutorials/podman-for-windows.md b/docs/tutorials/podman-for-windows.md index bb9674774..4e929a14a 100644 --- a/docs/tutorials/podman-for-windows.md +++ b/docs/tutorials/podman-for-windows.md @@ -233,15 +233,15 @@ Linux container. This supports several notation schemes, including: Windows Style Paths: -`podman run -it c:\Users\User\myfolder:/myfolder ubi8-micro ls /myfolder` +`podman run --rm -v c:\Users\User\myfolder:/myfolder ubi8-micro ls /myfolder` Unixy Windows Paths: -`podman run -it /c/Users/User/myfolder:/myfolder ubi8-micro ls /myfolder` +`podman run --rm -v /c/Users/User/myfolder:/myfolder ubi8-micro ls /myfolder` Linux paths local to the WSL filesystem: -`podman run -it /var/myfolder:/myfolder ubi-micro ls /myfolder` +`podman run --rm -v /var/myfolder:/myfolder ubi-micro ls /myfolder` All of the above conventions work, whether running on a Windows prompt or the WSL Linux shell. Although when using Windows paths on Linux, appropriately quote @@ -12,9 +12,9 @@ require ( github.com/containernetworking/cni v1.1.0 github.com/containernetworking/plugins v1.1.1 github.com/containers/buildah v1.26.1 - github.com/containers/common v0.48.0 + github.com/containers/common v0.48.1-0.20220512112240-7536bf6ff9b1 github.com/containers/conmon v2.0.20+incompatible - github.com/containers/image/v5 v5.21.2-0.20220511203756-fe4fd4ed8be4 + github.com/containers/image/v5 v5.21.2-0.20220519193817-1e26896b8059 github.com/containers/ocicrypt v1.1.4-0.20220428134531-566b808bdf6f github.com/containers/psgo v1.7.2 github.com/containers/storage v1.41.1-0.20220511210719-cacc3325a9c8 @@ -24,7 +24,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001 github.com/docker/distribution v2.8.1+incompatible - github.com/docker/docker v20.10.15+incompatible + github.com/docker/docker v20.10.16+incompatible github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11 github.com/docker/go-plugins-helpers v0.0.0-20211224144127-6eecb7beb651 github.com/docker/go-units v0.4.0 @@ -47,7 +47,7 @@ require ( github.com/onsi/gomega v1.19.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 - github.com/opencontainers/runc v1.1.1 + github.com/opencontainers/runc v1.1.2 github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab github.com/opencontainers/runtime-tools v0.9.1-0.20220110225228-7e2d60f1e41f github.com/opencontainers/selinux v1.10.1 @@ -339,13 +339,14 @@ github.com/containernetworking/plugins v1.1.1 h1:+AGfFigZ5TiQH00vhR8qPeSatj53eNG github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8= github.com/containers/buildah v1.26.1 h1:D65Vuo+orsI14WWtJhSX6KrpgBBa7+hveVWevzG8p8E= github.com/containers/buildah v1.26.1/go.mod h1:CsWSG8OpJd8v3mlLREJzVAOBgC93DjRNALUVHoi8QsY= -github.com/containers/common v0.48.0 h1:997nnXBZ+eNpfSM7L4SxhhZubQrfEyw3jRyNMTSsNlw= github.com/containers/common v0.48.0/go.mod h1:zPLZCfLXfnd1jI0QRsD4By54fP4k1+ifQs+tulIe3o0= +github.com/containers/common v0.48.1-0.20220512112240-7536bf6ff9b1 h1:U+2rYjzRCvI3WRSFf+Rohtu7jRgk/VhJjjFHbU6j0Sk= +github.com/containers/common v0.48.1-0.20220512112240-7536bf6ff9b1/go.mod h1:h8YZVXePE7UViJQ3fPWpYAaeDNYBCzGtL5dA3N8yfT8= 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.21.1/go.mod h1:zl35egpcDQa79IEXIuoUe1bW+D1pdxRxYjNlyb3YiXw= -github.com/containers/image/v5 v5.21.2-0.20220511203756-fe4fd4ed8be4 h1:9yDGjKniCxCIVJwdiUHGTjguGJUcntDtWLUIz+LhyzY= -github.com/containers/image/v5 v5.21.2-0.20220511203756-fe4fd4ed8be4/go.mod h1:OsX9sFexyGF0FCNAjfcVFv3IwMqDyLyV/WQY/roLPcE= +github.com/containers/image/v5 v5.21.2-0.20220519193817-1e26896b8059 h1:/FzsjrQ2nJtMom9IXEGieORlwUk/NyDuuz5SWcNo324= +github.com/containers/image/v5 v5.21.2-0.20220519193817-1e26896b8059/go.mod h1:KntCBNQn3qOuZmQuJ38ORyTozmWXiuo05Vef2S0Sm5M= github.com/containers/libtrust v0.0.0-20200511145503-9c3a6c22cd9a h1:spAGlqziZjCJL25C6F1zsQY05tfCKE9F5YwtEWWe6hU= github.com/containers/libtrust v0.0.0-20200511145503-9c3a6c22cd9a/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= @@ -361,6 +362,7 @@ github.com/containers/storage v1.37.0/go.mod h1:kqeJeS0b7DO2ZT1nVWs0XufrmPFbgV3c github.com/containers/storage v1.38.0/go.mod h1:lBzt28gAk5ADZuRtwdndRJyqX22vnRaXmlF+7ktfMYc= github.com/containers/storage v1.40.0/go.mod h1:zUyPC3CFIGR1OhY1CKkffxgw9+LuH76PGvVcFj38dgs= github.com/containers/storage v1.40.2/go.mod h1:zUyPC3CFIGR1OhY1CKkffxgw9+LuH76PGvVcFj38dgs= +github.com/containers/storage v1.41.0/go.mod h1:Pb0l5Sm/89kolX3o2KolKQ5cCHk5vPNpJrhNaLcdS5s= github.com/containers/storage v1.41.1-0.20220511210719-cacc3325a9c8 h1:4XdTbn3iVIr1+kN5srZND2G3/Q3hJiZSZZtKdL6r9jg= github.com/containers/storage v1.41.1-0.20220511210719-cacc3325a9c8/go.mod h1:Pb0l5Sm/89kolX3o2KolKQ5cCHk5vPNpJrhNaLcdS5s= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -429,8 +431,9 @@ github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r github.com/docker/docker v20.10.3-0.20220208084023-a5c757555091+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.15+incompatible h1:dk9FewY/9Xwm4ay/HViEEHSQuM/kL4F+JaG6GQdgmGo= github.com/docker/docker v20.10.15+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.16+incompatible h1:2Db6ZR/+FUR3hqPMwnogOPHFn405crbpxvWzKovETOQ= +github.com/docker/docker v20.10.16+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= @@ -1052,8 +1055,9 @@ github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84 github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runc v1.1.1 h1:PJ9DSs2sVwE0iVr++pAHE6QkS9tzcVWozlPifdwMgrU= github.com/opencontainers/runc v1.1.1/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.2 h1:2VSZwLx5k/BfsBxMMipG/LYUnmqOD/BPkIVgQUcTlLw= +github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -1107,8 +1111,9 @@ github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:w github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/proglottis/gpgme v0.1.1 h1:72xI0pt/hy7pqsRxk32KExITkXp+RZErRizsA+up/lQ= github.com/proglottis/gpgme v0.1.1/go.mod h1:fPbW/EZ0LvwQtH8Hy7eixhp1eF3G39dtx7GUN+0Gmy0= +github.com/proglottis/gpgme v0.1.2 h1:dKlhDqJ0kdEt+YHCD8FQEUdF9cJj/+mbJUNyUGNAEzY= +github.com/proglottis/gpgme v0.1.2/go.mod h1:fPbW/EZ0LvwQtH8Hy7eixhp1eF3G39dtx7GUN+0Gmy0= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= diff --git a/hack/buildah-vendor-treadmill b/hack/buildah-vendor-treadmill index 0aa4245c5..d579a180a 100755 --- a/hack/buildah-vendor-treadmill +++ b/hack/buildah-vendor-treadmill @@ -14,9 +14,10 @@ use warnings; use File::Temp qw(tempfile); use JSON; use LWP::UserAgent; +use POSIX qw(strftime); (our $ME = $0) =~ s|.*/||; -our $VERSION = '0.2'; +our $VERSION = '0.3'; # For debugging, show data structures using DumpTree($var) #use Data::TreeDumper; $Data::TreeDumper::Displayaddress = 0; @@ -65,7 +66,7 @@ eval ' sub usage { print <<"END_USAGE"; -Usage: $ME [OPTIONS] [--sync | --pick ] +Usage: $ME [OPTIONS] [--sync | --pick | --reset ] $ME is (2022-04-20) **EXPERIMENTAL** @@ -82,6 +83,9 @@ Call me with one of two options: --pick Used for really-truly vendoring in a new buildah; will cherry-pick a commit on your buildah-vendor working branch + --reset Used after vendoring buildah into main, when there + really aren't any buildah patches to keep rolling. + For latest documentation and best practices, please see: $Docs_URL @@ -105,8 +109,9 @@ our $NOT = ''; # print "blahing the blah$NOT\n" if $debug sub handle_opts { use Getopt::Long; GetOptions( - 'sync' => sub { $action{sync}++ }, - 'pick' => sub { $action{pick}++ }, + 'sync' => sub { $action{sync}++ }, + 'pick' => sub { $action{pick}++ }, + 'reset' => sub { $action{reset}++ }, 'force-old-main' => \$force_old_main, 'force-testing' => \$force_testing, @@ -183,8 +188,10 @@ sub do_sync { pull_main(); git('checkout', '-q', $current_branch); - # Preserve local patches - git('format-patch', "--output=$Patch_File", 'HEAD^'); + # Preserve local patches. --always will generate empty patches (e.g., + # after a buildah vendor when everything is copacetic); --no-signature + # prevents a buildup of "-- 2.35" (git version) lines at the end. + git('format-patch', '--always', '--no-signature', "--output=$Patch_File", 'HEAD^'); progress("Treadmill patches saved to $Patch_File"); # @@ -250,20 +257,11 @@ END_FAIL_INSTRUCTIONS } # Commit everything. - git('commit', '-as', '-m', <<"END_COMMIT_MESSAGE"); -[DO NOT MERGE] vendor in buildah \@ $buildah_new - -This is a JUNK COMMIT from $ME v$VERSION. - -DO NOT MERGE. This is just a way to keep the buildah-podman -vendoring in sync. Refer to: - - $Docs_URL -END_COMMIT_MESSAGE + git_commit_buildah($buildah_new); # And, finally, this has the highest possibility of failing progress('Reapplying preserved patches'); - git('am', $Patch_File); + git('am', '--empty=keep', $Patch_File); # It worked! Clean up: remove our local die() handler and the patch file undef $SIG{__DIE__}; @@ -638,6 +636,38 @@ END_EDIT_SCRIPT # END pick and its helpers ############################################################################### +# BEGIN reset and its helpers + +sub do_reset { + my $current_branch = git_current_branch(); + + # Make sure side branch == main (i.e., there are no commits on the branch) + if (git('rev-parse', $current_branch) ne git('rev-parse', 'main')) { + die "$ME: for --reset, $current_branch must == main\n"; + } + + # Pull main, and pivot back to this branch + pull_main(); + git('checkout', '-q', $current_branch); + + git('rebase', '--empty=keep', 'main'); + git_commit_buildah('[none]'); + + my $ymd = strftime("%Y-%m-%d", localtime); + git('commit', '--allow-empty', '-s', '-m' => <<"END_COMMIT_MESSAGE"); +$Treadmill_PR_Title + +As you run --sync, please update this commit message with your +actual changes. + +Changes since $ymd: +END_COMMIT_MESSAGE + + progress("Done. You may now run --sync.\n"); +} + +# END reset and its helpers +############################################################################### # BEGIN general-purpose helpers ############## @@ -728,6 +758,24 @@ sub git_upstream { die "$ME: did not find a remote with 'github.com/containers/podman'\n"; } +######################## +# git_commit_buildah # Do the buildah commit +######################## +sub git_commit_buildah { + my $buildah_version = shift; + + # When called by --reset, this can be empty + git('commit', '-as', '--allow-empty', '-m', <<"END_COMMIT_MESSAGE"); +DO NOT MERGE: vendor in buildah \@ $buildah_version + +This is a JUNK COMMIT from $ME v$VERSION. + +DO NOT MERGE! This is just a way to keep the buildah-podman +vendoring in sync. Refer to: + + $Docs_URL +END_COMMIT_MESSAGE +} ######### # git # Run a git command diff --git a/hack/parse-localbenchmarks b/hack/parse-localbenchmarks new file mode 100755 index 000000000..6e22cabbb --- /dev/null +++ b/hack/parse-localbenchmarks @@ -0,0 +1,104 @@ +#!/usr/bin/perl +# +# parse-localbenchmarks - convert localbenchmarks output to CSV +# +# This is a filter. It transforms data from one format to another. Usage: +# +# $ make localbenchmarks &> mylogfile +# $ hack/parse-localbenchmarks <mylogfile > benchmarks.csv +# +# To be more precise, this is a very stupid simpleminded filter. It is +# not a complete solution to the benchmarks problem. In particular, +# other tools are still needed to: +# +# * Actually _run_ the benchmarks in some standard production environment +# * Run this script on the results +# * Save results, with identifying tags (datetime, git hash, PR id, ...) +# * Compare two or more sets of CSVs +# +(our $ME = $0) =~ s|^.*/||; # script name + +use v5.14; +use utf8; + +# FIXME: add --help. Some day. Not urgent. +die "$ME: This is a filter, not an interactive tool\n" if -t *STDIN; + +my $n_samples; # Number of timing runs (FIXME: unused) +my %results; # Timing results +my @benchmarks; # Names of benchmarks +my ($type, $testname); # Current context + +# +# Pass 1: read in timings +# +while (my $line = <STDIN>) { + # Log will have lots of ginkgo output. The only thing we care about is + # the summary at the end, which will look something like: + # + # * [MEASUREMENT] + # Podman Benchmark Suite + # .... + # Ran 3 samples: + # [CPU] podman images: + # Fastest Time: 0.265s + # Slowest Time: 0.322s + # Average Time: 0.302s ± 0.018s + # [MEM] podman images: + # Smallest: 44076.0KB + # Largest: 44616.0KB + # Average: 44338.7KB ± 171.2KB + # [CPU] podman push: + # ....repeat [CPU] and [MEM] for each test + # -------------------------- + # SSSSSSSSSSSSSSSSSSSSS (and more ginkgo output we don't care about) + # + chomp $line; + next unless $line =~ /^.{1,3}\s+\[MEASUREMENT\]/ .. $line =~ /^-{20,}$/; + + # Trim leading & trailing whitespace + $line =~ s/(^\s+|\s+$)//g; + + # FIXME: we don't actually emit this. What would be a good way to do so? + if ($line =~ /^Ran\s+(\d+)\s+samples/) { + $n_samples = $1; + } + + # e.g., [CPU] podman foo: + elsif ($line =~ /^\[([A-Z]+)\]\s+(\S.*\S):$/) { + ($type, $testname) = ($1, $2); + } + + # e.g., 'Fastest Time: 0.265s' + elsif ($line =~ /^(\S.*?\S):\s+(.*)/) { + my $benchmark = "$type $1"; + $results{$testname}{$benchmark} = $2; + + # Keep an ordered list of benchmark names (as in, the order we + # encounter them) + push @benchmarks, $benchmark + unless grep { $_ eq $benchmark } @benchmarks; + } + + else { + warn "Cannot grok '$line'\n" if $ENV{DEBUG_PARSELOCALBENCHMARKS}; + } +} + +# +# Pass 2: write out CSV +# + +# Headings... +print "\"Test Name\""; +printf ", \"%s\"", $_ for @benchmarks; +print "\n"; + +# ...then data +for my $t (sort keys %results) { + printf "\"%s\"", $t; + for my $benchmark (@benchmarks) { + printf ", \"%s\"", $results{$t}{$benchmark} || ''; + } + print "\n"; +} diff --git a/libpod/container.go b/libpod/container.go index d7af9a100..64b4453fb 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -211,6 +211,14 @@ type ContainerState struct { // network and an interface names NetInterfaceDescriptions ContainerNetworkDescriptions `json:"networkDescriptions,omitempty"` + // Service indicates that container is the service container of a + // service. A service consists of one or more pods. The service + // container is started before all pods and is stopped when the last + // pod stops. The service container allows for tracking and managing + // the entire life cycle of service which may be started via + // `podman-play-kube`. + Service Service + // containerPlatformState holds platform-specific container state. containerPlatformState diff --git a/libpod/container_config.go b/libpod/container_config.go index 371a1dec0..3e85ad4d5 100644 --- a/libpod/container_config.go +++ b/libpod/container_config.go @@ -382,6 +382,9 @@ type ContainerMiscConfig struct { // IsInfra is a bool indicating whether this container is an infra container used for // sharing kernel namespaces in a pod IsInfra bool `json:"pause"` + // IsService is a bool indicating whether this container is a service container used for + // tracking the life cycle of K8s service. + IsService bool `json:"isService"` // SdNotifyMode tells libpod what to do with a NOTIFY_SOCKET if passed SdNotifyMode string `json:"sdnotifyMode,omitempty"` // Systemd tells libpod to setup the container in systemd mode, a value of nil denotes false diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 76e0e9e13..93240812d 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -171,6 +171,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver Mounts: inspectMounts, Dependencies: c.Dependencies(), IsInfra: c.IsInfra(), + IsService: c.IsService(), } if c.state.ConfigPath != "" { diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 4742b22ab..d7683cce9 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -3282,7 +3282,7 @@ func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error { return err } stat := st.Sys().(*syscall.Stat_t) - atime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec)) + atime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec)) // nolint: unconvert if err := os.Chtimes(mountPoint, atime, st.ModTime()); err != nil { return err } diff --git a/libpod/container_validate.go b/libpod/container_validate.go index c6c9a4c6d..cfbdd2b1e 100644 --- a/libpod/container_validate.go +++ b/libpod/container_validate.go @@ -1,6 +1,8 @@ package libpod import ( + "fmt" + "github.com/containers/podman/v4/libpod/define" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" @@ -27,6 +29,12 @@ func (c *Container) validate() error { return errors.Wrapf(define.ErrInvalidArg, "must set root filesystem source to either image or rootfs") } + // A container cannot be marked as an infra and service container at + // the same time. + if c.IsInfra() && c.IsService() { + return fmt.Errorf("cannot be infra and service container at the same time: %w", define.ErrInvalidArg) + } + // Cannot make a network namespace if we are joining another container's // network namespace if c.config.CreateNetNS && c.config.NetNsCtr != "" { diff --git a/libpod/define/container.go b/libpod/define/container.go index bb44a6a4a..ba939578f 100644 --- a/libpod/define/container.go +++ b/libpod/define/container.go @@ -35,4 +35,6 @@ const ( // OneShotInitContainer is a container that only runs as init once // and is then deleted. OneShotInitContainer = "once" + // ContainerInitPath is the default path of the mounted container init. + ContainerInitPath = "/run/podman-init" ) diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go index 6cdffb8b7..e7b82d654 100644 --- a/libpod/define/container_inspect.go +++ b/libpod/define/container_inspect.go @@ -683,6 +683,7 @@ type InspectContainerData struct { NetworkSettings *InspectNetworkSettings `json:"NetworkSettings"` Namespace string `json:"Namespace"` IsInfra bool `json:"IsInfra"` + IsService bool `json:"IsService"` Config *InspectContainerConfig `json:"Config"` HostConfig *InspectContainerHostConfig `json:"HostConfig"` } diff --git a/libpod/diff.go b/libpod/diff.go index 794b26b48..86fa063ec 100644 --- a/libpod/diff.go +++ b/libpod/diff.go @@ -8,17 +8,18 @@ import ( ) var initInodes = map[string]bool{ - "/dev": true, - "/etc/hostname": true, - "/etc/hosts": true, - "/etc/resolv.conf": true, - "/proc": true, - "/run": true, - "/run/notify": true, - "/run/.containerenv": true, - "/run/secrets": true, - "/sys": true, - "/etc/mtab": true, + "/dev": true, + "/etc/hostname": true, + "/etc/hosts": true, + "/etc/resolv.conf": true, + "/proc": true, + "/run": true, + "/run/notify": true, + "/run/.containerenv": true, + "/run/secrets": true, + define.ContainerInitPath: true, + "/sys": true, + "/etc/mtab": true, } // GetDiff returns the differences between the two images, layers, or containers diff --git a/libpod/events.go b/libpod/events.go index 39f5786a4..f09d8402a 100644 --- a/libpod/events.go +++ b/libpod/events.go @@ -89,8 +89,8 @@ func (p *Pod) newPodEvent(status events.Status) { } } -// newSystemEvent creates a new event for libpod as a whole. -func (r *Runtime) newSystemEvent(status events.Status) { +// NewSystemEvent creates a new event for libpod as a whole. +func (r *Runtime) NewSystemEvent(status events.Status) { e := events.NewEvent(status) e.Type = events.System diff --git a/libpod/events/config.go b/libpod/events/config.go index 00cdca007..2e7016136 100644 --- a/libpod/events/config.go +++ b/libpod/events/config.go @@ -98,6 +98,8 @@ type Type string // Status describes the actual event action (stop, start, create, kill) type Status string +// When updating this list below please also update the shell completion list in +// cmd/podman/common/completion.go and the StringToXXX function in events.go. const ( // Container - event is related to containers Container Type = "container" diff --git a/libpod/events/events.go b/libpod/events/events.go index 04417fd8d..e83c2efee 100644 --- a/libpod/events/events.go +++ b/libpod/events/events.go @@ -150,6 +150,8 @@ func StringToStatus(name string) (Status, error) { switch name { case Attach.String(): return Attach, nil + case AutoUpdate.String(): + return AutoUpdate, nil case Build.String(): return Build, nil case Checkpoint.String(): diff --git a/libpod/info.go b/libpod/info.go index 321680a81..bc49a6cc9 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -406,26 +406,25 @@ func getCPUUtilization() (*define.CPUUsage, error) { } defer f.Close() scanner := bufio.NewScanner(f) - // Read firt line of /proc/stat + // Read first line of /proc/stat that has entries for system ("cpu" line) for scanner.Scan() { break } // column 1 is user, column 3 is system, column 4 is idle - stats := strings.Split(scanner.Text(), " ") + stats := strings.Fields(scanner.Text()) return statToPercent(stats) } func statToPercent(stats []string) (*define.CPUUsage, error) { - // There is always an extra space between cpu and the first metric - userTotal, err := strconv.ParseFloat(stats[2], 64) + userTotal, err := strconv.ParseFloat(stats[1], 64) if err != nil { return nil, errors.Wrapf(err, "unable to parse user value %q", stats[1]) } - systemTotal, err := strconv.ParseFloat(stats[4], 64) + systemTotal, err := strconv.ParseFloat(stats[3], 64) if err != nil { return nil, errors.Wrapf(err, "unable to parse system value %q", stats[3]) } - idleTotal, err := strconv.ParseFloat(stats[5], 64) + idleTotal, err := strconv.ParseFloat(stats[4], 64) if err != nil { return nil, errors.Wrapf(err, "unable to parse idle value %q", stats[4]) } diff --git a/libpod/info_test.go b/libpod/info_test.go index 909b573c0..b0e4bf8c0 100644 --- a/libpod/info_test.go +++ b/libpod/info_test.go @@ -20,7 +20,7 @@ func Test_statToPercent(t *testing.T) { }{ { name: "GoodParse", - args: args{in0: []string{"cpu", " ", "33628064", "27537", "9696996", "1314806705", "588142", "4775073", "2789228", "0", "598711", "0"}}, + args: args{in0: []string{"cpu", "33628064", "27537", "9696996", "1314806705", "588142", "4775073", "2789228", "0", "598711", "0"}}, want: &define.CPUUsage{ UserPercent: 2.48, SystemPercent: 0.71, @@ -30,19 +30,19 @@ func Test_statToPercent(t *testing.T) { }, { name: "BadUserValue", - args: args{in0: []string{"cpu", " ", "k", "27537", "9696996", "1314806705", "588142", "4775073", "2789228", "0", "598711", "0"}}, + args: args{in0: []string{"cpu", "k", "27537", "9696996", "1314806705", "588142", "4775073", "2789228", "0", "598711", "0"}}, want: nil, wantErr: assert.Error, }, { name: "BadSystemValue", - args: args{in0: []string{"cpu", " ", "33628064", "27537", "k", "1314806705", "588142", "4775073", "2789228", "0", "598711", "0"}}, + args: args{in0: []string{"cpu", "33628064", "27537", "k", "1314806705", "588142", "4775073", "2789228", "0", "598711", "0"}}, want: nil, wantErr: assert.Error, }, { name: "BadIdleValue", - args: args{in0: []string{"cpu", " ", "33628064", "27537", "9696996", "k", "588142", "4775073", "2789228", "0", "598711", "0"}}, + args: args{in0: []string{"cpu", "33628064", "27537", "9696996", "k", "588142", "4775073", "2789228", "0", "598711", "0"}}, want: nil, wantErr: assert.Error, }, diff --git a/libpod/options.go b/libpod/options.go index 9b83cb76a..feb89510f 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1,6 +1,7 @@ package libpod import ( + "fmt" "net" "os" "path/filepath" @@ -1477,7 +1478,7 @@ func WithCreateCommand(cmd []string) CtrCreateOption { } } -// withIsInfra allows us to dfferentiate between infra containers and regular containers +// withIsInfra allows us to dfferentiate between infra containers and other containers // within the container config func withIsInfra() CtrCreateOption { return func(ctr *Container) error { @@ -1491,6 +1492,20 @@ func withIsInfra() CtrCreateOption { } } +// WithIsService allows us to dfferentiate between service containers and other container +// within the container config +func WithIsService() CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return define.ErrCtrFinalized + } + + ctr.config.IsService = true + + return nil + } +} + // WithCreateWorkingDir tells Podman to create the container's working directory // if it does not exist. func WithCreateWorkingDir() CtrCreateOption { @@ -2081,6 +2096,27 @@ func WithInfraContainer() PodCreateOption { } } +// WithServiceContainer associates the specified service container ID with the pod. +func WithServiceContainer(id string) PodCreateOption { + return func(pod *Pod) error { + if pod.valid { + return define.ErrPodFinalized + } + + ctr, err := pod.runtime.LookupContainer(id) + if err != nil { + return fmt.Errorf("looking up service container: %w", err) + } + + if err := ctr.addServicePodLocked(pod.ID()); err != nil { + return fmt.Errorf("associating service container %s with pod %s: %w", id, pod.ID(), err) + } + + pod.config.ServiceContainerID = id + return nil + } +} + // WithVolatile sets the volatile flag for the container storage. // The option can potentially cause data loss when used on a container that must survive a machine reboot. func WithVolatile() CtrCreateOption { diff --git a/libpod/pod.go b/libpod/pod.go index 2211d5be7..3c8dc43d4 100644 --- a/libpod/pod.go +++ b/libpod/pod.go @@ -64,6 +64,13 @@ type PodConfig struct { HasInfra bool `json:"hasInfra,omitempty"` + // ServiceContainerID is the main container of a service. A service + // consists of one or more pods. The service container is started + // before all pods and is stopped when the last pod stops. + // The service container allows for tracking and managing the entire + // life cycle of service which may be started via `podman-play-kube`. + ServiceContainerID string `json:"serviceContainerID,omitempty"` + // Time pod was created CreatedTime time.Time `json:"created"` diff --git a/libpod/pod_api.go b/libpod/pod_api.go index 73b28822b..eede896a9 100644 --- a/libpod/pod_api.go +++ b/libpod/pod_api.go @@ -75,6 +75,10 @@ func (p *Pod) Start(ctx context.Context) (map[string]error, error) { return nil, define.ErrPodRemoved } + if err := p.maybeStartServiceContainer(ctx); err != nil { + return nil, err + } + // Before "regular" containers start in the pod, all init containers // must have run and exited successfully. if err := p.startInitContainers(ctx); err != nil { @@ -197,6 +201,11 @@ func (p *Pod) stopWithTimeout(ctx context.Context, cleanup bool, timeout int) (m if len(ctrErrors) > 0 { return ctrErrors, errors.Wrapf(define.ErrPodPartialFail, "error stopping some containers") } + + if err := p.maybeStopServiceContainer(); err != nil { + return nil, err + } + return nil, nil } @@ -297,6 +306,10 @@ func (p *Pod) Cleanup(ctx context.Context) (map[string]error, error) { return ctrErrors, errors.Wrapf(define.ErrPodPartialFail, "error cleaning up some containers") } + if err := p.maybeStopServiceContainer(); err != nil { + return nil, err + } + return nil, nil } @@ -443,6 +456,10 @@ func (p *Pod) Restart(ctx context.Context) (map[string]error, error) { return nil, define.ErrPodRemoved } + if err := p.maybeStartServiceContainer(ctx); err != nil { + return nil, err + } + allCtrs, err := p.runtime.state.PodContainers(p) if err != nil { return nil, err @@ -530,6 +547,11 @@ func (p *Pod) Kill(ctx context.Context, signal uint) (map[string]error, error) { if len(ctrErrors) > 0 { return ctrErrors, errors.Wrapf(define.ErrPodPartialFail, "error killing some containers") } + + if err := p.maybeStopServiceContainer(); err != nil { + return nil, err + } + return nil, nil } diff --git a/libpod/runtime.go b/libpod/runtime.go index f4cd9cf00..4efa7b8e8 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -349,7 +349,7 @@ func makeRuntime(runtime *Runtime) (retErr error) { // it will try to use existing XDG_RUNTIME_DIR // if current user has no write access to XDG_RUNTIME_DIR we will fail later if err := unix.Access(runtime.storageConfig.RunRoot, unix.W_OK); err != nil { - msg := "XDG_RUNTIME_DIR is pointing to a path which is not writable. Most likely podman will fail." + msg := fmt.Sprintf("RunRoot is pointing to a path (%s) which is not writable. Most likely podman will fail.", runtime.storageConfig.RunRoot) if errors.Is(err, os.ErrNotExist) { // if dir does not exists try to create it if err := os.MkdirAll(runtime.storageConfig.RunRoot, 0700); err != nil { @@ -930,7 +930,7 @@ func (r *Runtime) refresh(alivePath string) error { } defer file.Close() - r.newSystemEvent(events.Refresh) + r.NewSystemEvent(events.Refresh) return nil } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index df7174ac6..2eaa77572 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -644,6 +644,16 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo return err } + if c.IsService() { + canStop, err := c.canStopServiceContainer() + if err != nil { + return err + } + if !canStop { + return fmt.Errorf("container %s is the service container of pod(s) %s and cannot be removed without removing the pod(s)", c.ID(), strings.Join(c.state.Service.Pods, ",")) + } + } + // If we're not force-removing, we need to check if we're in a good // state to remove. if !force { @@ -732,7 +742,11 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo // after setting the state to ContainerStateRemoving will prevent that the container is // restarted if err := c.removeAllExecSessions(); err != nil { - return err + if cleanupErr == nil { + cleanupErr = err + } else { + logrus.Errorf("Remove exec sessions: %v", err) + } } // Stop the container's storage @@ -903,6 +917,16 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol } } + if c.IsService() { + canStop, err := c.canStopServiceContainer() + if err != nil { + return id, err + } + if !canStop { + return id, fmt.Errorf("container %s is the service container of pod(s) %s and cannot be removed without removing the pod(s)", c.ID(), strings.Join(c.state.Service.Pods, ",")) + } + } + var cleanupErr error // Remove the container from the state if c.config.Pod != "" { diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index 54eadf6b8..b13482722 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -40,7 +40,7 @@ func (r *Runtime) RemoveContainersForImageCallback(ctx context.Context) libimage if ctr.config.IsInfra { pod, err := r.state.Pod(ctr.config.Pod) if err != nil { - return errors.Wrapf(err, "container %s is in pod %s, but pod cannot be retrieved", ctr.ID(), pod.ID()) + return errors.Wrapf(err, "container %s is in pod %s, but pod cannot be retrieved", ctr.ID(), ctr.config.Pod) } if err := r.removePod(ctx, pod, true, true, timeout); err != nil { return errors.Wrapf(err, "removing image %s: container %s using image could not be removed", imageID, ctr.ID()) diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 62ec7df60..dcc3a044f 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -380,6 +380,10 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool, } } + if err := p.maybeRemoveServiceContainer(); err != nil { + return err + } + // Remove pod from state if err := r.state.RemovePod(p); err != nil { if removalErr != nil { diff --git a/libpod/runtime_renumber.go b/libpod/runtime_renumber.go index 17e1d97e5..db055f40b 100644 --- a/libpod/runtime_renumber.go +++ b/libpod/runtime_renumber.go @@ -71,7 +71,7 @@ func (r *Runtime) renumberLocks() error { } } - r.newSystemEvent(events.Renumber) + r.NewSystemEvent(events.Renumber) return nil } diff --git a/libpod/service.go b/libpod/service.go new file mode 100644 index 000000000..c14f5e51d --- /dev/null +++ b/libpod/service.go @@ -0,0 +1,220 @@ +package libpod + +import ( + "context" + "fmt" + + "github.com/containers/podman/v4/libpod/define" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// A service consists of one or more pods. The service container is started +// before all pods and is stopped when the last pod stops. The service +// container allows for tracking and managing the entire life cycle of service +// which may be started via `podman-play-kube`. +type Service struct { + // Pods running as part of the service. + Pods []string `json:"servicePods"` +} + +// Indicates whether the pod is associated with a service container. +// The pod is expected to be updated and locked. +func (p *Pod) hasServiceContainer() bool { + return p.config.ServiceContainerID != "" +} + +// Returns the pod's service container. +// The pod is expected to be updated and locked. +func (p *Pod) serviceContainer() (*Container, error) { + id := p.config.ServiceContainerID + if id == "" { + return nil, errors.Wrap(define.ErrNoSuchCtr, "pod has no service container") + } + return p.runtime.state.Container(id) +} + +// ServiceContainer returns the service container. +func (p *Pod) ServiceContainer() (*Container, error) { + p.lock.Lock() + defer p.lock.Unlock() + if err := p.updatePod(); err != nil { + return nil, err + } + return p.serviceContainer() +} + +func (c *Container) addServicePodLocked(id string) error { + c.lock.Lock() + defer c.lock.Unlock() + if err := c.syncContainer(); err != nil { + return err + } + c.state.Service.Pods = append(c.state.Service.Pods, id) + return c.save() +} + +// IsService returns true when the container is a "service container". +func (c *Container) IsService() bool { + return c.config.IsService +} + +// canStopServiceContainerLocked returns true if all pods of the service are stopped. +// Note that the method acquires the container lock. +func (c *Container) canStopServiceContainerLocked() (bool, error) { + c.lock.Lock() + defer c.lock.Unlock() + if err := c.syncContainer(); err != nil { + return false, err + } + + if !c.IsService() { + return false, fmt.Errorf("internal error: checking service: container %s is not a service container", c.ID()) + } + + return c.canStopServiceContainer() +} + +// canStopServiceContainer returns true if all pods of the service are stopped. +// Note that the method expects the container to be locked. +func (c *Container) canStopServiceContainer() (bool, error) { + for _, id := range c.state.Service.Pods { + pod, err := c.runtime.LookupPod(id) + if err != nil { + if errors.Is(err, define.ErrNoSuchPod) { + continue + } + return false, err + } + + status, err := pod.GetPodStatus() + if err != nil { + return false, err + } + + // We can only stop the service if all pods are done. + switch status { + case define.PodStateStopped, define.PodStateExited, define.PodStateErrored: + continue + default: + return false, nil + } + } + + return true, nil +} + +// Checks whether the service container can be stopped and does so. +func (p *Pod) maybeStopServiceContainer() error { + if !p.hasServiceContainer() { + return nil + } + + serviceCtr, err := p.serviceContainer() + if err != nil { + return fmt.Errorf("getting pod's service container: %w", err) + } + // Checking whether the service can be stopped must be done in + // the runtime's work queue to resolve ABBA dead locks in the + // pod->container->servicePods hierarchy. + p.runtime.queueWork(func() { + logrus.Debugf("Pod %s has a service %s: checking if it can be stopped", p.ID(), serviceCtr.ID()) + canStop, err := serviceCtr.canStopServiceContainerLocked() + if err != nil { + logrus.Errorf("Checking whether service of container %s can be stopped: %v", serviceCtr.ID(), err) + return + } + if !canStop { + return + } + logrus.Debugf("Stopping service container %s", serviceCtr.ID()) + if err := serviceCtr.Stop(); err != nil { + logrus.Errorf("Stopping service container %s: %v", serviceCtr.ID(), err) + } + }) + return nil +} + +// Starts the pod's service container if it's not already running. +func (p *Pod) maybeStartServiceContainer(ctx context.Context) error { + if !p.hasServiceContainer() { + return nil + } + + serviceCtr, err := p.serviceContainer() + if err != nil { + return fmt.Errorf("getting pod's service container: %w", err) + } + + serviceCtr.lock.Lock() + defer serviceCtr.lock.Unlock() + + if err := serviceCtr.syncContainer(); err != nil { + return err + } + + if serviceCtr.state.State == define.ContainerStateRunning { + return nil + } + + // Restart will reinit among other things. + return serviceCtr.restartWithTimeout(ctx, 0) +} + +// canRemoveServiceContainer returns true if all pods of the service are removed. +// Note that the method acquires the container lock. +func (c *Container) canRemoveServiceContainerLocked() (bool, error) { + c.lock.Lock() + defer c.lock.Unlock() + if err := c.syncContainer(); err != nil { + return false, err + } + + if !c.IsService() { + return false, fmt.Errorf("internal error: checking service: container %s is not a service container", c.ID()) + } + + for _, id := range c.state.Service.Pods { + if _, err := c.runtime.LookupPod(id); err != nil { + if errors.Is(err, define.ErrNoSuchPod) { + continue + } + return false, err + } + return false, nil + } + + return true, nil +} + +// Checks whether the service container can be removed and does so. +func (p *Pod) maybeRemoveServiceContainer() error { + if !p.hasServiceContainer() { + return nil + } + + serviceCtr, err := p.serviceContainer() + if err != nil { + return fmt.Errorf("getting pod's service container: %w", err) + } + // Checking whether the service can be stopped must be done in + // the runtime's work queue to resolve ABBA dead locks in the + // pod->container->servicePods hierarchy. + p.runtime.queueWork(func() { + logrus.Debugf("Pod %s has a service %s: checking if it can be removed", p.ID(), serviceCtr.ID()) + canRemove, err := serviceCtr.canRemoveServiceContainerLocked() + if err != nil { + logrus.Errorf("Checking whether service of container %s can be removed: %v", serviceCtr.ID(), err) + return + } + if !canRemove { + return + } + timeout := uint(0) + logrus.Debugf("Removing service container %s", serviceCtr.ID()) + if err := p.runtime.RemoveContainer(context.Background(), serviceCtr, true, false, &timeout); err != nil { + logrus.Errorf("Removing service container %s: %v", serviceCtr.ID(), err) + } + }) + return nil +} diff --git a/pkg/api/Makefile b/pkg/api/Makefile index 6da5fb57e..d07cf6f93 100644 --- a/pkg/api/Makefile +++ b/pkg/api/Makefile @@ -1,5 +1,3 @@ -export GO111MODULE=off - SWAGGER_OUT ?= swagger.yaml validate: ${SWAGGER_OUT} diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 1c339730e..616f0a138 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -254,7 +254,7 @@ func KillContainer(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL { + if sig == 0 || sig == syscall.SIGKILL { opts := entities.WaitOptions{ Condition: []define.ContainerStatus{define.ContainerStateExited, define.ContainerStateStopped}, Interval: time.Millisecond * 250, @@ -341,8 +341,8 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error for idx, portMapping := range portMappings { ports[idx] = types.Port{ IP: portMapping.HostIP, - PrivatePort: uint16(portMapping.ContainerPort), - PublicPort: uint16(portMapping.HostPort), + PrivatePort: portMapping.ContainerPort, + PublicPort: portMapping.HostPort, Type: portMapping.Protocol, } } @@ -369,26 +369,28 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error return nil, err } - return &handlers.Container{Container: types.Container{ - ID: l.ID(), - Names: []string{fmt.Sprintf("/%s", l.Name())}, - Image: imageName, - ImageID: "sha256:" + imageID, - Command: strings.Join(l.Command(), " "), - Created: l.CreatedTime().Unix(), - Ports: ports, - SizeRw: sizeRW, - SizeRootFs: sizeRootFs, - Labels: l.Labels(), - State: stateStr, - Status: status, - HostConfig: struct { - NetworkMode string `json:",omitempty"` - }{ - "host"}, - NetworkSettings: &networkSettings, - Mounts: mounts, - }, + return &handlers.Container{ + Container: types.Container{ + ID: l.ID(), + Names: []string{fmt.Sprintf("/%s", l.Name())}, + Image: imageName, + ImageID: "sha256:" + imageID, + Command: strings.Join(l.Command(), " "), + Created: l.CreatedTime().Unix(), + Ports: ports, + SizeRw: sizeRW, + SizeRootFs: sizeRootFs, + Labels: l.Labels(), + State: stateStr, + Status: status, + HostConfig: struct { + NetworkMode string `json:",omitempty"` + }{ + "host", + }, + NetworkSettings: &networkSettings, + Mounts: mounts, + }, ContainerCreateConfig: types.ContainerCreateConfig{}, }, nil } diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go index cd592a975..b9b7f6708 100644 --- a/pkg/api/handlers/compat/containers_create.go +++ b/pkg/api/handlers/compat/containers_create.go @@ -2,18 +2,29 @@ package compat import ( "encoding/json" + "fmt" + "net" "net/http" + "os" + "path/filepath" + "strconv" + "strings" - "github.com/containers/podman/v4/cmd/podman/common" + "github.com/containers/common/libnetwork/types" + "github.com/containers/common/pkg/cgroups" + "github.com/containers/common/pkg/config" "github.com/containers/podman/v4/libpod" + "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/api/handlers" "github.com/containers/podman/v4/pkg/api/handlers/utils" api "github.com/containers/podman/v4/pkg/api/types" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/domain/infra/abi" + "github.com/containers/podman/v4/pkg/rootless" "github.com/containers/podman/v4/pkg/specgen" "github.com/containers/podman/v4/pkg/specgenutil" "github.com/containers/storage" + "github.com/docker/docker/api/types/mount" "github.com/gorilla/schema" "github.com/pkg/errors" ) @@ -70,7 +81,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { } // Take body structure and convert to cliopts - cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(body, rtc) + cliOpts, args, err := cliOpts(body, rtc) if err != nil { utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "make cli opts()")) return @@ -107,3 +118,456 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { } utils.WriteResponse(w, http.StatusCreated, createResponse) } + +func stringMaptoArray(m map[string]string) []string { + a := make([]string, 0, len(m)) + for k, v := range m { + a = append(a, fmt.Sprintf("%s=%s", k, v)) + } + return a +} + +// cliOpts converts a compat input struct to cliopts +func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.ContainerCreateOptions, []string, error) { + var ( + capAdd []string + cappDrop []string + entrypoint *string + init bool + specPorts []types.PortMapping + ) + + if cc.HostConfig.Init != nil { + init = *cc.HostConfig.Init + } + + // Iterate devices and convert to CLI expected string + devices := make([]string, 0, len(cc.HostConfig.Devices)) + for _, dev := range cc.HostConfig.Devices { + devices = append(devices, fmt.Sprintf("%s:%s:%s", dev.PathOnHost, dev.PathInContainer, dev.CgroupPermissions)) + } + + // iterate blkreaddevicebps + readBps := make([]string, 0, len(cc.HostConfig.BlkioDeviceReadBps)) + for _, dev := range cc.HostConfig.BlkioDeviceReadBps { + readBps = append(readBps, dev.String()) + } + + // iterate blkreaddeviceiops + readIops := make([]string, 0, len(cc.HostConfig.BlkioDeviceReadIOps)) + for _, dev := range cc.HostConfig.BlkioDeviceReadIOps { + readIops = append(readIops, dev.String()) + } + + // iterate blkwritedevicebps + writeBps := make([]string, 0, len(cc.HostConfig.BlkioDeviceWriteBps)) + for _, dev := range cc.HostConfig.BlkioDeviceWriteBps { + writeBps = append(writeBps, dev.String()) + } + + // iterate blkwritedeviceiops + writeIops := make([]string, 0, len(cc.HostConfig.BlkioDeviceWriteIOps)) + for _, dev := range cc.HostConfig.BlkioDeviceWriteIOps { + writeIops = append(writeIops, dev.String()) + } + + // entrypoint + // can be a string or slice. if it is a slice, we need to + // marshall it to json; otherwise it should just be the string + // value + if len(cc.Config.Entrypoint) > 0 { + entrypoint = &cc.Config.Entrypoint[0] + if len(cc.Config.Entrypoint) > 1 { + b, err := json.Marshal(cc.Config.Entrypoint) + if err != nil { + return nil, nil, err + } + jsonString := string(b) + entrypoint = &jsonString + } + } + + // expose ports + expose := make([]string, 0, len(cc.Config.ExposedPorts)) + for p := range cc.Config.ExposedPorts { + expose = append(expose, fmt.Sprintf("%s/%s", p.Port(), p.Proto())) + } + + // mounts type=tmpfs/bind,source=...,target=...=,opt=val + volSources := make(map[string]bool) + volDestinations := make(map[string]bool) + mounts := make([]string, 0, len(cc.HostConfig.Mounts)) + var builder strings.Builder + for _, m := range cc.HostConfig.Mounts { + addField(&builder, "type", string(m.Type)) + addField(&builder, "source", m.Source) + addField(&builder, "target", m.Target) + + // Store source/dest so we don't add duplicates if a volume is + // also mentioned in cc.Volumes. + // Which Docker Compose v2.0 does, for unclear reasons... + volSources[m.Source] = true + volDestinations[m.Target] = true + + if m.ReadOnly { + addField(&builder, "ro", "true") + } + addField(&builder, "consistency", string(m.Consistency)) + // Map any specialized mount options that intersect between *Options and cli options + switch m.Type { + case mount.TypeBind: + if m.BindOptions != nil { + addField(&builder, "bind-propagation", string(m.BindOptions.Propagation)) + addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive)) + } + case mount.TypeTmpfs: + if m.TmpfsOptions != nil { + addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10)) + addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 8)) + } + case mount.TypeVolume: + // All current VolumeOpts are handled above + // See vendor/github.com/containers/common/pkg/parse/parse.go:ValidateVolumeOpts() + } + mounts = append(mounts, builder.String()) + builder.Reset() + } + + // dns + dns := make([]net.IP, 0, len(cc.HostConfig.DNS)) + for _, d := range cc.HostConfig.DNS { + dns = append(dns, net.ParseIP(d)) + } + + // publish + for port, pbs := range cc.HostConfig.PortBindings { + for _, pb := range pbs { + var hostport int + var err error + if pb.HostPort != "" { + hostport, err = strconv.Atoi(pb.HostPort) + } + if err != nil { + return nil, nil, err + } + tmpPort := types.PortMapping{ + HostIP: pb.HostIP, + ContainerPort: uint16(port.Int()), + HostPort: uint16(hostport), + Range: 0, + Protocol: port.Proto(), + } + specPorts = append(specPorts, tmpPort) + } + } + + // netMode + nsmode, networks, netOpts, err := specgen.ParseNetworkFlag([]string{string(cc.HostConfig.NetworkMode)}) + if err != nil { + return nil, nil, err + } + + // network + // Note: we cannot emulate compat exactly here. we only allow specifics of networks to be + // defined when there is only one network. + netInfo := entities.NetOptions{ + AddHosts: cc.HostConfig.ExtraHosts, + DNSOptions: cc.HostConfig.DNSOptions, + DNSSearch: cc.HostConfig.DNSSearch, + DNSServers: dns, + Network: nsmode, + PublishPorts: specPorts, + NetworkOptions: netOpts, + } + + // network names + switch { + case len(cc.NetworkingConfig.EndpointsConfig) > 0: + endpointsConfig := cc.NetworkingConfig.EndpointsConfig + networks := make(map[string]types.PerNetworkOptions, len(endpointsConfig)) + for netName, endpoint := range endpointsConfig { + netOpts := types.PerNetworkOptions{} + if endpoint != nil { + netOpts.Aliases = endpoint.Aliases + + // if IP address is provided + if len(endpoint.IPAddress) > 0 { + staticIP := net.ParseIP(endpoint.IPAddress) + if staticIP == nil { + return nil, nil, errors.Errorf("failed to parse the ip address %q", endpoint.IPAddress) + } + netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP) + } + + if endpoint.IPAMConfig != nil { + // if IPAMConfig.IPv4Address is provided + if len(endpoint.IPAMConfig.IPv4Address) > 0 { + staticIP := net.ParseIP(endpoint.IPAMConfig.IPv4Address) + if staticIP == nil { + return nil, nil, errors.Errorf("failed to parse the ipv4 address %q", endpoint.IPAMConfig.IPv4Address) + } + netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP) + } + // if IPAMConfig.IPv6Address is provided + if len(endpoint.IPAMConfig.IPv6Address) > 0 { + staticIP := net.ParseIP(endpoint.IPAMConfig.IPv6Address) + if staticIP == nil { + return nil, nil, errors.Errorf("failed to parse the ipv6 address %q", endpoint.IPAMConfig.IPv6Address) + } + netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP) + } + } + // If MAC address is provided + if len(endpoint.MacAddress) > 0 { + staticMac, err := net.ParseMAC(endpoint.MacAddress) + if err != nil { + return nil, nil, errors.Errorf("failed to parse the mac address %q", endpoint.MacAddress) + } + netOpts.StaticMAC = types.HardwareAddr(staticMac) + } + } + + networks[netName] = netOpts + } + + netInfo.Networks = networks + case len(cc.HostConfig.NetworkMode) > 0: + netInfo.Networks = networks + } + + parsedTmp := make([]string, 0, len(cc.HostConfig.Tmpfs)) + for path, options := range cc.HostConfig.Tmpfs { + finalString := path + if options != "" { + finalString += ":" + options + } + parsedTmp = append(parsedTmp, finalString) + } + + // Note: several options here are marked as "don't need". this is based + // on speculation by Matt and I. We think that these come into play later + // like with start. We believe this is just a difference in podman/compat + cliOpts := entities.ContainerCreateOptions{ + // Attach: nil, // don't need? + Authfile: "", + CapAdd: append(capAdd, cc.HostConfig.CapAdd...), + CapDrop: append(cappDrop, cc.HostConfig.CapDrop...), + CgroupParent: cc.HostConfig.CgroupParent, + CIDFile: cc.HostConfig.ContainerIDFile, + CPUPeriod: uint64(cc.HostConfig.CPUPeriod), + CPUQuota: cc.HostConfig.CPUQuota, + CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod), + CPURTRuntime: cc.HostConfig.CPURealtimeRuntime, + CPUShares: uint64(cc.HostConfig.CPUShares), + // CPUS: 0, // don't need? + CPUSetCPUs: cc.HostConfig.CpusetCpus, + CPUSetMems: cc.HostConfig.CpusetMems, + // Detach: false, // don't need + // DetachKeys: "", // don't need + Devices: devices, + DeviceCgroupRule: nil, + DeviceReadBPs: readBps, + DeviceReadIOPs: readIops, + DeviceWriteBPs: writeBps, + DeviceWriteIOPs: writeIops, + Entrypoint: entrypoint, + Env: cc.Config.Env, + Expose: expose, + GroupAdd: cc.HostConfig.GroupAdd, + Hostname: cc.Config.Hostname, + ImageVolume: "bind", + Init: init, + Interactive: cc.Config.OpenStdin, + IPC: string(cc.HostConfig.IpcMode), + Label: stringMaptoArray(cc.Config.Labels), + LogDriver: cc.HostConfig.LogConfig.Type, + LogOptions: stringMaptoArray(cc.HostConfig.LogConfig.Config), + Name: cc.Name, + OOMScoreAdj: &cc.HostConfig.OomScoreAdj, + Arch: "", + OS: "", + Variant: "", + PID: string(cc.HostConfig.PidMode), + PIDsLimit: cc.HostConfig.PidsLimit, + Privileged: cc.HostConfig.Privileged, + PublishAll: cc.HostConfig.PublishAllPorts, + Quiet: false, + ReadOnly: cc.HostConfig.ReadonlyRootfs, + ReadOnlyTmpFS: true, // podman default + Rm: cc.HostConfig.AutoRemove, + SecurityOpt: cc.HostConfig.SecurityOpt, + StopSignal: cc.Config.StopSignal, + StorageOpts: stringMaptoArray(cc.HostConfig.StorageOpt), + Sysctl: stringMaptoArray(cc.HostConfig.Sysctls), + Systemd: "true", // podman default + TmpFS: parsedTmp, + TTY: cc.Config.Tty, + UnsetEnv: cc.UnsetEnv, + UnsetEnvAll: cc.UnsetEnvAll, + User: cc.Config.User, + UserNS: string(cc.HostConfig.UsernsMode), + UTS: string(cc.HostConfig.UTSMode), + Mount: mounts, + VolumesFrom: cc.HostConfig.VolumesFrom, + Workdir: cc.Config.WorkingDir, + Net: &netInfo, + HealthInterval: define.DefaultHealthCheckInterval, + HealthRetries: define.DefaultHealthCheckRetries, + HealthTimeout: define.DefaultHealthCheckTimeout, + HealthStartPeriod: define.DefaultHealthCheckStartPeriod, + } + if !rootless.IsRootless() { + var ulimits []string + if len(cc.HostConfig.Ulimits) > 0 { + for _, ul := range cc.HostConfig.Ulimits { + ulimits = append(ulimits, ul.String()) + } + cliOpts.Ulimit = ulimits + } + } + if cc.HostConfig.Resources.NanoCPUs > 0 { + if cliOpts.CPUPeriod != 0 || cliOpts.CPUQuota != 0 { + return nil, nil, errors.Errorf("NanoCpus conflicts with CpuPeriod and CpuQuota") + } + cliOpts.CPUPeriod = 100000 + cliOpts.CPUQuota = cc.HostConfig.Resources.NanoCPUs / 10000 + } + + // volumes + for _, vol := range cc.HostConfig.Binds { + cliOpts.Volume = append(cliOpts.Volume, vol) + // Extract the destination so we don't add duplicate mounts in + // the volumes phase. + splitVol := strings.SplitN(vol, ":", 3) + switch len(splitVol) { + case 1: + volDestinations[vol] = true + default: + volSources[splitVol[0]] = true + volDestinations[splitVol[1]] = true + } + } + // Anonymous volumes are added differently from other volumes, in their + // own special field, for reasons known only to Docker. Still use the + // format of `-v` so we can just append them in there. + // Unfortunately, these may be duplicates of existing mounts in Binds. + // So... We need to catch that. + // This also handles volumes duplicated between cc.HostConfig.Mounts and + // cc.Volumes, as seen in compose v2.0. + for vol := range cc.Volumes { + if _, ok := volDestinations[filepath.Clean(vol)]; ok { + continue + } + cliOpts.Volume = append(cliOpts.Volume, vol) + } + // Make mount points for compat volumes + for vol := range volSources { + // This might be a named volume. + // Assume it is if it's not an absolute path. + if !filepath.IsAbs(vol) { + continue + } + // If volume already exists, there is nothing to do + if _, err := os.Stat(vol); err == nil { + continue + } + if err := os.MkdirAll(vol, 0o755); err != nil { + if !os.IsExist(err) { + return nil, nil, errors.Wrapf(err, "error making volume mountpoint for volume %s", vol) + } + } + } + if len(cc.HostConfig.BlkioWeightDevice) > 0 { + devices := make([]string, 0, len(cc.HostConfig.BlkioWeightDevice)) + for _, d := range cc.HostConfig.BlkioWeightDevice { + devices = append(devices, d.String()) + } + cliOpts.BlkIOWeightDevice = devices + } + if cc.HostConfig.BlkioWeight > 0 { + cliOpts.BlkIOWeight = strconv.Itoa(int(cc.HostConfig.BlkioWeight)) + } + + if cc.HostConfig.Memory > 0 { + cliOpts.Memory = strconv.Itoa(int(cc.HostConfig.Memory)) + } + + if cc.HostConfig.MemoryReservation > 0 { + cliOpts.MemoryReservation = strconv.Itoa(int(cc.HostConfig.MemoryReservation)) + } + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + if err != nil { + return nil, nil, err + } + if cc.HostConfig.MemorySwap > 0 && (!rootless.IsRootless() || (rootless.IsRootless() && cgroupsv2)) { + cliOpts.MemorySwap = strconv.Itoa(int(cc.HostConfig.MemorySwap)) + } + + if cc.Config.StopTimeout != nil { + cliOpts.StopTimeout = uint(*cc.Config.StopTimeout) + } + + if cc.HostConfig.ShmSize > 0 { + cliOpts.ShmSize = strconv.Itoa(int(cc.HostConfig.ShmSize)) + } + + if len(cc.HostConfig.RestartPolicy.Name) > 0 { + policy := cc.HostConfig.RestartPolicy.Name + // only add restart count on failure + if cc.HostConfig.RestartPolicy.IsOnFailure() { + policy += fmt.Sprintf(":%d", cc.HostConfig.RestartPolicy.MaximumRetryCount) + } + cliOpts.Restart = policy + } + + if cc.HostConfig.MemorySwappiness != nil && (!rootless.IsRootless() || rootless.IsRootless() && cgroupsv2 && rtc.Engine.CgroupManager == "systemd") { + cliOpts.MemorySwappiness = *cc.HostConfig.MemorySwappiness + } else { + cliOpts.MemorySwappiness = -1 + } + if cc.HostConfig.OomKillDisable != nil { + cliOpts.OOMKillDisable = *cc.HostConfig.OomKillDisable + } + if cc.Config.Healthcheck != nil { + finCmd := "" + for _, str := range cc.Config.Healthcheck.Test { + finCmd = finCmd + str + " " + } + if len(finCmd) > 1 { + finCmd = finCmd[:len(finCmd)-1] + } + cliOpts.HealthCmd = finCmd + if cc.Config.Healthcheck.Interval > 0 { + cliOpts.HealthInterval = cc.Config.Healthcheck.Interval.String() + } + if cc.Config.Healthcheck.Retries > 0 { + cliOpts.HealthRetries = uint(cc.Config.Healthcheck.Retries) + } + if cc.Config.Healthcheck.StartPeriod > 0 { + cliOpts.HealthStartPeriod = cc.Config.Healthcheck.StartPeriod.String() + } + if cc.Config.Healthcheck.Timeout > 0 { + cliOpts.HealthTimeout = cc.Config.Healthcheck.Timeout.String() + } + } + + // specgen assumes the image name is arg[0] + cmd := []string{cc.Config.Image} + cmd = append(cmd, cc.Config.Cmd...) + return &cliOpts, cmd, nil +} + +// addField is a helper function to populate mount options +func addField(b *strings.Builder, name, value string) { + if value == "" { + return + } + + if b.Len() > 0 { + b.WriteRune(',') + } + b.WriteString(name) + b.WriteRune('=') + b.WriteString(value) +} diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go index 03b3d54bc..6bcb7bd32 100644 --- a/pkg/api/handlers/compat/events.go +++ b/pkg/api/handlers/compat/events.go @@ -63,7 +63,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) { errorChannel <- runtime.Events(r.Context(), readOpts) }() - var flush = func() {} + flush := func() {} if flusher, ok := w.(http.Flusher); ok { flush = flusher.Flush } diff --git a/pkg/api/handlers/compat/exec.go b/pkg/api/handlers/compat/exec.go index def16d1b5..a8b45c685 100644 --- a/pkg/api/handlers/compat/exec.go +++ b/pkg/api/handlers/compat/exec.go @@ -11,6 +11,7 @@ import ( "github.com/containers/podman/v4/pkg/api/handlers/utils" "github.com/containers/podman/v4/pkg/api/server/idle" api "github.com/containers/podman/v4/pkg/api/types" + "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/specgenutil" "github.com/gorilla/mux" "github.com/pkg/errors" @@ -93,10 +94,7 @@ func ExecCreateHandler(w http.ResponseWriter, r *http.Request) { return } - resp := new(handlers.ExecCreateResponse) - resp.ID = sessID - - utils.WriteResponse(w, http.StatusCreated, resp) + utils.WriteResponse(w, http.StatusCreated, entities.IDResponse{ID: sessID}) } // ExecInspectHandler inspects a given exec session. diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index a690cdd40..8c4dea327 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -165,7 +165,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) { utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure")) return } - utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: commitImage.ID()}) // nolint + utils.WriteResponse(w, http.StatusCreated, entities.IDResponse{ID: commitImage.ID()}) // nolint } func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index f0d07f492..bcd102901 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -119,6 +119,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Registry string `schema:"registry"` Rm bool `schema:"rm"` RusageLogFile string `schema:"rusagelogfile"` + Remote string `schema:"remote"` Seccomp string `schema:"seccomp"` Secrets string `schema:"secrets"` SecurityOpt string `schema:"securityopt"` @@ -169,14 +170,50 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { // convert addcaps formats containerFiles := []string{} - if _, found := r.URL.Query()["dockerfile"]; found { - var m = []string{} - if err := json.Unmarshal([]byte(query.Dockerfile), &m); err != nil { - // it's not json, assume just a string - m = []string{filepath.Join(contextDirectory, query.Dockerfile)} + // Tells if query paramemter `dockerfile` is set or not. + dockerFileSet := false + if utils.IsLibpodRequest(r) && query.Remote != "" { + // The context directory could be a URL. Try to handle that. + anchorDir, err := ioutil.TempDir(parse.GetTempDir(), "libpod_builder") + if err != nil { + utils.InternalServerError(w, err) + } + tempDir, subDir, err := buildahDefine.TempDirForURL(anchorDir, "buildah", query.Remote) + if err != nil { + utils.InternalServerError(w, err) + } + if tempDir != "" { + // We had to download it to a temporary directory. + // Delete it later. + defer func() { + if err = os.RemoveAll(tempDir); err != nil { + // We are deleting this on server so log on server end + // client does not have to worry about server cleanup. + logrus.Errorf("Cannot delete downloaded temp dir %q: %s", tempDir, err) + } + }() + contextDirectory = filepath.Join(tempDir, subDir) + } else { + // Nope, it was local. Use it as is. + absDir, err := filepath.Abs(query.Remote) + if err != nil { + utils.BadRequest(w, "remote", query.Remote, err) + } + contextDirectory = absDir } - containerFiles = m } else { + if _, found := r.URL.Query()["dockerfile"]; found { + var m = []string{} + if err := json.Unmarshal([]byte(query.Dockerfile), &m); err != nil { + // it's not json, assume just a string + m = []string{filepath.Join(contextDirectory, query.Dockerfile)} + } + containerFiles = m + dockerFileSet = true + } + } + + if !dockerFileSet { containerFiles = []string{filepath.Join(contextDirectory, "Dockerfile")} if utils.IsLibpodRequest(r) { containerFiles = []string{filepath.Join(contextDirectory, "Containerfile")} @@ -568,7 +605,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Output: output, OutputFormat: format, PullPolicy: pullPolicy, - PullPushRetryDelay: time.Duration(2 * time.Second), + PullPushRetryDelay: 2 * time.Second, Quiet: query.Quiet, Registry: registry, RemoveIntermediateCtrs: query.Rm, @@ -739,7 +776,7 @@ func extractTarFile(r *http.Request) (string, error) { } path := filepath.Join(anchorDir, "tarBall") - tarBall, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + tarBall, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600) if err != nil { return "", err } @@ -753,7 +790,7 @@ func extractTarFile(r *http.Request) (string, error) { } buildDir := filepath.Join(anchorDir, "build") - err = os.Mkdir(buildDir, 0700) + err = os.Mkdir(buildDir, 0o700) if err != nil { return "", err } diff --git a/pkg/api/handlers/compat/images_prune.go b/pkg/api/handlers/compat/images_prune.go index 46524fcff..02cadbbbe 100644 --- a/pkg/api/handlers/compat/images_prune.go +++ b/pkg/api/handlers/compat/images_prune.go @@ -17,9 +17,7 @@ import ( ) func PruneImages(w http.ResponseWriter, r *http.Request) { - var ( - filters []string - ) + var filters []string runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) filterMap, err := util.PrepareFilters(r) diff --git a/pkg/api/handlers/compat/images_remove.go b/pkg/api/handlers/compat/images_remove.go index f45b38c66..35bcb36aa 100644 --- a/pkg/api/handlers/compat/images_remove.go +++ b/pkg/api/handlers/compat/images_remove.go @@ -52,7 +52,10 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) { utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name)) return } - + if errors.Cause(err) == storage.ErrImageUsedByContainer { + utils.Error(w, http.StatusConflict, errors.Wrapf(err, "image %s is in use", name)) + return + } utils.Error(w, http.StatusInternalServerError, err) return } diff --git a/pkg/api/handlers/compat/info.go b/pkg/api/handlers/compat/info.go index 6286fdaee..85547570a 100644 --- a/pkg/api/handlers/compat/info.go +++ b/pkg/api/handlers/compat/info.go @@ -53,75 +53,76 @@ func GetInfo(w http.ResponseWriter, r *http.Request) { // FIXME: Need to expose if runtime supports Checkpointing // liveRestoreEnabled := criu.CheckForCriu() && configInfo.RuntimeSupportsCheckpoint() - info := &handlers.Info{Info: docker.Info{ - Architecture: goRuntime.GOARCH, - BridgeNfIP6tables: !sysInfo.BridgeNFCallIP6TablesDisabled, - BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled, - CPUCfsPeriod: sysInfo.CPUCfsPeriod, - CPUCfsQuota: sysInfo.CPUCfsQuota, - CPUSet: sysInfo.Cpuset, - CPUShares: sysInfo.CPUShares, - CgroupDriver: configInfo.Engine.CgroupManager, - ClusterAdvertise: "", - ClusterStore: "", - ContainerdCommit: docker.Commit{}, - Containers: infoData.Store.ContainerStore.Number, - ContainersPaused: stateInfo[define.ContainerStatePaused], - ContainersRunning: stateInfo[define.ContainerStateRunning], - ContainersStopped: stateInfo[define.ContainerStateStopped] + stateInfo[define.ContainerStateExited], - Debug: log.IsLevelEnabled(log.DebugLevel), - DefaultRuntime: configInfo.Engine.OCIRuntime, - DockerRootDir: infoData.Store.GraphRoot, - Driver: infoData.Store.GraphDriverName, - DriverStatus: getGraphStatus(infoData.Store.GraphStatus), - ExperimentalBuild: true, - GenericResources: nil, - HTTPProxy: getEnv("http_proxy"), - HTTPSProxy: getEnv("https_proxy"), - ID: uuid.New().String(), - IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled, - Images: infoData.Store.ImageStore.Number, - IndexServerAddress: "", - InitBinary: "", - InitCommit: docker.Commit{}, - Isolation: "", - KernelMemoryTCP: false, - KernelVersion: infoData.Host.Kernel, - Labels: nil, - LiveRestoreEnabled: false, - LoggingDriver: "", - MemTotal: infoData.Host.MemTotal, - MemoryLimit: sysInfo.MemoryLimit, - NCPU: goRuntime.NumCPU(), - NEventsListener: 0, - NFd: getFdCount(), - NGoroutines: goRuntime.NumGoroutine(), - Name: infoData.Host.Hostname, - NoProxy: getEnv("no_proxy"), - OSType: goRuntime.GOOS, - OSVersion: infoData.Host.Distribution.Version, - OomKillDisable: sysInfo.OomKillDisable, - OperatingSystem: infoData.Host.Distribution.Distribution, - PidsLimit: sysInfo.PidsLimit, - Plugins: docker.PluginsInfo{ - Volume: infoData.Plugins.Volume, - Network: infoData.Plugins.Network, - Log: infoData.Plugins.Log, + info := &handlers.Info{ + Info: docker.Info{ + Architecture: goRuntime.GOARCH, + BridgeNfIP6tables: !sysInfo.BridgeNFCallIP6TablesDisabled, + BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled, + CPUCfsPeriod: sysInfo.CPUCfsPeriod, + CPUCfsQuota: sysInfo.CPUCfsQuota, + CPUSet: sysInfo.Cpuset, + CPUShares: sysInfo.CPUShares, + CgroupDriver: configInfo.Engine.CgroupManager, + ClusterAdvertise: "", + ClusterStore: "", + ContainerdCommit: docker.Commit{}, + Containers: infoData.Store.ContainerStore.Number, + ContainersPaused: stateInfo[define.ContainerStatePaused], + ContainersRunning: stateInfo[define.ContainerStateRunning], + ContainersStopped: stateInfo[define.ContainerStateStopped] + stateInfo[define.ContainerStateExited], + Debug: log.IsLevelEnabled(log.DebugLevel), + DefaultRuntime: configInfo.Engine.OCIRuntime, + DockerRootDir: infoData.Store.GraphRoot, + Driver: infoData.Store.GraphDriverName, + DriverStatus: getGraphStatus(infoData.Store.GraphStatus), + ExperimentalBuild: true, + GenericResources: nil, + HTTPProxy: getEnv("http_proxy"), + HTTPSProxy: getEnv("https_proxy"), + ID: uuid.New().String(), + IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled, + Images: infoData.Store.ImageStore.Number, + IndexServerAddress: "", + InitBinary: "", + InitCommit: docker.Commit{}, + Isolation: "", + KernelMemoryTCP: false, + KernelVersion: infoData.Host.Kernel, + Labels: nil, + LiveRestoreEnabled: false, + LoggingDriver: "", + MemTotal: infoData.Host.MemTotal, + MemoryLimit: sysInfo.MemoryLimit, + NCPU: goRuntime.NumCPU(), + NEventsListener: 0, + NFd: getFdCount(), + NGoroutines: goRuntime.NumGoroutine(), + Name: infoData.Host.Hostname, + NoProxy: getEnv("no_proxy"), + OSType: goRuntime.GOOS, + OSVersion: infoData.Host.Distribution.Version, + OomKillDisable: sysInfo.OomKillDisable, + OperatingSystem: infoData.Host.Distribution.Distribution, + PidsLimit: sysInfo.PidsLimit, + Plugins: docker.PluginsInfo{ + Volume: infoData.Plugins.Volume, + Network: infoData.Plugins.Network, + Log: infoData.Plugins.Log, + }, + ProductLicense: "Apache-2.0", + RegistryConfig: getServiceConfig(runtime), + RuncCommit: docker.Commit{}, + Runtimes: getRuntimes(configInfo), + SecurityOptions: getSecOpts(sysInfo), + ServerVersion: versionInfo.Version, + SwapLimit: sysInfo.SwapLimit, + Swarm: swarm.Info{ + LocalNodeState: swarm.LocalNodeStateInactive, + }, + SystemStatus: nil, + SystemTime: time.Now().Format(time.RFC3339Nano), + Warnings: []string{}, }, - ProductLicense: "Apache-2.0", - RegistryConfig: getServiceConfig(runtime), - RuncCommit: docker.Commit{}, - Runtimes: getRuntimes(configInfo), - SecurityOptions: getSecOpts(sysInfo), - ServerVersion: versionInfo.Version, - SwapLimit: sysInfo.SwapLimit, - Swarm: swarm.Info{ - LocalNodeState: swarm.LocalNodeStateInactive, - }, - SystemStatus: nil, - SystemTime: time.Now().Format(time.RFC3339Nano), - Warnings: []string{}, - }, BuildahVersion: infoData.Host.BuildahVersion, CPURealtimePeriod: sysInfo.CPURealtimePeriod, CPURealtimeRuntime: sysInfo.CPURealtimeRuntime, @@ -186,7 +187,7 @@ func getSecOpts(sysInfo *sysinfo.SysInfo) []string { } func getRuntimes(configInfo *config.Config) map[string]docker.Runtime { - var runtimes = map[string]docker.Runtime{} + runtimes := map[string]docker.Runtime{} for name, paths := range configInfo.Engine.OCIRuntimes { runtimes[name] = docker.Runtime{ Path: paths[0], @@ -206,7 +207,7 @@ func getFdCount() (count int) { // Just ignoring Container errors here... func getContainersState(r *libpod.Runtime) map[define.ContainerStatus]int { - var states = map[define.ContainerStatus]int{} + states := map[define.ContainerStatus]int{} ctnrs, err := r.GetAllContainers() if err == nil { for _, ctnr := range ctnrs { diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go index 89d914e0a..6fdd5c6a7 100644 --- a/pkg/api/handlers/compat/networks.go +++ b/pkg/api/handlers/compat/networks.go @@ -298,9 +298,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) { func Connect(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - var ( - netConnect types.NetworkConnect - ) + var netConnect types.NetworkConnect if err := json.NewDecoder(r.Body).Decode(&netConnect); err != nil { utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()")) return diff --git a/pkg/api/handlers/compat/secrets.go b/pkg/api/handlers/compat/secrets.go index 0c2306dc8..5031bf76b 100644 --- a/pkg/api/handlers/compat/secrets.go +++ b/pkg/api/handlers/compat/secrets.go @@ -16,9 +16,7 @@ import ( ) func ListSecrets(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) filtersMap, err := util.PrepareFilters(r) if err != nil { utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) @@ -51,9 +49,7 @@ func ListSecrets(w http.ResponseWriter, r *http.Request) { } func InspectSecret(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) name := utils.GetName(r) names := []string{name} ic := abi.ContainerEngine{Libpod: runtime} @@ -84,9 +80,7 @@ func InspectSecret(w http.ResponseWriter, r *http.Request) { } func RemoveSecret(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) opts := entities.SecretRmOptions{} name := utils.GetName(r) @@ -104,9 +98,7 @@ func RemoveSecret(w http.ResponseWriter, r *http.Request) { } func CreateSecret(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) opts := entities.SecretCreateOptions{} createParams := struct { *entities.SecretCreateRequest diff --git a/pkg/api/handlers/compat/swagger.go b/pkg/api/handlers/compat/swagger.go deleted file mode 100644 index 86527da6e..000000000 --- a/pkg/api/handlers/compat/swagger.go +++ /dev/null @@ -1,67 +0,0 @@ -package compat - -import ( - "github.com/containers/podman/v4/pkg/domain/entities" - "github.com/docker/docker/api/types" -) - -// Create container -// swagger:response ContainerCreateResponse -type swagCtrCreateResponse struct { - // in:body - Body struct { - entities.ContainerCreateResponse - } -} - -// Wait container -// swagger:response ContainerWaitResponse -type swagCtrWaitResponse struct { - // in:body - Body struct { - // container exit code - StatusCode int - Error struct { - Message string - } - } -} - -// Network inspect -// swagger:response CompatNetworkInspect -type swagCompatNetworkInspect struct { - // in:body - Body types.NetworkResource -} - -// Network list -// swagger:response CompatNetworkList -type swagCompatNetworkList struct { - // in:body - Body []types.NetworkResource -} - -// Network create -// swagger:model NetworkCreateRequest -type NetworkCreateRequest struct { - types.NetworkCreateRequest -} - -// Network create -// swagger:response CompatNetworkCreate -type swagCompatNetworkCreateResponse struct { - // in:body - Body struct{ types.NetworkCreate } -} - -// Network disconnect -// swagger:model NetworkCompatConnectRequest -type swagCompatNetworkConnectRequest struct { - types.NetworkConnect -} - -// Network disconnect -// swagger:model NetworkCompatDisconnectRequest -type swagCompatNetworkDisconnectRequest struct { - types.NetworkDisconnect -} diff --git a/pkg/api/handlers/compat/version.go b/pkg/api/handlers/compat/version.go index b113fbc90..cfc3468c2 100644 --- a/pkg/api/handlers/compat/version.go +++ b/pkg/api/handlers/compat/version.go @@ -57,13 +57,15 @@ func VersionHandler(w http.ResponseWriter, r *http.Request) { Version: conmon.Version, Details: map[string]string{ "Package": conmon.Package, - }}, + }, + }, { Name: fmt.Sprintf("OCI Runtime (%s)", oci.Name), Version: oci.Version, Details: map[string]string{ "Package": oci.Package, - }}, + }, + }, } components = append(components, additional...) } @@ -89,5 +91,6 @@ func VersionHandler(w http.ResponseWriter, r *http.Request) { MinAPIVersion: fmt.Sprintf("%d.%d", minVersion.Major, minVersion.Minor), Os: components[0].Details["Os"], Version: components[0].Version, - }}) + }, + }) } diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go index c8e4339b0..ff0a7af02 100644 --- a/pkg/api/handlers/compat/volumes.go +++ b/pkg/api/handlers/compat/volumes.go @@ -180,9 +180,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { } func InspectVolume(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) name := utils.GetName(r) vol, err := runtime.GetVolume(name) if err != nil { @@ -263,9 +261,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) { } func PruneVolumes(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) filterMap, err := util.PrepareFilters(r) if err != nil { utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()")) diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index 03dd436f6..6b5bee403 100644 --- a/pkg/api/handlers/libpod/containers.go +++ b/pkg/api/handlers/libpod/containers.go @@ -168,6 +168,7 @@ func UnmountContainer(w http.ResponseWriter, r *http.Request) { } utils.WriteResponse(w, http.StatusNoContent, "") } + func MountContainer(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) name := utils.GetName(r) diff --git a/pkg/api/handlers/libpod/generate.go b/pkg/api/handlers/libpod/generate.go index 28785b00d..b1ac6a65a 100644 --- a/pkg/api/handlers/libpod/generate.go +++ b/pkg/api/handlers/libpod/generate.go @@ -41,17 +41,17 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) { return } - var ContainerPrefix = "container" + ContainerPrefix := "container" if query.ContainerPrefix != nil { ContainerPrefix = *query.ContainerPrefix } - var PodPrefix = "pod" + PodPrefix := "pod" if query.PodPrefix != nil { PodPrefix = *query.PodPrefix } - var Separator = "-" + Separator := "-" if query.Separator != nil { Separator = *query.Separator } @@ -106,5 +106,7 @@ func GenerateKube(w http.ResponseWriter, r *http.Request) { return } + // FIXME: Content-Type is being set as application/x-tar NOT text/vnd.yaml + // https://mailarchive.ietf.org/arch/msg/media-types/e9ZNC0hDXKXeFlAVRWxLCCaG9GI/ utils.WriteResponse(w, http.StatusOK, report.Reader) } diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index cddf4c205..efcbe9d77 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -102,9 +102,7 @@ func GetImage(w http.ResponseWriter, r *http.Request) { } func PruneImages(w http.ResponseWriter, r *http.Request) { - var ( - err error - ) + var err error runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { @@ -129,7 +127,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) { return } - var libpodFilters = []string{} + libpodFilters := []string{} if _, found := r.URL.Query()["filters"]; found { dangling := (*filterMap)["all"] if len(dangling) > 0 { @@ -162,9 +160,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) { } func ExportImage(w http.ResponseWriter, r *http.Request) { - var ( - output string - ) + var output string runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { @@ -243,9 +239,7 @@ func ExportImage(w http.ResponseWriter, r *http.Request) { } func ExportImages(w http.ResponseWriter, r *http.Request) { - var ( - output string - ) + var output string runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { @@ -566,7 +560,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) { utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure")) return } - utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: commitImage.ID()}) // nolint + utils.WriteResponse(w, http.StatusOK, entities.IDResponse{ID: commitImage.ID()}) // nolint } func UntagImage(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go index 8dc7c57d5..65b9d6cb5 100644 --- a/pkg/api/handlers/libpod/manifests.go +++ b/pkg/api/handlers/libpod/manifests.go @@ -88,7 +88,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) { // Treat \r\n as empty body if len(buffer) < 3 { - utils.WriteResponse(w, status, handlers.IDResponse{ID: manID}) + utils.WriteResponse(w, status, entities.IDResponse{ID: manID}) return } @@ -113,7 +113,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) { return } - utils.WriteResponse(w, status, handlers.IDResponse{ID: id}) + utils.WriteResponse(w, status, entities.IDResponse{ID: id}) } // ManifestExists return true if manifest list exists. @@ -204,7 +204,7 @@ func ManifestAddV3(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: newID}) + utils.WriteResponse(w, http.StatusOK, entities.IDResponse{ID: newID}) } // ManifestRemoveDigestV3 remove digest from manifest list @@ -238,7 +238,7 @@ func ManifestRemoveDigestV3(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: manifestList.ID()}) + utils.WriteResponse(w, http.StatusOK, entities.IDResponse{ID: manifestList.ID()}) } // ManifestPushV3 push image to registry @@ -294,7 +294,7 @@ func ManifestPushV3(w http.ResponseWriter, r *http.Request) { utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "error pushing image %q", query.Destination)) return } - utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: digest}) + utils.WriteResponse(w, http.StatusOK, entities.IDResponse{ID: digest}) } // ManifestPush push image to registry @@ -353,7 +353,7 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) { utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "error pushing image %q", destination)) return } - utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: digest}) + utils.WriteResponse(w, http.StatusOK, entities.IDResponse{ID: digest}) } // ManifestModify efficiently updates the named manifest list diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go index d522631b7..5b92358fa 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -81,7 +81,7 @@ func PodCreate(w http.ResponseWriter, r *http.Request) { utils.Error(w, httpCode, errors.Wrap(err, "failed to make pod")) return } - utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: pod.ID()}) + utils.WriteResponse(w, http.StatusCreated, entities.IDResponse{ID: pod.ID()}) } func Pods(w http.ResponseWriter, r *http.Request) { @@ -290,9 +290,7 @@ func PodPrune(w http.ResponseWriter, r *http.Request) { } func PodPruneHelper(r *http.Request) ([]*entities.PodPruneReport, error) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) responses, err := runtime.PrunePods(r.Context()) if err != nil { return nil, err @@ -414,7 +412,7 @@ loop: // break out of for/select infinite` loop } if len(output) > 0 { - var body = handlers.PodTopOKBody{} + body := handlers.PodTopOKBody{} body.Titles = strings.Split(output[0], "\t") for i := range body.Titles { body.Titles[i] = strings.TrimSpace(body.Titles[i]) diff --git a/pkg/api/handlers/libpod/swagger.go b/pkg/api/handlers/libpod/swagger.go deleted file mode 100644 index 5f33e6c01..000000000 --- a/pkg/api/handlers/libpod/swagger.go +++ /dev/null @@ -1,157 +0,0 @@ -package libpod - -import ( - "net/http" - "os" - - "github.com/containers/common/libnetwork/types" - "github.com/containers/image/v5/manifest" - "github.com/containers/podman/v4/libpod/define" - "github.com/containers/podman/v4/pkg/api/handlers/utils" - "github.com/containers/podman/v4/pkg/domain/entities" - "github.com/pkg/errors" -) - -// DefaultPodmanSwaggerSpec provides the default path to the podman swagger spec file -const DefaultPodmanSwaggerSpec = "/usr/share/containers/podman/swagger.yaml" - -// List Containers -// swagger:response ListContainers -type swagInspectPodResponse struct { - // in:body - Body []entities.ListContainer -} - -// Inspect Manifest -// swagger:response InspectManifest -type swagInspectManifestResponse struct { - // in:body - Body manifest.Schema2List -} - -// Kill Pod -// swagger:response PodKillReport -type swagKillPodResponse struct { - // in:body - Body entities.PodKillReport -} - -// Pause pod -// swagger:response PodPauseReport -type swagPausePodResponse struct { - // in:body - Body entities.PodPauseReport -} - -// Unpause pod -// swagger:response PodUnpauseReport -type swagUnpausePodResponse struct { - // in:body - Body entities.PodUnpauseReport -} - -// Stop pod -// swagger:response PodStopReport -type swagStopPodResponse struct { - // in:body - Body entities.PodStopReport -} - -// Restart pod -// swagger:response PodRestartReport -type swagRestartPodResponse struct { - // in:body - Body entities.PodRestartReport -} - -// Start pod -// swagger:response PodStartReport -type swagStartPodResponse struct { - // in:body - Body entities.PodStartReport -} - -// Prune pod -// swagger:response PodPruneReport -type swagPrunePodResponse struct { - // in:body - Body entities.PodPruneReport -} - -// Rm pod -// swagger:response PodRmReport -type swagRmPodResponse struct { - // in:body - Body entities.PodRmReport -} - -// Info -// swagger:response InfoResponse -type swagInfoResponse struct { - // in:body - Body define.Info -} - -// Network rm -// swagger:response NetworkRmReport -type swagNetworkRmReport struct { - // in:body - Body []entities.NetworkRmReport -} - -// Network inspect -// swagger:response NetworkInspectReport -type swagNetworkInspectReport struct { - // in:body - Body types.Network -} - -// Network list -// swagger:response NetworkListReport -type swagNetworkListReport struct { - // in:body - Body []types.Network -} - -// Network create -// swagger:model NetworkCreateLibpod -type swagNetworkCreateLibpod struct { - types.Network -} - -// Network create -// swagger:response NetworkCreateReport -type swagNetworkCreateReport struct { - // in:body - Body types.Network -} - -// Network prune -// swagger:response NetworkPruneResponse -type swagNetworkPruneResponse struct { - // in:body - Body []entities.NetworkPruneReport -} - -// Network connect -// swagger:model NetworkConnectRequest -type swagNetworkConnectRequest struct { - entities.NetworkConnectOptions -} - -func ServeSwagger(w http.ResponseWriter, r *http.Request) { - path := DefaultPodmanSwaggerSpec - if p, found := os.LookupEnv("PODMAN_SWAGGER_SPEC"); found { - path = p - } - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - utils.InternalServerError(w, errors.Errorf("file %q does not exist", path)) - return - } - utils.InternalServerError(w, err) - return - } - w.Header().Set("Content-Type", "text/yaml") - http.ServeFile(w, r, path) -} diff --git a/pkg/api/handlers/libpod/swagger_spec.go b/pkg/api/handlers/libpod/swagger_spec.go new file mode 100644 index 000000000..8eeb041d2 --- /dev/null +++ b/pkg/api/handlers/libpod/swagger_spec.go @@ -0,0 +1,29 @@ +package libpod + +import ( + "net/http" + "os" + + "github.com/containers/podman/v4/pkg/api/handlers/utils" + "github.com/pkg/errors" +) + +// DefaultPodmanSwaggerSpec provides the default path to the podman swagger spec file +const DefaultPodmanSwaggerSpec = "/usr/share/containers/podman/swagger.yaml" + +func ServeSwagger(w http.ResponseWriter, r *http.Request) { + path := DefaultPodmanSwaggerSpec + if p, found := os.LookupEnv("PODMAN_SWAGGER_SPEC"); found { + path = p + } + if _, err := os.Stat(path); err != nil { + if errors.Is(err, os.ErrNotExist) { + utils.InternalServerError(w, errors.Errorf("swagger spec %q does not exist", path)) + return + } + utils.InternalServerError(w, err) + return + } + w.Header().Set("Content-Type", "text/yaml") + http.ServeFile(w, r, path) +} diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go index e0ea16d82..e792dea35 100644 --- a/pkg/api/handlers/libpod/volumes.go +++ b/pkg/api/handlers/libpod/volumes.go @@ -25,8 +25,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder) ) - query := struct { - }{ + query := struct{}{ // override any golang type defaults } if err := decoder.Decode(&query, r.URL.Query()); err != nil { @@ -86,9 +85,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { } func InspectVolume(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) name := utils.GetName(r) vol, err := runtime.GetVolume(name) if err != nil { @@ -107,9 +104,7 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) { } func ListVolumes(w http.ResponseWriter, r *http.Request) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) filterMap, err := util.PrepareFilters(r) if err != nil { utils.Error(w, http.StatusInternalServerError, @@ -153,9 +148,7 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) { } func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) { - var ( - runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - ) + runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) filterMap, err := util.PrepareFilters(r) if err != nil { return nil, err diff --git a/pkg/api/handlers/swagger/doc.go b/pkg/api/handlers/swagger/doc.go new file mode 100644 index 000000000..67ede275a --- /dev/null +++ b/pkg/api/handlers/swagger/doc.go @@ -0,0 +1,17 @@ +// Package swagger defines the payloads used by the Podman API +// +// - errors.go: declares the errors used in the API. By embedding errors.ErrorModel, more meaningful +// comments can be provided for the developer documentation. +// - models.go: declares the models used in API requests. +// - responses.go: declares the responses used in the API responses. +// +// +// Notes: +// 1. As a developer of the Podman API, you are responsible for maintaining the associations between +// these models and responses, and the handler code. +// 2. There are a number of warnings produces when compiling the swagger yaml file. This is expected. +// Most are because embedded structs have been discovered but not used in the API declarations. +// 3. Response and model references that are exported (start with upper-case letter) imply that they +// exist outside this package and should be found in the entities package. +// +package swagger diff --git a/pkg/api/handlers/swagger/errors.go b/pkg/api/handlers/swagger/errors.go new file mode 100644 index 000000000..28e11c9fb --- /dev/null +++ b/pkg/api/handlers/swagger/errors.go @@ -0,0 +1,116 @@ +//nolint:deadcode,unused // these types are used to wire generated swagger to API code +package swagger + +import ( + "github.com/containers/podman/v4/pkg/errorhandling" +) + +// Error model embedded in swagger:response to aid in documentation generation + +// No such image +// swagger:response +type imageNotFound struct { + // in:body + Body errorhandling.ErrorModel +} + +// No such container +// swagger:response +type containerNotFound struct { + // in:body + Body errorhandling.ErrorModel +} + +// No such network +// swagger:response +type networkNotFound struct { + // in:body + Body errorhandling.ErrorModel +} + +// No such exec instance +// swagger:response +type execSessionNotFound struct { + // in:body + Body errorhandling.ErrorModel +} + +// No such volume +// swagger:response +type volumeNotFound struct { + // in:body + Body errorhandling.ErrorModel +} + +// No such pod +// swagger:response +type podNotFound struct { + // in:body + Body errorhandling.ErrorModel +} + +// No such manifest +// swagger:response +type manifestNotFound struct { + // in:body + Body errorhandling.ErrorModel +} + +// Internal server error +// swagger:response +type internalError struct { + // in:body + Body errorhandling.ErrorModel +} + +// Conflict error in operation +// swagger:response +type conflictError struct { + // in:body + Body errorhandling.ErrorModel +} + +// Bad parameter in request +// swagger:response +type badParamError struct { + // in:body + Body errorhandling.ErrorModel +} + +// Container already started +// swagger:response +type containerAlreadyStartedError struct { + // in:body + Body errorhandling.ErrorModel +} + +// Container already stopped +// swagger:response +type containerAlreadyStoppedError struct { + // in:body + Body errorhandling.ErrorModel +} + +// Pod already started +// swagger:response +type podAlreadyStartedError struct { + // in:body + Body errorhandling.ErrorModel +} + +// Pod already stopped +// swagger:response +type podAlreadyStoppedError struct { + // in:body + Body errorhandling.ErrorModel +} + +// Success +// swagger:response +type ok struct { + // in:body + Body struct { + // example: OK + ok string + } +} diff --git a/pkg/api/handlers/swagger/models.go b/pkg/api/handlers/swagger/models.go new file mode 100644 index 000000000..a05e57dff --- /dev/null +++ b/pkg/api/handlers/swagger/models.go @@ -0,0 +1,46 @@ +//nolint:deadcode,unused // these types are used to wire generated swagger to API code +package swagger + +import ( + "github.com/containers/podman/v4/pkg/domain/entities" + "github.com/docker/docker/api/types" +) + +// Details for creating a volume +// swagger:model +type volumeCreate struct { + // Name of the volume driver to use. + // Required: true + Driver string `json:"Driver"` + + // A mapping of driver options and values. These options are + // passed directly to the driver and are driver specific. + // + // Required: true + DriverOpts map[string]string `json:"DriverOpts"` + + // User-defined key/value metadata. + // Required: true + Labels map[string]string `json:"Labels"` + + // The new volume's name. If not specified, Docker generates a name. + // + // Required: true + Name string `json:"Name"` +} + +// Network create +// swagger:model +type networkCreate types.NetworkCreateRequest + +// Network connect +// swagger:model +type networkConnectRequest types.NetworkConnect + +// Network disconnect +// swagger:model +type networkDisconnectRequest types.NetworkDisconnect + +// Network connect +// swagger:model +type networkConnectRequestLibpod entities.NetworkConnectOptions diff --git a/pkg/api/handlers/swagger/responses.go b/pkg/api/handlers/swagger/responses.go new file mode 100644 index 000000000..55fc1a77f --- /dev/null +++ b/pkg/api/handlers/swagger/responses.go @@ -0,0 +1,453 @@ +//nolint:deadcode,unused // these types are used to wire generated swagger to API code +package swagger + +import ( + "github.com/containers/common/libnetwork/types" + "github.com/containers/image/v5/manifest" + "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/pkg/api/handlers" + "github.com/containers/podman/v4/pkg/domain/entities" + "github.com/containers/podman/v4/pkg/domain/entities/reports" + "github.com/containers/podman/v4/pkg/inspect" + dockerAPI "github.com/docker/docker/api/types" + dockerVolume "github.com/docker/docker/api/types/volume" +) + +// Image Tree +// swagger:response +type treeResponse struct { + // in:body + Body entities.ImageTreeReport +} + +// Image History +// swagger:response +type history struct { + // in:body + Body handlers.HistoryResponse +} + +// Image Inspect +// swagger:response +type imageInspect struct { + // in:body + Body handlers.ImageInspect +} + +// Image Load +// swagger:response +type imagesLoadResponseLibpod struct { + // in:body + Body entities.ImageLoadReport +} + +// Image Import +// swagger:response +type imagesImportResponseLibpod struct { + // in:body + Body entities.ImageImportReport +} + +// Image Pull +// swagger:response +type imagesPullResponseLibpod struct { + // in:body + Body handlers.LibpodImagesPullReport +} + +// Image Remove +// swagger:response +type imagesRemoveResponseLibpod struct { + // in:body + Body handlers.LibpodImagesRemoveReport +} + +// PlayKube response +// swagger:response +type playKubeResponseLibpod struct { + // in:body + Body entities.PlayKubeReport +} + +// Image Delete +// swagger:response +type imageDeleteResponse struct { + // in:body + Body []struct { + Untagged []string `json:"untagged"` + Deleted string `json:"deleted"` + } +} + +// Registry Search +// swagger:response +type registrySearchResponse struct { + // in:body + Body struct { + // Index is the image index + // example: quay.io + Index string + // Name is the canonical name of the image + // example: docker.io/library/alpine" + Name string + // Description of the image. + Description string + // Stars is the number of stars of the image. + Stars int + // Official indicates if it's an official image. + Official string + // Automated indicates if the image was created by an automated build. + Automated string + // Tag is the image tag + Tag string + } +} + +// Inspect Image +// swagger:response +type inspectImageResponseLibpod struct { + // in:body + Body inspect.ImageData +} + +// Inspect container +// swagger:response +type containerInspectResponse struct { + // in:body + Body dockerAPI.ContainerJSON +} + +// List processes in container +// swagger:response +type containerTopResponse struct { + // in:body + Body handlers.ContainerTopOKBody +} + +// List processes in pod +// swagger:response +type podTopResponse struct { + // in:body + Body handlers.PodTopOKBody +} + +// Pod Statistics +// swagger:response +type podStatsResponse struct { + // in:body + Body []entities.PodStatsReport +} + +// Inspect container +// swagger:response +type containerInspectResponseLibpod struct { + // in:body + Body define.InspectContainerData +} + +// List pods +// swagger:response +type podsListResponse struct { + // in:body + Body []entities.ListPodsReport +} + +// Inspect pod +// swagger:response +type podInspectResponse struct { + // in:body + Body define.InspectPodData +} + +// Volume details +// swagger:response +type volumeCreateResponse struct { + // in:body + Body entities.VolumeConfigResponse +} + +// Healthcheck Results +// swagger:response +type healthCheck struct { + // in:body + Body define.HealthCheckResults +} + +// Version +// swagger:response +type versionResponse struct { + // in:body + Body entities.ComponentVersion +} + +// Disk usage +// swagger:response +type systemDiskUsage struct { + // in:body + Body entities.SystemDfReport +} + +// System Prune results +// swagger:response +type systemPruneResponse struct { + // in:body + Body entities.SystemPruneReport +} + +// Auth response +// swagger:response +type systemAuthResponse struct { + // in:body + Body entities.AuthReport +} + +// Exec Session Inspect +// swagger:response +type execSessionInspect struct { + // in:body + Body define.InspectExecSession +} + +// Image summary for compat API +// swagger:response +type imageList struct { + // in:body + Body []dockerAPI.ImageSummary +} + +// Image summary for libpod API +// swagger:response +type imageListLibpod struct { + // in:body + Body []entities.ImageSummary +} + +// List Containers +// swagger:response +type containersList struct { + // in:body + Body []handlers.Container +} + +// This response definition is used for both the create and inspect endpoints +// swagger:response +type volumeInspect struct { + // in:body + Body dockerAPI.Volume +} + +// Volume prune +// swagger:response +type volumePruneResponse struct { + // in:body + Body dockerAPI.VolumesPruneReport +} + +// Volume List +// swagger:response +type volumeList struct { + // in:body + Body dockerVolume.VolumeListOKBody +} + +// Volume list +// swagger:response +type volumeListLibpod struct { + // in:body + Body []entities.VolumeConfigResponse +} + +// Image Prune +// swagger:response +type imagesPruneLibpod struct { + // in:body + Body []reports.PruneReport +} + +// Remove Containers +// swagger:response +type containerRemoveLibpod struct { + // in: body + Body []handlers.LibpodContainersRmReport +} + +// Prune Containers +// swagger:response +type containersPrune struct { + // in: body + Body []handlers.ContainersPruneReport +} + +// Prune Containers +// swagger:response +type containersPruneLibpod struct { + // in: body + Body []handlers.ContainersPruneReportLibpod +} + +// Get stats for one or more containers +// swagger:response +type containerStats struct { + // in:body + Body define.ContainerStats +} + +// Volume Prune +// swagger:response +type volumePruneLibpod struct { + // in:body + Body []reports.PruneReport +} + +// Create container +// swagger:response +type containerCreateResponse struct { + // in:body + Body entities.ContainerCreateResponse +} + +// Wait container +// swagger:response +type containerWaitResponse struct { + // in:body + Body struct { + // container exit code + StatusCode int + Error struct { + Message string + } + } +} + +// Network inspect +// swagger:response +type networkInspectCompat struct { + // in:body + Body dockerAPI.NetworkResource +} + +// Network list +// swagger:response +type networkListCompat struct { + // in:body + Body []dockerAPI.NetworkResource +} + +// List Containers +// swagger:response +type containersListLibpod struct { + // in:body + Body []entities.ListContainer +} + +// Inspect Manifest +// swagger:response +type manifestInspect struct { + // in:body + Body manifest.Schema2List +} + +// Kill Pod +// swagger:response +type podKillResponse struct { + // in:body + Body entities.PodKillReport +} + +// Pause pod +// swagger:response +type podPauseResponse struct { + // in:body + Body entities.PodPauseReport +} + +// Unpause pod +// swagger:response +type podUnpauseResponse struct { + // in:body + Body entities.PodUnpauseReport +} + +// Stop pod +// swagger:response +type podStopResponse struct { + // in:body + Body entities.PodStopReport +} + +// Restart pod +// swagger:response +type podRestartResponse struct { + // in:body + Body entities.PodRestartReport +} + +// Start pod +// swagger:response +type podStartResponse struct { + // in:body + Body entities.PodStartReport +} + +// Prune pod +// swagger:response +type podPruneResponse struct { + // in:body + Body entities.PodPruneReport +} + +// Rm pod +// swagger:response +type podRmResponse struct { + // in:body + Body entities.PodRmReport +} + +// Info +// swagger:response +type infoResponse struct { + // in:body + Body define.Info +} + +// Network Delete +// swagger:response +type networkRmResponse struct { + // in:body + Body []entities.NetworkRmReport +} + +// Network inspect +// swagger:response +type networkInspectResponse struct { + // in:body + Body types.Network +} + +// Network list +// swagger:response +type networkListLibpod struct { + // in:body + Body []types.Network +} + +// Network create +// swagger:model +type networkCreateLibpod struct { + // in:body + types.Network +} + +// Network create +// swagger:response +type networkCreateResponse struct { + // in:body + Body types.Network +} + +// Network prune +// swagger:response +type networkPruneResponse struct { + // in:body + Body []entities.NetworkPruneReport +} diff --git a/pkg/api/handlers/swagger/swagger.go b/pkg/api/handlers/swagger/swagger.go deleted file mode 100644 index 7446d901e..000000000 --- a/pkg/api/handlers/swagger/swagger.go +++ /dev/null @@ -1,194 +0,0 @@ -package swagger - -import ( - "github.com/containers/podman/v4/libpod/define" - "github.com/containers/podman/v4/pkg/api/handlers" - "github.com/containers/podman/v4/pkg/domain/entities" - "github.com/containers/podman/v4/pkg/inspect" - "github.com/docker/docker/api/types" -) - -// Tree response -// swagger:response TreeResponse -type swagTree struct { - // in:body - Body struct { - entities.ImageTreeReport - } -} - -// History response -// swagger:response DocsHistory -type swagHistory struct { - // in:body - Body struct { - handlers.HistoryResponse - } -} - -// Inspect response -// swagger:response DocsImageInspect -type swagImageInspect struct { - // in:body - Body struct { - handlers.ImageInspect - } -} - -// Load response -// swagger:response DocsLibpodImagesLoadResponse -type swagLibpodImagesLoadResponse struct { - // in:body - Body entities.ImageLoadReport -} - -// Import response -// swagger:response DocsLibpodImagesImportResponse -type swagLibpodImagesImportResponse struct { - // in:body - Body entities.ImageImportReport -} - -// Pull response -// swagger:response DocsLibpodImagesPullResponse -type swagLibpodImagesPullResponse struct { - // in:body - Body handlers.LibpodImagesPullReport -} - -// Remove response -// swagger:response DocsLibpodImagesRemoveResponse -type swagLibpodImagesRemoveResponse struct { - // in:body - Body handlers.LibpodImagesRemoveReport -} - -// PlayKube response -// swagger:response DocsLibpodPlayKubeResponse -type swagLibpodPlayKubeResponse struct { - // in:body - Body entities.PlayKubeReport -} - -// Delete response -// swagger:response DocsImageDeleteResponse -type swagImageDeleteResponse struct { - // in:body - Body []struct { - Untagged []string `json:"untagged"` - Deleted string `json:"deleted"` - } -} - -// Search results -// swagger:response DocsSearchResponse -type swagSearchResponse struct { - // in:body - Body struct { - // Index is the image index (e.g., "docker.io" or "quay.io") - Index string - // Name is the canonical name of the image (e.g., "docker.io/library/alpine"). - Name string - // Description of the image. - Description string - // Stars is the number of stars of the image. - Stars int - // Official indicates if it's an official image. - Official string - // Automated indicates if the image was created by an automated build. - Automated string - // Tag is the image tag - Tag string - } -} - -// Inspect image -// swagger:response DocsLibpodInspectImageResponse -type swagLibpodInspectImageResponse struct { - // in:body - Body struct { - inspect.ImageData - } -} - -// Rm containers -// swagger:response DocsLibpodContainerRmReport -type swagLibpodContainerRmReport struct { - // in: body - Body []handlers.LibpodContainersRmReport -} - -// Prune containers -// swagger:response DocsContainerPruneReport -type swagContainerPruneReport struct { - // in: body - Body []handlers.ContainersPruneReport -} - -// Prune containers -// swagger:response DocsLibpodPruneResponse -type swagLibpodContainerPruneReport struct { - // in: body - Body []handlers.LibpodContainersPruneReport -} - -// Inspect container -// swagger:response DocsContainerInspectResponse -type swagContainerInspectResponse struct { - // in:body - Body struct { - types.ContainerJSON - } -} - -// List processes in container -// swagger:response DocsContainerTopResponse -type swagContainerTopResponse struct { - // in:body - Body struct { - handlers.ContainerTopOKBody - } -} - -// List processes in pod -// swagger:response DocsPodTopResponse -type swagPodTopResponse struct { - // in:body - Body struct { - handlers.PodTopOKBody - } -} - -// Inspect container -// swagger:response LibpodInspectContainerResponse -type swagLibpodInspectContainerResponse struct { - // in:body - Body struct { - define.InspectContainerData - } -} - -// List pods -// swagger:response ListPodsResponse -type swagListPodsResponse struct { - // in:body - Body []entities.ListPodsReport -} - -// Inspect pod -// swagger:response InspectPodResponse -type swagInspectPodResponse struct { - // in:body - Body struct { - define.InspectPodData - } -} - -// Get stats for one or more containers -// swagger:response ContainerStats -type swagContainerStatsResponse struct { - // in:body - Body struct { - define.ContainerStats - } -} diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go index 07eebb4f4..9eb712c30 100644 --- a/pkg/api/handlers/types.go +++ b/pkg/api/handlers/types.go @@ -41,7 +41,7 @@ type ContainersPruneReport struct { docker.ContainersPruneReport } -type LibpodContainersPruneReport struct { +type ContainersPruneReportLibpod struct { ID string `json:"Id"` SpaceReclaimed int64 `json:"Size"` // Error which occurred during prune operation (if any). @@ -121,7 +121,7 @@ type ContainerWaitOKBody struct { } // CreateContainerConfig used when compatible endpoint creates a container -// swagger:model CreateContainerConfig +// swagger:model type CreateContainerConfig struct { Name string // container name dockerContainer.Config // desired container configuration @@ -131,12 +131,6 @@ type CreateContainerConfig struct { UnsetEnvAll bool // unset all default environment variables } -// swagger:model IDResponse -type IDResponse struct { - // ID - ID string `json:"Id"` -} - type ContainerTopOKBody struct { dockerContainer.ContainerTopOKBody } @@ -145,20 +139,6 @@ type PodTopOKBody struct { dockerContainer.ContainerTopOKBody } -// swagger:model PodCreateConfig -type PodCreateConfig struct { - Name string `json:"name"` - CgroupParent string `json:"cgroup-parent"` - Hostname string `json:"hostname"` - Infra bool `json:"infra"` - InfraCommand string `json:"infra-command"` - InfraImage string `json:"infra-image"` - InfraName string `json:"infra-name"` - Labels []string `json:"labels"` - Publish []string `json:"publish"` - Share string `json:"share"` -} - // HistoryResponse provides details on image layers type HistoryResponse struct { ID string `json:"Id"` @@ -173,10 +153,6 @@ type ExecCreateConfig struct { docker.ExecConfig } -type ExecCreateResponse struct { - docker.IDResponse -} - type ExecStartConfig struct { Detach bool `json:"Detach"` Tty bool `json:"Tty"` @@ -250,7 +226,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libimage.Image) (*ImageInsp return &ImageInspect{dockerImageInspect}, nil } -// portsToPortSet converts libpods exposed ports to dockers structs +// portsToPortSet converts libpod's exposed ports to docker's structs func portsToPortSet(input map[string]struct{}) (nat.PortSet, error) { ports := make(nat.PortSet) for k := range input { diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go index 3a5488a4a..8588b49ba 100644 --- a/pkg/api/handlers/utils/containers.go +++ b/pkg/api/handlers/utils/containers.go @@ -57,7 +57,6 @@ func WaitContainerDocker(w http.ResponseWriter, r *http.Request) { name := GetName(r) exists, err := containerExists(ctx, name) - if err != nil { InternalServerError(w, err) return diff --git a/pkg/api/server/docs.go b/pkg/api/server/doc.go index 2127e7d82..0bb10a19c 100644 --- a/pkg/api/server/docs.go +++ b/pkg/api/server/doc.go @@ -1,10 +1,7 @@ -// Package api Provides an API for the Libpod library +// Package server supports a RESTful API for the Libpod library // -// This documentation describes the Podman v2.0 RESTful API. -// It replaces the Podman v1.0 API and was initially delivered -// along with Podman v2.0. It consists of a Docker-compatible -// API and a Libpod API providing support for Podman’s unique -// features such as pods. +// This documentation describes the Podman v2.x+ RESTful API. It consists of a Docker-compatible +// API and a Libpod API providing support for Podman’s unique features such as pods. // // To start the service and keep it running for 5,000 seconds (-t 0 runs forever): // @@ -15,11 +12,11 @@ // NOTE: if you install the package podman-docker, it will create a symbolic // link for /run/docker.sock to /run/podman/podman.sock // -// NOTE: some fields in the API response JSON are set as omitempty, which means that -// if there is no value set for them, they will not show up in the API response. This +// NOTE: Some fields in the API response JSON are encoded as omitempty, which means that +// if said field has a zero value, they will not be encoded in the API response. This // is a feature to help reduce the size of the JSON responses returned via the API. // -// NOTE: due to the limitations of [go-swagger](https://github.com/go-swagger/go-swagger), +// NOTE: Due to the limitations of [go-swagger](https://github.com/go-swagger/go-swagger), // some field values that have a complex type show up as null in the docs as well as in the // API responses. This is because the zero value for the field type is null. The field // description in the docs will state what type the field is expected to be for such cases. @@ -30,18 +27,20 @@ // // 'podman info' // -// curl --unix-socket /run/podman/podman.sock http://d/v3.0.0/libpod/info +// curl --unix-socket /run/podman/podman.sock http://d/v4.0.0/libpod/info // // 'podman pull quay.io/containers/podman' // -// curl -XPOST --unix-socket /run/podman/podman.sock -v 'http://d/v3.0.0/images/create?fromImage=quay.io%2Fcontainers%2Fpodman' +// curl -XPOST --unix-socket /run/podman/podman.sock -v 'http://d/v4.0.0/images/create?fromImage=quay.io%2Fcontainers%2Fpodman' // // 'podman list images' // -// curl --unix-socket /run/podman/podman.sock -v 'http://d/v3.0.0/libpod/images/json' | jq +// curl --unix-socket /run/podman/podman.sock -v 'http://d/v4.0.0/libpod/images/json' | jq // // Terms Of Service: // +// https://github.com/containers/podman/blob/913caaa9b1de2b63692c9bae15120208194c9eb3/LICENSE +// // Schemes: http, https // Host: podman.io // BasePath: / @@ -62,5 +61,6 @@ // Consumes: // - application/json // - application/x-tar +// // swagger:meta package server diff --git a/pkg/api/server/register_archive.go b/pkg/api/server/register_archive.go index e51d12300..10131c7f2 100644 --- a/pkg/api/server/register_archive.go +++ b/pkg/api/server/register_archive.go @@ -44,13 +44,13 @@ func (s *APIServer) registerArchiveHandlers(r *mux.Router) error { // 200: // description: no error // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 403: // description: the container rootfs is read-only // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" // swagger:operation GET /containers/{name}/archive compat ContainerArchive // --- @@ -78,11 +78,11 @@ func (s *APIServer) registerArchiveHandlers(r *mux.Router) error { // type: string // format: binary // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/archive"), s.APIHandler(compat.Archive)).Methods(http.MethodGet, http.MethodPut, http.MethodHead) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/archive", s.APIHandler(compat.Archive)).Methods(http.MethodGet, http.MethodPut, http.MethodHead) @@ -124,13 +124,13 @@ func (s *APIServer) registerArchiveHandlers(r *mux.Router) error { // 200: // description: no error // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 403: // description: the container rootfs is read-only // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" // swagger:operation GET /libpod/containers/{name}/archive libpod ContainerArchiveLibpod // --- @@ -162,11 +162,11 @@ func (s *APIServer) registerArchiveHandlers(r *mux.Router) error { // type: string // format: binary // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/archive"), s.APIHandler(compat.Archive)).Methods(http.MethodGet, http.MethodPut, http.MethodHead) return nil diff --git a/pkg/api/server/register_auth.go b/pkg/api/server/register_auth.go index e66a211fd..beb37bf00 100644 --- a/pkg/api/server/register_auth.go +++ b/pkg/api/server/register_auth.go @@ -23,9 +23,9 @@ func (s *APIServer) registerAuthHandlers(r *mux.Router) error { // $ref: "#/definitions/AuthConfig" // responses: // 200: - // $ref: "#/responses/SystemAuthResponse" + // $ref: "#/responses/systemAuthResponse" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/auth"), s.APIHandler(compat.Auth)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/auth", s.APIHandler(compat.Auth)).Methods(http.MethodPost) diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index 89324794e..e2ecdb6af 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -29,15 +29,15 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // required: true // responses: // 201: - // $ref: "#/responses/ContainerCreateResponse" + // $ref: "#/responses/containerCreateResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/create"), s.APIHandler(compat.CreateContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/create", s.APIHandler(compat.CreateContainer)).Methods(http.MethodPost) @@ -90,11 +90,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsListContainer" + // $ref: "#/responses/containersList" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/json"), s.APIHandler(compat.ListContainers)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/json", s.APIHandler(compat.ListContainers)).Methods(http.MethodGet) @@ -116,9 +116,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsContainerPruneReport" + // $ref: "#/responses/containersPrune" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/prune"), s.APIHandler(compat.PruneContainers)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/prune", s.APIHandler(compat.PruneContainers)).Methods(http.MethodPost) @@ -153,13 +153,13 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}"), s.APIHandler(compat.RemoveContainer)).Methods(http.MethodDelete) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}", s.APIHandler(compat.RemoveContainer)).Methods(http.MethodDelete) @@ -184,11 +184,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsContainerInspectResponse" + // $ref: "#/responses/containerInspectResponse" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/json"), s.APIHandler(compat.GetContainer)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/json", s.APIHandler(compat.GetContainer)).Methods(http.MethodGet) @@ -221,11 +221,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/kill"), s.APIHandler(compat.KillContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/kill", s.APIHandler(compat.KillContainer)).Methods(http.MethodPost) @@ -277,9 +277,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 200: // description: logs returned as a stream in response body. // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/logs"), s.APIHandler(compat.LogsFromContainer)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/logs", s.APIHandler(compat.LogsFromContainer)).Methods(http.MethodGet) @@ -301,9 +301,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/pause"), s.APIHandler(compat.PauseContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/pause", s.APIHandler(compat.PauseContainer)).Methods(http.MethodPost) @@ -328,9 +328,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/restart"), s.APIHandler(compat.RestartContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/restart", s.APIHandler(compat.RestartContainer)).Methods(http.MethodPost) @@ -356,11 +356,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 304: - // $ref: "#/responses/ContainerAlreadyStartedError" + // $ref: "#/responses/containerAlreadyStartedError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/start"), s.APIHandler(compat.StartContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/start", s.APIHandler(compat.StartContainer)).Methods(http.MethodPost) @@ -390,11 +390,13 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // description: OK + // description: no error + // schema: + // type: object // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/stats"), s.APIHandler(compat.StatsContainer)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/stats", s.APIHandler(compat.StatsContainer)).Methods(http.MethodGet) @@ -420,11 +422,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 304: - // $ref: "#/responses/ContainerAlreadyStoppedError" + // $ref: "#/responses/containerAlreadyStoppedError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/stop"), s.APIHandler(compat.StopContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/stop", s.APIHandler(compat.StopContainer)).Methods(http.MethodPost) @@ -448,11 +450,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsContainerTopResponse" + // $ref: "#/responses/containerTopResponse" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/top"), s.APIHandler(compat.TopContainer)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/top", s.APIHandler(compat.TopContainer)).Methods(http.MethodGet) @@ -474,9 +476,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/unpause"), s.APIHandler(compat.UnpauseContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/unpause", s.APIHandler(compat.UnpauseContainer)).Methods(http.MethodPost) @@ -512,11 +514,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/ContainerWaitResponse" + // $ref: "#/responses/containerWaitResponse" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/wait"), s.APIHandler(compat.WaitContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/wait", s.APIHandler(compat.WaitContainer)).Methods(http.MethodPost) @@ -569,11 +571,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 101: // description: No error, connection has been hijacked for transporting streams. // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/attach"), s.APIHandler(compat.AttachContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/attach", s.APIHandler(compat.AttachContainer)).Methods(http.MethodPost) @@ -610,9 +612,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 200: // $ref: "#/responses/ok" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/resize"), s.APIHandler(compat.ResizeTTY)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.HandleFunc("/containers/{name}/resize", s.APIHandler(compat.ResizeTTY)).Methods(http.MethodPost) @@ -634,9 +636,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 200: // description: tarball is returned in body // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/export"), s.APIHandler(compat.ExportContainer)).Methods(http.MethodGet) r.HandleFunc("/containers/{name}/export", s.APIHandler(compat.ExportContainer)).Methods(http.MethodGet) // swagger:operation POST /containers/{name}/rename compat ContainerRename @@ -662,11 +664,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/rename"), s.APIHandler(compat.RenameContainer)).Methods(http.MethodPost) r.HandleFunc("/containers/{name}/rename", s.APIHandler(compat.RenameContainer)).Methods(http.MethodPost) @@ -689,15 +691,15 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // $ref: "#/definitions/SpecGenerator" // responses: // 201: - // $ref: "#/responses/ContainerCreateResponse" + // $ref: "#/responses/containerCreateResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/create"), s.APIHandler(libpod.CreateContainer)).Methods(http.MethodPost) // swagger:operation GET /libpod/containers/json libpod ContainerListLibpod // --- @@ -758,11 +760,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/ListContainers" + // $ref: "#/responses/containersListLibpod" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/json"), s.APIHandler(libpod.ListContainers)).Methods(http.MethodGet) // swagger:operation POST /libpod/containers/prune libpod ContainerPruneLibpod // --- @@ -782,9 +784,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodPruneResponse" + // $ref: "#/responses/containersPruneLibpod" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/prune"), s.APIHandler(compat.PruneContainers)).Methods(http.MethodPost) // swagger:operation GET /libpod/containers/showmounted libpod ContainerShowMountedLibpod // --- @@ -802,7 +804,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // additionalProperties: // type: string // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/showmounted"), s.APIHandler(libpod.ShowMountedContainers)).Methods(http.MethodGet) // swagger:operation DELETE /libpod/containers/{name} libpod ContainerDeleteLibpod // --- @@ -841,17 +843,17 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodContainerRmReport" + // $ref: "#/responses/containerRemoveLibpod" // 204: // description: no error // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}"), s.APIHandler(compat.RemoveContainer)).Methods(http.MethodDelete) // swagger:operation GET /libpod/containers/{name}/json libpod ContainerInspectLibpod // --- @@ -873,11 +875,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/LibpodInspectContainerResponse" + // $ref: "#/responses/containerInspectResponseLibpod" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/json"), s.APIHandler(libpod.GetContainer)).Methods(http.MethodGet) // swagger:operation POST /libpod/containers/{name}/kill libpod ContainerKillLibpod // --- @@ -902,11 +904,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/kill"), s.APIHandler(compat.KillContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/mount libpod ContainerMountLibpod // --- @@ -930,9 +932,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // type: string // example: /var/lib/containers/storage/overlay/f3f693bd88872a1e3193f4ebb925f4c282e8e73aadb8ab3e7492754dda3a02a4/merged // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/mount"), s.APIHandler(libpod.MountContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/unmount libpod ContainerUnmountLibpod // --- @@ -952,9 +954,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: ok // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/unmount"), s.APIHandler(libpod.UnmountContainer)).Methods(http.MethodPost) // swagger:operation GET /libpod/containers/{name}/logs libpod ContainerLogsLibpod // --- @@ -1004,9 +1006,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 200: // description: logs returned as a stream in response body. // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/logs"), s.APIHandler(compat.LogsFromContainer)).Methods(http.MethodGet) // swagger:operation POST /libpod/containers/{name}/pause libpod ContainerPauseLibpod // --- @@ -1026,9 +1028,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // "$ref": "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // "$ref": "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/pause"), s.APIHandler(compat.PauseContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/restart libpod ContainerRestartLibpod // --- @@ -1052,9 +1054,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/restart"), s.APIHandler(compat.RestartContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/start libpod ContainerStartLibpod // --- @@ -1078,11 +1080,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 304: - // $ref: "#/responses/ContainerAlreadyStartedError" + // $ref: "#/responses/containerAlreadyStartedError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/start"), s.APIHandler(compat.StartContainer)).Methods(http.MethodPost) // swagger:operation GET /libpod/containers/{name}/stats libpod ContainerStatsLibpod // --- @@ -1107,11 +1109,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 200: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/stats"), s.APIHandler(compat.StatsContainer)).Methods(http.MethodGet) // swagger:operation GET /libpod/containers/stats libpod ContainersStatsAllLibpod // --- @@ -1140,11 +1142,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/ContainerStats" + // $ref: "#/responses/containerStats" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/stats"), s.APIHandler(libpod.StatsContainer)).Methods(http.MethodGet) // swagger:operation GET /libpod/containers/{name}/top libpod ContainerTopLibpod @@ -1179,11 +1181,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsContainerTopResponse" + // $ref: "#/responses/containerTopResponse" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/top"), s.APIHandler(compat.TopContainer)).Methods(http.MethodGet) // swagger:operation POST /libpod/containers/{name}/unpause libpod ContainerUnpauseLibpod // --- @@ -1202,16 +1204,16 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/unpause"), s.APIHandler(compat.UnpauseContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/wait libpod ContainerWaitLibpod // --- // tags: // - containers // summary: Wait on a container - // description: Wait on a container to met a given condition + // description: Wait on a container to meet a given condition // parameters: // - in: path // name: name @@ -1250,9 +1252,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // examples: // text/plain: 137 // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/wait"), s.APIHandler(libpod.WaitContainer)).Methods(http.MethodPost) // swagger:operation GET /libpod/containers/{name}/exists libpod ContainerExistsLibpod // --- @@ -1272,9 +1274,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: container exists // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/exists"), s.APIHandler(libpod.ContainerExists)).Methods(http.MethodGet) // swagger:operation POST /libpod/containers/{name}/stop libpod ContainerStopLibpod // --- @@ -1308,11 +1310,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 304: - // $ref: "#/responses/ContainerAlreadyStoppedError" + // $ref: "#/responses/containerAlreadyStoppedError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/stop"), s.APIHandler(compat.StopContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/attach libpod ContainerAttachLibpod // --- @@ -1363,11 +1365,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 101: // description: No error, connection has been hijacked for transporting streams. // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/attach"), s.APIHandler(compat.AttachContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/resize libpod ContainerResizeLibpod // --- @@ -1397,11 +1399,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 200: // $ref: "#/responses/ok" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/resize"), s.APIHandler(compat.ResizeTTY)).Methods(http.MethodPost) // swagger:operation GET /libpod/containers/{name}/export libpod ContainerExportLibpod // --- @@ -1421,9 +1423,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 200: // description: tarball is returned in body // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/export"), s.APIHandler(compat.ExportContainer)).Methods(http.MethodGet) // swagger:operation POST /libpod/containers/{name}/checkpoint libpod ContainerCheckpointLibpod // --- @@ -1466,9 +1468,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 200: // description: tarball is returned in body if exported // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/checkpoint"), s.APIHandler(libpod.Checkpoint)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/restore libpod ContainerRestoreLibpod // --- @@ -1524,9 +1526,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 200: // description: tarball is returned in body if exported // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/restore"), s.APIHandler(libpod.Restore)).Methods(http.MethodPost) // swagger:operation GET /containers/{name}/changes compat ContainerChanges // swagger:operation GET /libpod/containers/{name}/changes libpod ContainerChangesLibpod @@ -1564,9 +1566,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // schema: // $ref: "#/responses/Changes" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/containers/{name}/changes"), s.APIHandler(compat.Changes)).Methods(http.MethodGet) r.HandleFunc("/containers/{name}/changes", s.APIHandler(compat.Changes)).Methods(http.MethodGet) r.HandleFunc(VersionedPath("/libpod/containers/{name}/changes"), s.APIHandler(compat.Changes)).Methods(http.MethodGet) @@ -1590,9 +1592,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 304: // description: container already initialized // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/init"), s.APIHandler(libpod.InitContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/rename libpod ContainerRenameLibpod // --- @@ -1617,11 +1619,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/rename"), s.APIHandler(compat.RenameContainer)).Methods(http.MethodPost) return nil } diff --git a/pkg/api/server/register_events.go b/pkg/api/server/register_events.go index 10a7b76fc..76f9ec619 100644 --- a/pkg/api/server/register_events.go +++ b/pkg/api/server/register_events.go @@ -33,7 +33,7 @@ func (s *APIServer) registerEventsHandlers(r *mux.Router) error { // 200: // description: returns a string of json data describing an event // 500: - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/events"), s.APIHandler(compat.GetEvents)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/events", s.APIHandler(compat.GetEvents)).Methods(http.MethodGet) @@ -67,7 +67,7 @@ func (s *APIServer) registerEventsHandlers(r *mux.Router) error { // 200: // description: returns a string of json data describing an event // 500: - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/libpod/events"), s.APIHandler(compat.GetEvents)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_exec.go b/pkg/api/server/register_exec.go index 90136463d..cf1fb8c16 100644 --- a/pkg/api/server/register_exec.go +++ b/pkg/api/server/register_exec.go @@ -69,11 +69,11 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 201: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: // description: container is paused // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/containers/{name}/exec"), s.APIHandler(compat.ExecCreateHandler)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/containers/{name}/exec", s.APIHandler(compat.ExecCreateHandler)).Methods(http.MethodPost) @@ -107,11 +107,11 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 200: // description: no error // 404: - // $ref: "#/responses/NoSuchExecInstance" + // $ref: "#/responses/execSessionNotFound" // 409: // description: container is not running // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/exec/{id}/start"), s.APIHandler(compat.ExecStartHandler)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/exec/{id}/start", s.APIHandler(compat.ExecStartHandler)).Methods(http.MethodPost) @@ -147,9 +147,9 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 201: // description: no error // 404: - // $ref: "#/responses/NoSuchExecInstance" + // $ref: "#/responses/execSessionNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/exec/{id}/resize"), s.APIHandler(compat.ResizeTTY)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/exec/{id}/resize", s.APIHandler(compat.ResizeTTY)).Methods(http.MethodPost) @@ -169,11 +169,11 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/InspectExecSession" + // $ref: "#/responses/execSessionInspect" // 404: - // $ref: "#/responses/NoSuchExecInstance" + // $ref: "#/responses/execSessionNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/exec/{id}/json"), s.APIHandler(compat.ExecInspectHandler)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/exec/{id}/json", s.APIHandler(compat.ExecInspectHandler)).Methods(http.MethodGet) @@ -243,11 +243,11 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 201: // description: no error // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: // description: container is paused // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/containers/{name}/exec"), s.APIHandler(compat.ExecCreateHandler)).Methods(http.MethodPost) // swagger:operation POST /libpod/exec/{id}/start libpod ExecStartLibpod // --- @@ -285,11 +285,11 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 200: // description: no error // 404: - // $ref: "#/responses/NoSuchExecInstance" + // $ref: "#/responses/execSessionNotFound" // 409: // description: container is not running. // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/exec/{id}/start"), s.APIHandler(compat.ExecStartHandler)).Methods(http.MethodPost) // swagger:operation POST /libpod/exec/{id}/resize libpod ExecResizeLibpod // --- @@ -318,9 +318,9 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 201: // description: no error // 404: - // $ref: "#/responses/NoSuchExecInstance" + // $ref: "#/responses/execSessionNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/exec/{id}/resize"), s.APIHandler(compat.ResizeTTY)).Methods(http.MethodPost) // swagger:operation GET /libpod/exec/{id}/json libpod ExecInspectLibpod // --- @@ -340,9 +340,9 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 200: // description: no error // 404: - // $ref: "#/responses/NoSuchExecInstance" + // $ref: "#/responses/execSessionNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/exec/{id}/json"), s.APIHandler(compat.ExecInspectHandler)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_generate.go b/pkg/api/server/register_generate.go index 6b7f0cfe7..82fbe3d09 100644 --- a/pkg/api/server/register_generate.go +++ b/pkg/api/server/register_generate.go @@ -103,7 +103,7 @@ func (s *APIServer) registerGenerateHandlers(r *mux.Router) error { // additionalProperties: // type: string // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/generate/{name:.*}/systemd"), s.APIHandler(libpod.GenerateSystemd)).Methods(http.MethodGet) // swagger:operation GET /libpod/generate/kube libpod GenerateKubeLibpod @@ -127,15 +127,16 @@ func (s *APIServer) registerGenerateHandlers(r *mux.Router) error { // default: false // description: Generate YAML for a Kubernetes service object. // produces: + // - text/vnd.yaml // - application/json // responses: // 200: - // description: no error + // description: Kubernetes YAML file describing pod // schema: // type: string // format: binary // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/generate/kube"), s.APIHandler(libpod.GenerateKube)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_healthcheck.go b/pkg/api/server/register_healthcheck.go index 014e82fe4..4e2d4059a 100644 --- a/pkg/api/server/register_healthcheck.go +++ b/pkg/api/server/register_healthcheck.go @@ -24,13 +24,13 @@ func (s *APIServer) registerHealthCheckHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/HealthcheckRun" + // $ref: "#/responses/healthCheck" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 409: // description: container has no healthcheck or is not running // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/containers/{name:.*}/healthcheck"), s.APIHandler(libpod.RunHealthCheck)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 89f808e7d..1617a5dd7 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -66,9 +66,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // type: "string" // format: "binary" // 404: - // $ref: "#/responses/NoSuchImage" + // $ref: "#/responses/imageNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/images/create"), s.APIHandler(compat.CreateImageFromImage)).Methods(http.MethodPost).Queries("fromImage", "{fromImage}") // Added non version path to URI to support docker non versioned paths r.Handle("/images/create", s.APIHandler(compat.CreateImageFromImage)).Methods(http.MethodPost).Queries("fromImage", "{fromImage}") @@ -106,9 +106,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DockerImageSummaryResponse" + // $ref: "#/responses/imageList" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/images/json"), s.APIHandler(compat.GetImages)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/images/json", s.APIHandler(compat.GetImages)).Methods(http.MethodGet) @@ -134,7 +134,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 200: // description: no error // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/images/load"), s.APIHandler(compat.LoadImages)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/images/load", s.APIHandler(compat.LoadImages)).Methods(http.MethodPost) @@ -159,9 +159,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsImageDeleteResponse" + // $ref: "#/responses/imageDeleteResponse" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/images/prune"), s.APIHandler(compat.PruneImages)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/images/prune", s.APIHandler(compat.PruneImages)).Methods(http.MethodPost) @@ -202,11 +202,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsSearchResponse" + // $ref: "#/responses/registrySearchResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/images/search"), s.APIHandler(compat.SearchImages)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/images/search", s.APIHandler(compat.SearchImages)).Methods(http.MethodGet) @@ -234,13 +234,13 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsImageDeleteResponse" + // $ref: "#/responses/imageDeleteResponse" // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 409: - // $ref: '#/responses/ConflictError' + // $ref: '#/responses/conflictError' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/images/{name:.*}"), s.APIHandler(compat.RemoveImage)).Methods(http.MethodDelete) // Added non version path to URI to support docker non versioned paths r.Handle("/images/{name:.*}", s.APIHandler(compat.RemoveImage)).Methods(http.MethodDelete) @@ -285,9 +285,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // type: string // format: binary // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/images/{name:.*}/push"), s.APIHandler(compat.PushImage)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/images/{name:.*}/push", s.APIHandler(compat.PushImage)).Methods(http.MethodPost) @@ -312,7 +312,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // type: string // format: binary // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/images/{name:.*}/get"), s.APIHandler(compat.ExportImage)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/images/{name:.*}/get", s.APIHandler(compat.ExportImage)).Methods(http.MethodGet) @@ -337,7 +337,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // type: string // format: binary // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/images/get"), s.APIHandler(compat.ExportImages)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/images/get", s.APIHandler(compat.ExportImages)).Methods(http.MethodGet) @@ -357,11 +357,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsHistory" + // $ref: "#/responses/history" // 404: - // $ref: "#/responses/NoSuchImage" + // $ref: "#/responses/imageNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/images/{name:.*}/history"), s.APIHandler(compat.HistoryImage)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/images/{name:.*}/history", s.APIHandler(compat.HistoryImage)).Methods(http.MethodGet) @@ -381,11 +381,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsImageInspect" + // $ref: "#/responses/imageInspect" // 404: - // $ref: "#/responses/NoSuchImage" + // $ref: "#/responses/imageNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/images/{name:.*}/json"), s.APIHandler(compat.GetImage)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/images/{name:.*}/json", s.APIHandler(compat.GetImage)).Methods(http.MethodGet) @@ -415,13 +415,13 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 201: // description: no error // 400: - // $ref: '#/responses/BadParamError' + // $ref: '#/responses/badParamError' // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 409: - // $ref: '#/responses/ConflictError' + // $ref: '#/responses/conflictError' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/images/{name:.*}/tag"), s.APIHandler(compat.TagImage)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/images/{name:.*}/tag", s.APIHandler(compat.TagImage)).Methods(http.MethodPost) @@ -470,9 +470,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 201: // description: no error // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/commit"), s.APIHandler(compat.CommitContainer)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/commit", s.APIHandler(compat.CommitContainer)).Methods(http.MethodPost) @@ -699,9 +699,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // Successfully built 8ba084515c724cbf90d447a63600c0a6 // Successfully tagged your_image:latest // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/build"), s.APIHandler(compat.BuildImage)).Methods(http.MethodPost) // Added non version path to URI to support docker non versioned paths r.Handle("/build", s.APIHandler(compat.BuildImage)).Methods(http.MethodPost) @@ -743,9 +743,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // type: string // format: binary // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/{name:.*}/push"), s.APIHandler(libpod.PushImage)).Methods(http.MethodPost) // swagger:operation GET /libpod/images/{name}/exists libpod ImageExistsLibpod // --- @@ -765,9 +765,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 204: // description: image exists // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/{name:.*}/exists"), s.APIHandler(libpod.ImageExists)).Methods(http.MethodGet) // swagger:operation GET /libpod/images/{name}/tree libpod ImageTreeLibpod // --- @@ -789,11 +789,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/TreeResponse" + // $ref: "#/responses/treeResponse" // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/{name:.*}/tree"), s.APIHandler(libpod.ImageTree)).Methods(http.MethodGet) // swagger:operation GET /libpod/images/{name}/history libpod ImageHistoryLibpod // --- @@ -811,11 +811,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsHistory" + // $ref: "#/responses/history" // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/{name:.*}/history"), s.APIHandler(compat.HistoryImage)).Methods(http.MethodGet) // swagger:operation GET /libpod/images/json libpod ImageListLibpod // --- @@ -844,9 +844,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/LibpodImageSummaryResponse" + // $ref: "#/responses/imageListLibpod" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/json"), s.APIHandler(compat.GetImages)).Methods(http.MethodGet) // swagger:operation POST /libpod/images/load libpod ImageLoadLibpod // --- @@ -867,11 +867,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodImagesLoadResponse" + // $ref: "#/responses/imagesLoadResponseLibpod" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/load"), s.APIHandler(libpod.ImagesLoad)).Methods(http.MethodPost) // swagger:operation POST /libpod/images/import libpod ImageImportLibpod // --- @@ -916,11 +916,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/x-tar // responses: // 200: - // $ref: "#/responses/DocsLibpodImagesImportResponse" + // $ref: "#/responses/imagesImportResponseLibpod" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/import"), s.APIHandler(libpod.ImagesImport)).Methods(http.MethodPost) // swagger:operation DELETE /libpod/images/remove libpod ImageDeleteAllLibpod // --- @@ -952,11 +952,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodImagesRemoveResponse" + // $ref: "#/responses/imagesRemoveResponseLibpod" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/remove"), s.APIHandler(libpod.ImagesBatchRemove)).Methods(http.MethodDelete) // swagger:operation DELETE /libpod/images/{name} libpod ImageDeleteLibpod // --- @@ -978,15 +978,15 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodImagesRemoveResponse" + // $ref: "#/responses/imagesRemoveResponseLibpod" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 409: - // $ref: '#/responses/ConflictError' + // $ref: '#/responses/conflictError' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/{name:.*}"), s.APIHandler(libpod.ImagesRemove)).Methods(http.MethodDelete) // swagger:operation POST /libpod/images/pull libpod ImagePullLibpod // --- @@ -1041,11 +1041,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodImagesPullResponse" + // $ref: "#/responses/imagesPullResponseLibpod" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/pull"), s.APIHandler(libpod.ImagesPull)).Methods(http.MethodPost) // swagger:operation POST /libpod/images/prune libpod ImagePruneLibpod // --- @@ -1080,9 +1080,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodPruneResponse" + // $ref: "#/responses/imagesPruneLibpod" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/prune"), s.APIHandler(libpod.PruneImages)).Methods(http.MethodPost) // swagger:operation GET /libpod/images/search libpod ImageSearchLibpod // --- @@ -1122,9 +1122,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsSearchResponse" + // $ref: "#/responses/registrySearchResponse" // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/search"), s.APIHandler(compat.SearchImages)).Methods(http.MethodGet) // swagger:operation GET /libpod/images/{name}/get libpod ImageGetLibpod // --- @@ -1155,9 +1155,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // type: string // format: binary // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/{name:.*}/get"), s.APIHandler(libpod.ExportImage)).Methods(http.MethodGet) // swagger:operation GET /libpod/images/export libpod ImageExportLibpod // --- @@ -1193,9 +1193,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // type: string // format: binary // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/export"), s.APIHandler(libpod.ExportImages)).Methods(http.MethodGet) // swagger:operation GET /libpod/images/{name}/json libpod ImageInspectLibpod // --- @@ -1213,11 +1213,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodInspectImageResponse" + // $ref: "#/responses/inspectImageResponseLibpod" // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/{name:.*}/json"), s.APIHandler(libpod.GetImage)).Methods(http.MethodGet) // swagger:operation POST /libpod/images/{name}/tag libpod ImageTagLibpod // --- @@ -1245,13 +1245,13 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 201: // description: no error // 400: - // $ref: '#/responses/BadParamError' + // $ref: '#/responses/badParamError' // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 409: - // $ref: '#/responses/ConflictError' + // $ref: '#/responses/conflictError' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/{name:.*}/tag"), s.APIHandler(compat.TagImage)).Methods(http.MethodPost) // swagger:operation POST /libpod/commit libpod ImageCommitLibpod // --- @@ -1301,9 +1301,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 201: // description: no error // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/commit"), s.APIHandler(libpod.CommitContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/images/{name}/untag libpod ImageUntagLibpod // --- @@ -1331,13 +1331,13 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 201: // description: no error // 400: - // $ref: '#/responses/BadParamError' + // $ref: '#/responses/badParamError' // 404: - // $ref: '#/responses/NoSuchImage' + // $ref: '#/responses/imageNotFound' // 409: - // $ref: '#/responses/ConflictError' + // $ref: '#/responses/conflictError' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/images/{name:.*}/untag"), s.APIHandler(libpod.UntagImage)).Methods(http.MethodPost) // swagger:operation GET /libpod/images/{name}/changes libpod ImageChangesLibpod @@ -1374,9 +1374,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // schema: // $ref: "#/responses/Changes" // 404: - // $ref: "#/responses/NoSuchContainer" + // $ref: "#/responses/containerNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/images/{name}/changes"), s.APIHandler(compat.Changes)).Methods(http.MethodGet) // swagger:operation POST /libpod/build libpod ImageBuildLibpod @@ -1611,9 +1611,9 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // example: | // (build details...) // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/build"), s.APIHandler(compat.BuildImage)).Methods(http.MethodPost) return nil } diff --git a/pkg/api/server/register_info.go b/pkg/api/server/register_info.go index ccb145366..116d847cc 100644 --- a/pkg/api/server/register_info.go +++ b/pkg/api/server/register_info.go @@ -21,7 +21,7 @@ func (s *APIServer) registerInfoHandlers(r *mux.Router) error { // 200: // description: to be determined // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/info"), s.APIHandler(compat.GetInfo)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/info", s.APIHandler(compat.GetInfo)).Methods(http.MethodGet) @@ -35,9 +35,9 @@ func (s *APIServer) registerInfoHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/InfoResponse" + // $ref: "#/responses/infoResponse" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/info"), s.APIHandler(libpod.GetInfo)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_manifest.go b/pkg/api/server/register_manifest.go index 3e3a516f4..4fadb92fd 100644 --- a/pkg/api/server/register_manifest.go +++ b/pkg/api/server/register_manifest.go @@ -39,11 +39,11 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // schema: // $ref: "#/definitions/IDResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchManifest" + // $ref: "#/responses/manifestNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" v3.Handle("/{name}/push", s.APIHandler(libpod.ManifestPushV3)).Methods(http.MethodPost) // swagger:operation POST /libpod/manifests/{name}/registry/{destination} manifests ManifestPushLibpod // --- @@ -80,11 +80,11 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // schema: // $ref: "#/definitions/IDResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchManifest" + // $ref: "#/responses/manifestNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" v4.Handle("/{name:.*}/registry/{destination:.*}", s.APIHandler(libpod.ManifestPush)).Methods(http.MethodPost) // swagger:operation POST /libpod/manifests manifests ManifestCreateLibpod // --- @@ -123,11 +123,11 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // schema: // $ref: "#/definitions/IDResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchImage" + // $ref: "#/responses/imageNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" v3.Handle("/create", s.APIHandler(libpod.ManifestCreate)).Methods(http.MethodPost) v4.Handle("/{name:.*}", s.APIHandler(libpod.ManifestCreate)).Methods(http.MethodPost) // swagger:operation GET /libpod/manifests/{name}/exists manifests ManifestExistsLibpod @@ -149,9 +149,9 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // 204: // description: manifest list exists // 404: - // $ref: '#/responses/NoSuchManifest' + // $ref: '#/responses/manifestNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' v3.Handle("/{name:.*}/exists", s.APIHandler(libpod.ManifestExists)).Methods(http.MethodGet) v4.Handle("/{name:.*}/exists", s.APIHandler(libpod.ManifestExists)).Methods(http.MethodGet) // swagger:operation GET /libpod/manifests/{name}/json manifests ManifestInspectLibpod @@ -168,11 +168,11 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // description: the name or ID of the manifest list // responses: // 200: - // $ref: "#/responses/InspectManifest" + // $ref: "#/responses/manifestInspect" // 404: - // $ref: "#/responses/NoSuchManifest" + // $ref: "#/responses/manifestNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" v3.Handle("/{name:.*}/json", s.APIHandler(libpod.ManifestInspect)).Methods(http.MethodGet) v4.Handle("/{name:.*}/json", s.APIHandler(libpod.ManifestInspect)).Methods(http.MethodGet) // swagger:operation PUT /libpod/manifests/{name} manifests ManifestModifyLibpod @@ -208,15 +208,15 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // schema: // $ref: "#/definitions/ManifestModifyReport" // 404: - // $ref: "#/responses/NoSuchManifest" + // $ref: "#/responses/manifestNotFound" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 409: // description: Operation had partial success, both Images and Errors may have members // schema: // $ref: "#/definitions/ManifestModifyReport" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" v4.Handle("/{name:.*}", s.APIHandler(libpod.ManifestModify)).Methods(http.MethodPut) // swagger:operation POST /libpod/manifests/{name}/add manifests ManifestAddLibpod // --- @@ -243,11 +243,11 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // schema: // $ref: "#/definitions/IDResponse" // 404: - // $ref: "#/responses/NoSuchManifest" + // $ref: "#/responses/manifestNotFound" // 409: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" v3.Handle("/{name:.*}/add", s.APIHandler(libpod.ManifestAddV3)).Methods(http.MethodPost) // swagger:operation DELETE /libpod/manifests/{name} manifests ManifestDeleteV3Libpod // --- @@ -273,11 +273,11 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // schema: // $ref: "#/definitions/IDResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchManifest" + // $ref: "#/responses/manifestNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" v3.Handle("/{name:.*}", s.APIHandler(libpod.ManifestRemoveDigestV3)).Methods(http.MethodDelete) // swagger:operation DELETE /libpod/manifests/{name} manifests ManifestDeleteLibpod // --- @@ -296,11 +296,11 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // description: The name or ID of the list to be deleted // responses: // 200: - // $ref: "#/responses/DocsLibpodImagesRemoveResponse" + // $ref: "#/responses/imagesRemoveResponseLibpod" // 404: - // $ref: "#/responses/NoSuchManifest" + // $ref: "#/responses/manifestNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" v4.Handle("/{name:.*}", s.APIHandler(libpod.ManifestDelete)).Methods(http.MethodDelete) return nil } diff --git a/pkg/api/server/register_networks.go b/pkg/api/server/register_networks.go index b900aa953..dcc656283 100644 --- a/pkg/api/server/register_networks.go +++ b/pkg/api/server/register_networks.go @@ -27,9 +27,9 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchNetwork" + // $ref: "#/responses/networkNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/networks/{name}"), s.APIHandler(compat.RemoveNetwork)).Methods(http.MethodDelete) r.HandleFunc("/networks/{name}", s.APIHandler(compat.RemoveNetwork)).Methods(http.MethodDelete) // swagger:operation GET /networks/{name} compat NetworkInspect @@ -58,11 +58,11 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/CompatNetworkInspect" + // $ref: "#/responses/networkInspectCompat" // 404: - // $ref: "#/responses/NoSuchNetwork" + // $ref: "#/responses/networkNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/networks/{name}"), s.APIHandler(compat.InspectNetwork)).Methods(http.MethodGet) r.HandleFunc("/networks/{name}", s.APIHandler(compat.InspectNetwork)).Methods(http.MethodGet) // swagger:operation GET /networks compat NetworkList @@ -85,9 +85,9 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/CompatNetworkList" + // $ref: "#/responses/networkListCompat" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/networks"), s.APIHandler(compat.ListNetworks)).Methods(http.MethodGet) r.HandleFunc("/networks", s.APIHandler(compat.ListNetworks)).Methods(http.MethodGet) // swagger:operation POST /networks/create compat NetworkCreate @@ -103,7 +103,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // name: create // description: attributes for creating a network // schema: - // $ref: "#/definitions/NetworkCreateRequest" + // $ref: "#/definitions/networkCreate" // responses: // 201: // description: network created @@ -115,9 +115,9 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // Warning: // type: string // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/networks/create"), s.APIHandler(compat.CreateNetwork)).Methods(http.MethodPost) r.HandleFunc("/networks/create", s.APIHandler(compat.CreateNetwork)).Methods(http.MethodPost) // swagger:operation POST /networks/{name}/connect compat NetworkConnect @@ -138,14 +138,14 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // name: create // description: attributes for connecting a container to a network // schema: - // $ref: "#/definitions/NetworkCompatConnectRequest" + // $ref: "#/definitions/networkConnectRequest" // responses: // 200: // description: OK // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/networks/{name}/connect"), s.APIHandler(compat.Connect)).Methods(http.MethodPost) r.HandleFunc("/networks/{name}/connect", s.APIHandler(compat.Connect)).Methods(http.MethodPost) // swagger:operation POST /networks/{name}/disconnect compat NetworkDisconnect @@ -166,14 +166,14 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // name: create // description: attributes for disconnecting a container from a network // schema: - // $ref: "#/definitions/NetworkCompatDisconnectRequest" + // $ref: "#/definitions/networkDisconnectRequest" // responses: // 200: // description: OK // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/networks/{name}/disconnect"), s.APIHandler(compat.Disconnect)).Methods(http.MethodPost) r.HandleFunc("/networks/{name}/disconnect", s.APIHandler(compat.Disconnect)).Methods(http.MethodPost) // swagger:operation POST /networks/prune compat NetworkPrune @@ -204,7 +204,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // items: // type: string // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/networks/prune"), s.APIHandler(compat.Prune)).Methods(http.MethodPost) r.HandleFunc("/networks/prune", s.APIHandler(compat.Prune)).Methods(http.MethodPost) @@ -228,11 +228,11 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/NetworkRmReport" + // $ref: "#/responses/networkRmResponse" // 404: - // $ref: "#/responses/NoSuchNetwork" + // $ref: "#/responses/networkNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/networks/{name}"), s.APIHandler(libpod.RemoveNetwork)).Methods(http.MethodDelete) // swagger:operation GET /libpod/networks/{name}/exists libpod NetworkExistsLibpod // --- @@ -252,9 +252,9 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // 204: // description: network exists // 404: - // $ref: '#/responses/NoSuchNetwork' + // $ref: '#/responses/networkNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/networks/{name}/exists"), s.APIHandler(libpod.ExistsNetwork)).Methods(http.MethodGet) // swagger:operation GET /libpod/networks/json libpod NetworkListLibpod // --- @@ -279,9 +279,9 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/NetworkListReport" + // $ref: "#/responses/networkListLibpod" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/networks/json"), s.APIHandler(libpod.ListNetworks)).Methods(http.MethodGet) // swagger:operation GET /libpod/networks/{name}/json libpod NetworkInspectLibpod // --- @@ -301,11 +301,11 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/NetworkInspectReport" + // $ref: "#/responses/networkInspectResponse" // 404: - // $ref: "#/responses/NoSuchNetwork" + // $ref: "#/responses/networkNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/networks/{name}/json"), s.APIHandler(libpod.InspectNetwork)).Methods(http.MethodGet) r.HandleFunc(VersionedPath("/libpod/networks/{name}"), s.APIHandler(libpod.InspectNetwork)).Methods(http.MethodGet) // swagger:operation POST /libpod/networks/create libpod NetworkCreateLibpod @@ -321,16 +321,16 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // name: create // description: attributes for creating a network // schema: - // $ref: "#/definitions/NetworkCreateLibpod" + // $ref: "#/definitions/networkCreateLibpod" // responses: // 200: - // $ref: "#/responses/NetworkCreateReport" + // $ref: "#/responses/networkCreateResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 409: - // $ref: "#/responses/ConflictError" + // $ref: "#/responses/conflictError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/networks/create"), s.APIHandler(libpod.CreateNetwork)).Methods(http.MethodPost) // swagger:operation POST /libpod/networks/{name}/connect libpod NetworkConnectLibpod // --- @@ -350,14 +350,14 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // name: create // description: attributes for connecting a container to a network // schema: - // $ref: "#/definitions/NetworkConnectRequest" + // $ref: "#/definitions/networkConnectRequestLibpod" // responses: // 200: // description: OK // 404: - // $ref: "#/responses/NoSuchNetwork" + // $ref: "#/responses/networkNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/networks/{name}/connect"), s.APIHandler(libpod.Connect)).Methods(http.MethodPost) // swagger:operation POST /libpod/networks/{name}/disconnect libpod NetworkDisconnectLibpod // --- @@ -377,14 +377,14 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // name: create // description: attributes for disconnecting a container from a network // schema: - // $ref: "#/definitions/NetworkCompatDisconnectRequest" + // $ref: "#/definitions/networkDisconnectRequest" // responses: // 200: // description: OK // 404: - // $ref: "#/responses/NoSuchNetwork" + // $ref: "#/responses/networkNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/networks/{name}/disconnect"), s.APIHandler(compat.Disconnect)).Methods(http.MethodPost) // swagger:operation POST /libpod/networks/prune libpod NetworkPruneLibpod // --- @@ -405,9 +405,9 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune networks with (or without, in case `label!=...` is used) the specified labels. // responses: // 200: - // $ref: "#/responses/NetworkPruneResponse" + // $ref: "#/responses/networkPruneResponse" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/networks/prune"), s.APIHandler(libpod.Prune)).Methods(http.MethodPost) return nil } diff --git a/pkg/api/server/register_ping.go b/pkg/api/server/register_ping.go index 22c7eb3fd..fcc8b4a10 100644 --- a/pkg/api/server/register_ping.go +++ b/pkg/api/server/register_ping.go @@ -59,7 +59,7 @@ func (s *APIServer) registerPingHandlers(r *mux.Router) error { // Available if service is backed by Podman, therefore may be used to // determine if talking to Podman engine or another engine // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle("/libpod/_ping", s.APIHandler(compat.Ping)).Methods(http.MethodGet, http.MethodHead) r.Handle(VersionedPath("/libpod/_ping"), s.APIHandler(compat.Ping)).Methods(http.MethodGet, http.MethodHead) return nil diff --git a/pkg/api/server/register_play.go b/pkg/api/server/register_play.go index 52bc75bcf..35da80ccc 100644 --- a/pkg/api/server/register_play.go +++ b/pkg/api/server/register_play.go @@ -57,9 +57,9 @@ func (s *APIServer) registerPlayHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodPlayKubeResponse" + // $ref: "#/responses/playKubeResponseLibpod" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/play/kube"), s.APIHandler(libpod.PlayKube)).Methods(http.MethodPost) // swagger:operation DELETE /libpod/play/kube libpod PlayKubeDownLibpod // --- @@ -72,9 +72,9 @@ func (s *APIServer) registerPlayHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsLibpodPlayKubeResponse" + // $ref: "#/responses/playKubeResponseLibpod" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.HandleFunc(VersionedPath("/libpod/play/kube"), s.APIHandler(libpod.PlayKubeDown)).Methods(http.MethodDelete) return nil } diff --git a/pkg/api/server/register_pods.go b/pkg/api/server/register_pods.go index 7aeafe724..d54cc413e 100644 --- a/pkg/api/server/register_pods.go +++ b/pkg/api/server/register_pods.go @@ -31,11 +31,11 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // - `ctr-number=<pod-ctr-number>` Number of containers in the pod. // responses: // 200: - // $ref: "#/responses/ListPodsResponse" + // $ref: "#/responses/podsListResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/json"), s.APIHandler(libpod.Pods)).Methods(http.MethodGet) // swagger:operation POST /libpod/pods/create pods PodCreateLibpod // --- @@ -53,14 +53,14 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // schema: // $ref: "#/definitions/IDResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 409: // description: status conflict // schema: // type: string // description: message describing error // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/create"), s.APIHandler(libpod.PodCreate)).Methods(http.MethodPost) // swagger:operation POST /libpod/pods/prune pods PodPruneLibpod // --- @@ -69,13 +69,13 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: '#/responses/PodPruneReport' + // $ref: '#/responses/podPruneResponse' // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 409: // description: pod already exists // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/prune"), s.APIHandler(libpod.PodPrune)).Methods(http.MethodPost) // swagger:operation DELETE /libpod/pods/{name} pods PodDeleteLibpod // --- @@ -94,13 +94,13 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // description : force removal of a running pod by first stopping all containers, then removing all containers in the pod // responses: // 200: - // $ref: '#/responses/PodRmReport' + // $ref: '#/responses/podRmResponse' // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}"), s.APIHandler(libpod.PodDelete)).Methods(http.MethodDelete) // swagger:operation GET /libpod/pods/{name}/json pods PodInspectLibpod // --- @@ -115,11 +115,11 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // description: the name or ID of the pod // responses: // 200: - // $ref: "#/responses/InspectPodResponse" + // $ref: "#/responses/podInspectResponse" // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}/json"), s.APIHandler(libpod.PodInspect)).Methods(http.MethodGet) // swagger:operation GET /libpod/pods/{name}/exists pods PodExistsLibpod // --- @@ -137,9 +137,9 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // 204: // description: pod exists // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}/exists"), s.APIHandler(libpod.PodExists)).Methods(http.MethodGet) // swagger:operation POST /libpod/pods/{name}/kill pods PodKillLibpod // --- @@ -159,15 +159,15 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // default: SIGKILL // responses: // 200: - // $ref: "#/responses/PodKillReport" + // $ref: "#/responses/podKillResponse" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 409: - // $ref: "#/responses/PodKillReport" + // $ref: "#/responses/podKillResponse" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}/kill"), s.APIHandler(libpod.PodKill)).Methods(http.MethodPost) // swagger:operation POST /libpod/pods/{name}/pause pods PodPauseLibpod // --- @@ -183,13 +183,13 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // description: the name or ID of the pod // responses: // 200: - // $ref: '#/responses/PodPauseReport' + // $ref: '#/responses/podPauseResponse' // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 409: - // $ref: '#/responses/PodPauseReport' + // $ref: '#/responses/podPauseResponse' // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}/pause"), s.APIHandler(libpod.PodPause)).Methods(http.MethodPost) // swagger:operation POST /libpod/pods/{name}/restart pods PodRestartLibpod // --- @@ -204,13 +204,13 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // description: the name or ID of the pod // responses: // 200: - // $ref: '#/responses/PodRestartReport' + // $ref: '#/responses/podRestartResponse' // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 409: - // $ref: "#/responses/PodRestartReport" + // $ref: "#/responses/podRestartResponse" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}/restart"), s.APIHandler(libpod.PodRestart)).Methods(http.MethodPost) // swagger:operation POST /libpod/pods/{name}/start pods PodStartLibpod // --- @@ -225,15 +225,15 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // description: the name or ID of the pod // responses: // 200: - // $ref: '#/responses/PodStartReport' + // $ref: '#/responses/podStartResponse' // 304: - // $ref: "#/responses/PodAlreadyStartedError" + // $ref: "#/responses/podAlreadyStartedError" // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 409: - // $ref: '#/responses/PodStartReport' + // $ref: '#/responses/podStartResponse' // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}/start"), s.APIHandler(libpod.PodStart)).Methods(http.MethodPost) // swagger:operation POST /libpod/pods/{name}/stop pods PodStopLibpod // --- @@ -252,17 +252,17 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // description: timeout // responses: // 200: - // $ref: '#/responses/PodStopReport' + // $ref: '#/responses/podStopResponse' // 304: - // $ref: "#/responses/PodAlreadyStoppedError" + // $ref: "#/responses/podAlreadyStoppedError" // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 409: - // $ref: "#/responses/PodStopReport" + // $ref: "#/responses/podStopResponse" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}/stop"), s.APIHandler(libpod.PodStop)).Methods(http.MethodPost) // swagger:operation POST /libpod/pods/{name}/unpause pods PodUnpauseLibpod // --- @@ -277,13 +277,13 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // description: the name or ID of the pod // responses: // 200: - // $ref: '#/responses/PodUnpauseReport' + // $ref: '#/responses/podUnpauseResponse' // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 409: - // $ref: '#/responses/PodUnpauseReport' + // $ref: '#/responses/podUnpauseResponse' // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}/unpause"), s.APIHandler(libpod.PodUnpause)).Methods(http.MethodPost) // swagger:operation GET /libpod/pods/{name}/top pods PodTopLibpod // --- @@ -315,17 +315,17 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // Requires ps(1) to be installed in the container if no ps(1) compatible AIX descriptors are used. // responses: // 200: - // $ref: "#/responses/DocsPodTopResponse" + // $ref: "#/responses/podTopResponse" // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/{name}/top"), s.APIHandler(libpod.PodTop)).Methods(http.MethodGet) // swagger:operation GET /libpod/pods/stats pods PodStatsAllLibpod // --- // tags: // - pods - // summary: Get stats for one or more pods + // summary: Statistics for one or more pods // description: Display a live stream of resource usage statistics for the containers in one or more pods // parameters: // - in: query @@ -342,11 +342,11 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DocsPodTopResponse" + // $ref: "#/responses/podStatsResponse" // 404: - // $ref: "#/responses/NoSuchPod" + // $ref: "#/responses/podNotFound" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/pods/stats"), s.APIHandler(libpod.PodStats)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_secrets.go b/pkg/api/server/register_secrets.go index 26bc07834..f4608baa6 100644 --- a/pkg/api/server/register_secrets.go +++ b/pkg/api/server/register_secrets.go @@ -36,7 +36,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // '201': // $ref: "#/responses/SecretCreateResponse" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/libpod/secrets/create"), s.APIHandler(libpod.CreateSecret)).Methods(http.MethodPost) // swagger:operation GET /libpod/secrets/json libpod SecretListLibpod // --- @@ -59,7 +59,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // '200': // "$ref": "#/responses/SecretListResponse" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/libpod/secrets/json"), s.APIHandler(compat.ListSecrets)).Methods(http.MethodGet) // swagger:operation GET /libpod/secrets/{name}/json libpod SecretInspectLibpod // --- @@ -80,7 +80,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // '404': // "$ref": "#/responses/NoSuchSecret" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/libpod/secrets/{name}/json"), s.APIHandler(compat.InspectSecret)).Methods(http.MethodGet) // swagger:operation DELETE /libpod/secrets/{name} libpod SecretDeleteLibpod // --- @@ -106,7 +106,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // '404': // "$ref": "#/responses/NoSuchSecret" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/libpod/secrets/{name}"), s.APIHandler(compat.RemoveSecret)).Methods(http.MethodDelete) /* @@ -133,7 +133,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // '200': // "$ref": "#/responses/SecretListCompatResponse" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/secrets"), s.APIHandler(compat.ListSecrets)).Methods(http.MethodGet) r.Handle("/secrets", s.APIHandler(compat.ListSecrets)).Methods(http.MethodGet) // swagger:operation POST /secrets/create compat SecretCreate @@ -156,7 +156,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // '409': // "$ref": "#/responses/SecretInUse" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/secrets/create"), s.APIHandler(compat.CreateSecret)).Methods(http.MethodPost) r.Handle("/secrets/create", s.APIHandler(compat.CreateSecret)).Methods(http.MethodPost) // swagger:operation GET /secrets/{name} compat SecretInspect @@ -178,7 +178,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // '404': // "$ref": "#/responses/NoSuchSecret" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/secrets/{name}"), s.APIHandler(compat.InspectSecret)).Methods(http.MethodGet) r.Handle("/secrets/{name}", s.APIHandler(compat.InspectSecret)).Methods(http.MethodGet) // swagger:operation DELETE /secrets/{name} compat SecretDelete @@ -200,7 +200,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // '404': // "$ref": "#/responses/NoSuchSecret" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/secrets/{name}"), s.APIHandler(compat.RemoveSecret)).Methods(http.MethodDelete) r.Handle("/secret/{name}", s.APIHandler(compat.RemoveSecret)).Methods(http.MethodDelete) diff --git a/pkg/api/server/register_system.go b/pkg/api/server/register_system.go index a70f3b5f2..8932ecc81 100644 --- a/pkg/api/server/register_system.go +++ b/pkg/api/server/register_system.go @@ -19,9 +19,9 @@ func (s *APIServer) registerSystemHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: '#/responses/SystemDiskUse' + // $ref: '#/responses/systemDiskUsage' // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/system/df"), s.APIHandler(compat.GetDiskUsage)).Methods(http.MethodGet) // Added non version path to URI to support docker non versioned paths r.Handle("/system/df", s.APIHandler(compat.GetDiskUsage)).Methods(http.MethodGet) @@ -34,11 +34,11 @@ func (s *APIServer) registerSystemHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: '#/responses/SystemPruneReport' + // $ref: '#/responses/systemPruneResponse' // 400: - // $ref: "#/responses/BadParamError" + // $ref: "#/responses/badParamError" // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/system/prune"), s.APIHandler(libpod.SystemPrune)).Methods(http.MethodPost) // swagger:operation GET /libpod/system/df libpod SystemDataUsageLibpod // --- @@ -50,9 +50,9 @@ func (s *APIServer) registerSystemHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: '#/responses/SystemDiskUse' + // $ref: '#/responses/systemDiskUsage' // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/system/df"), s.APIHandler(libpod.DiskUsage)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_version.go b/pkg/api/server/register_version.go index e9680f9ef..f7bdc2ea9 100644 --- a/pkg/api/server/register_version.go +++ b/pkg/api/server/register_version.go @@ -17,7 +17,7 @@ func (s *APIServer) registerVersionHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/Version" + // $ref: "#/responses/versionResponse" r.Handle("/version", s.APIHandler(compat.VersionHandler)).Methods(http.MethodGet) r.Handle(VersionedPath("/version"), s.APIHandler(compat.VersionHandler)).Methods(http.MethodGet) // swagger:operation GET /libpod/version libpod SystemVersionLibpod @@ -29,7 +29,7 @@ func (s *APIServer) registerVersionHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/Version" + // $ref: "#/responses/versionResponse" r.Handle(VersionedPath("/libpod/version"), s.APIHandler(compat.VersionHandler)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go index d36350146..820953b09 100644 --- a/pkg/api/server/register_volumes.go +++ b/pkg/api/server/register_volumes.go @@ -19,14 +19,14 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // name: create // description: attributes for creating a volume // schema: - // $ref: "#/definitions/VolumeCreate" + // $ref: "#/definitions/VolumeCreateOptions" // produces: // - application/json // responses: // '201': - // $ref: "#/responses/VolumeCreateResponse" + // $ref: "#/responses/volumeCreateResponse" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/libpod/volumes/create"), s.APIHandler(libpod.CreateVolume)).Methods(http.MethodPost) // swagger:operation GET /libpod/volumes/{name}/exists libpod VolumeExistsLibpod // --- @@ -46,9 +46,9 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // 204: // description: volume exists // 404: - // $ref: '#/responses/NoSuchVolume' + // $ref: '#/responses/volumeNotFound' // 500: - // $ref: '#/responses/InternalError' + // $ref: '#/responses/internalError' r.Handle(VersionedPath("/libpod/volumes/{name}/exists"), s.APIHandler(libpod.ExistsVolume)).Methods(http.MethodGet) // swagger:operation GET /libpod/volumes/json libpod VolumeListLibpod // --- @@ -71,9 +71,9 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // - `until=<timestamp>` List volumes created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. // responses: // '200': - // "$ref": "#/responses/VolumeList" + // "$ref": "#/responses/volumeListLibpod" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/libpod/volumes/json"), s.APIHandler(libpod.ListVolumes)).Methods(http.MethodGet) // swagger:operation POST /libpod/volumes/prune libpod VolumePruneLibpod // --- @@ -93,9 +93,9 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune volumes with (or without, in case `label!=...` is used) the specified labels. // responses: // '200': - // "$ref": "#/responses/VolumePruneResponse" + // "$ref": "#/responses/volumePruneLibpod" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/libpod/volumes/prune"), s.APIHandler(libpod.PruneVolumes)).Methods(http.MethodPost) // swagger:operation GET /libpod/volumes/{name}/json libpod VolumeInspectLibpod // --- @@ -111,12 +111,12 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // produces: // - application/json // responses: - // '200': - // "$ref": "#/responses/VolumeCreateResponse" - // '404': - // "$ref": "#/responses/NoSuchVolume" - // '500': - // "$ref": "#/responses/InternalError" + // 200: + // $ref: "#/responses/volumeCreateResponse" + // 404: + // $ref: "#/responses/volumeNotFound" + // 500: + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/volumes/{name}/json"), s.APIHandler(libpod.InspectVolume)).Methods(http.MethodGet) // swagger:operation DELETE /libpod/volumes/{name} libpod VolumeDeleteLibpod // --- @@ -139,11 +139,11 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // $ref: "#/responses/NoSuchVolume" + // $ref: "#/responses/volumeNotFound" // 409: // description: Volume is in use and cannot be removed // 500: - // $ref: "#/responses/InternalError" + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/libpod/volumes/{name}"), s.APIHandler(libpod.RemoveVolume)).Methods(http.MethodDelete) /* @@ -173,9 +173,9 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // The boolean `dangling` filter is not yet implemented for this endpoint. // responses: // '200': - // "$ref": "#/responses/VolumeListResponse" + // "$ref": "#/responses/volumeList" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/volumes"), s.APIHandler(compat.ListVolumes)).Methods(http.MethodGet) r.Handle("/volumes", s.APIHandler(compat.ListVolumes)).Methods(http.MethodGet) @@ -191,14 +191,14 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // attributes for creating a volume. // Note: If a volume by the same name exists, a 201 response with that volume's information will be generated. // schema: - // $ref: "#/definitions/DockerVolumeCreate" + // $ref: "#/definitions/volumeCreate" // produces: // - application/json // responses: // '201': - // "$ref": "#/responses/DockerVolumeInfoResponse" + // "$ref": "#/responses/volumeInspect" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/volumes/create"), s.APIHandler(compat.CreateVolume)).Methods(http.MethodPost) r.Handle("/volumes/create", s.APIHandler(compat.CreateVolume)).Methods(http.MethodPost) @@ -216,12 +216,12 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // produces: // - application/json // responses: - // '200': - // "$ref": "#/responses/DockerVolumeInfoResponse" - // '404': - // "$ref": "#/responses/NoSuchVolume" - // '500': - // "$ref": "#/responses/InternalError" + // 200: + // $ref: "#/responses/volumeInspect" + // 40': + // $ref: "#/responses/volumeNotFound" + // 500: + // $ref: "#/responses/internalError" r.Handle(VersionedPath("/volumes/{name}"), s.APIHandler(compat.InspectVolume)).Methods(http.MethodGet) r.Handle("/volumes/{name}", s.APIHandler(compat.InspectVolume)).Methods(http.MethodGet) @@ -249,11 +249,11 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // 204: // description: no error // 404: - // "$ref": "#/responses/NoSuchVolume" + // $ref: "#/responses/volumeNotFound" // 409: // description: Volume is in use and cannot be removed // 500: - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/volumes/{name}"), s.APIHandler(compat.RemoveVolume)).Methods(http.MethodDelete) r.Handle("/volumes/{name}", s.APIHandler(compat.RemoveVolume)).Methods(http.MethodDelete) @@ -275,9 +275,9 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune volumes with (or without, in case `label!=...` is used) the specified labels. // responses: // '200': - // "$ref": "#/responses/DockerVolumePruneResponse" + // "$ref": "#/responses/volumePruneResponse" // '500': - // "$ref": "#/responses/InternalError" + // "$ref": "#/responses/internalError" r.Handle(VersionedPath("/volumes/prune"), s.APIHandler(compat.PruneVolumes)).Methods(http.MethodPost) r.Handle("/volumes/prune", s.APIHandler(compat.PruneVolumes)).Methods(http.MethodPost) diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go index 7f5537fb4..7a7e35e8e 100644 --- a/pkg/api/server/server.go +++ b/pkg/api/server/server.go @@ -45,10 +45,8 @@ const ( UnlimitedServiceDuration = 0 * time.Second ) -var ( - // shutdownOnce ensures Shutdown() may safely be called from several go routines - shutdownOnce sync.Once -) +// shutdownOnce ensures Shutdown() may safely be called from several go routines +var shutdownOnce sync.Once // NewServer will create and configure a new API server with all defaults func NewServer(runtime *libpod.Runtime) (*APIServer, error) { @@ -209,7 +207,7 @@ func (s *APIServer) Serve() error { }() // Before we start serving, ensure umask is properly set for container creation. - _ = syscall.Umask(0022) + _ = syscall.Umask(0o022) errChan := make(chan error, 1) s.setupSystemd() diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go deleted file mode 100644 index 6cf89581a..000000000 --- a/pkg/api/server/swagger.go +++ /dev/null @@ -1,246 +0,0 @@ -package server - -import ( - "github.com/containers/podman/v4/libpod/define" - "github.com/containers/podman/v4/pkg/domain/entities" - "github.com/containers/podman/v4/pkg/domain/entities/reports" - "github.com/containers/podman/v4/pkg/errorhandling" - docker "github.com/docker/docker/api/types" -) - -// No such image -// swagger:response NoSuchImage -type swagErrNoSuchImage struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// No such container -// swagger:response NoSuchContainer -type swagErrNoSuchContainer struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// No such network -// swagger:response NoSuchNetwork -type swagErrNoSuchNetwork struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// No such exec instance -// swagger:response NoSuchExecInstance -type swagErrNoSuchExecInstance struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// No such volume -// swagger:response NoSuchVolume -type swagErrNoSuchVolume struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// No such pod -// swagger:response NoSuchPod -type swagErrNoSuchPod struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// No such manifest -// swagger:response NoSuchManifest -type swagErrNoSuchManifest struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// Internal server error -// swagger:response InternalError -type swagInternalError struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// Conflict error in operation -// swagger:response ConflictError -type swagConflictError struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// Bad parameter in request -// swagger:response BadParamError -type swagBadParamError struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// Container already started -// swagger:response ContainerAlreadyStartedError -type swagContainerAlreadyStartedError struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// Container already stopped -// swagger:response ContainerAlreadyStoppedError -type swagContainerAlreadyStopped struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// Pod already started -// swagger:response PodAlreadyStartedError -type swagPodAlreadyStartedError struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// Pod already stopped -// swagger:response PodAlreadyStoppedError -type swagPodAlreadyStopped struct { - // in:body - Body struct { - errorhandling.ErrorModel - } -} - -// Image summary for compat API -// swagger:response DockerImageSummaryResponse -type swagDockerImageSummaryResponse struct { - // in:body - Body []docker.ImageSummary -} - -// Image summary for libpod API -// swagger:response LibpodImageSummaryResponse -type swagLibpodImageSummaryResponse struct { - // in:body - Body []entities.ImageSummary -} - -// List Containers -// swagger:response DocsListContainer -type swagListContainers struct { - // in:body - Body struct { - // This causes go-swagger to crash - // handlers.Container - } -} - -// Success -// swagger:response -type ok struct { - // in:body - Body struct { - // example: OK - ok string - } -} - -// Volume prune response -// swagger:response VolumePruneResponse -type swagVolumePruneResponse struct { - // in:body - Body []reports.PruneReport -} - -// Volume create response -// swagger:response VolumeCreateResponse -type swagVolumeCreateResponse struct { - // in:body - Body struct { - entities.VolumeConfigResponse - } -} - -// Volume list -// swagger:response VolumeList -type swagVolumeListResponse struct { - // in:body - Body []entities.VolumeConfigResponse -} - -// Healthcheck -// swagger:response HealthcheckRun -type swagHealthCheckRunResponse struct { - // in:body - Body struct { - define.HealthCheckResults - } -} - -// Version -// swagger:response Version -type swagVersion struct { - // in:body - Body struct { - entities.ComponentVersion - } -} - -// Disk usage -// swagger:response SystemDiskUse -type swagDiskUseResponse struct { - // in:body - Body struct { - entities.SystemDfReport - } -} - -// Prune report -// swagger:response SystemPruneReport -type swagSystemPruneReport struct { - // in:body - Body struct { - entities.SystemPruneReport - } -} - -// Auth response -// swagger:response SystemAuthResponse -type swagSystemAuthResponse struct { - // in:body - Body struct { - entities.AuthReport - } -} - -// Inspect response -// swagger:response InspectExecSession -type swagInspectExecSession struct { - // in:body - Body struct { - define.InspectExecSession - } -} diff --git a/pkg/api/types/types.go b/pkg/api/types/types.go index d5067cc54..034bae6d4 100644 --- a/pkg/api/types/types.go +++ b/pkg/api/types/types.go @@ -1,13 +1,5 @@ package types -const ( - // DefaultAPIVersion is the version of the compatible API the server defaults to - DefaultAPIVersion = "1.40" // See https://docs.docker.com/engine/api/v1.40/ - - // MinimalAPIVersion is the minimal required version of the compatible API - MinimalAPIVersion = "1.24" -) - type APIContextKey int const ( diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go index ee530528e..0c795faed 100644 --- a/pkg/autoupdate/autoupdate.go +++ b/pkg/autoupdate/autoupdate.go @@ -12,6 +12,7 @@ import ( "github.com/containers/image/v5/transports/alltransports" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/libpod/events" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/systemd" systemdDefine "github.com/containers/podman/v4/pkg/systemd/define" @@ -142,6 +143,8 @@ func AutoUpdate(ctx context.Context, runtime *libpod.Runtime, options entities.A } defer conn.Close() + runtime.NewSystemEvent(events.AutoUpdate) + // Update all images/container according to their auto-update policy. var allReports []*entities.AutoUpdateReport updatedRawImages := make(map[string]bool) diff --git a/pkg/bindings/containers/commit.go b/pkg/bindings/containers/commit.go index 41761a2c6..1a85bfc38 100644 --- a/pkg/bindings/containers/commit.go +++ b/pkg/bindings/containers/commit.go @@ -4,24 +4,24 @@ import ( "context" "net/http" - "github.com/containers/podman/v4/pkg/api/handlers" "github.com/containers/podman/v4/pkg/bindings" + "github.com/containers/podman/v4/pkg/domain/entities" ) // Commit creates a container image from a container. The container is defined by nameOrID. Use // the CommitOptions for finer grain control on characteristics of the resulting image. -func Commit(ctx context.Context, nameOrID string, options *CommitOptions) (handlers.IDResponse, error) { +func Commit(ctx context.Context, nameOrID string, options *CommitOptions) (entities.IDResponse, error) { if options == nil { options = new(CommitOptions) } - id := handlers.IDResponse{} + id := entities.IDResponse{} conn, err := bindings.GetClient(ctx) if err != nil { return id, err } params, err := options.ToParams() if err != nil { - return handlers.IDResponse{}, err + return entities.IDResponse{}, err } params.Set("container", nameOrID) response, err := conn.DoRequest(ctx, nil, http.MethodPost, "/commit", params, nil) diff --git a/pkg/bindings/containers/exec.go b/pkg/bindings/containers/exec.go index ce02763a1..3ad5d67d2 100644 --- a/pkg/bindings/containers/exec.go +++ b/pkg/bindings/containers/exec.go @@ -9,6 +9,7 @@ import ( "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/api/handlers" "github.com/containers/podman/v4/pkg/bindings" + "github.com/containers/podman/v4/pkg/domain/entities" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -41,7 +42,7 @@ func ExecCreate(ctx context.Context, nameOrID string, config *handlers.ExecCreat } defer resp.Body.Close() - respStruct := new(handlers.ExecCreateResponse) + respStruct := new(entities.IDResponse) if err := resp.Process(respStruct); err != nil { return "", err } diff --git a/pkg/bindings/images/build_unix.go b/pkg/bindings/images/build_unix.go index 67a5e2998..32e2ba9af 100644 --- a/pkg/bindings/images/build_unix.go +++ b/pkg/bindings/images/build_unix.go @@ -11,7 +11,7 @@ import ( func checkHardLink(fi os.FileInfo) (devino, bool) { st := fi.Sys().(*syscall.Stat_t) return devino{ - Dev: uint64(st.Dev), - Ino: uint64(st.Ino), + Dev: uint64(st.Dev), // nolint: unconvert + Ino: st.Ino, }, st.Nlink > 1 } diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go index 828f4922c..feff5d6e8 100644 --- a/pkg/bindings/manifests/manifests.go +++ b/pkg/bindings/manifests/manifests.go @@ -9,7 +9,6 @@ import ( "github.com/containers/image/v5/manifest" imageTypes "github.com/containers/image/v5/types" - "github.com/containers/podman/v4/pkg/api/handlers" "github.com/containers/podman/v4/pkg/auth" "github.com/containers/podman/v4/pkg/bindings" "github.com/containers/podman/v4/pkg/bindings/images" @@ -24,7 +23,7 @@ import ( // of a list if the name provided is a manifest list. The ID of the new manifest list // is returned as a string. func Create(ctx context.Context, name string, images []string, options *CreateOptions) (string, error) { - var idr handlers.IDResponse + var idr entities.IDResponse if options == nil { options = new(CreateOptions) } @@ -122,9 +121,7 @@ func Remove(ctx context.Context, name, digest string, _ *RemoveOptions) (string, // the name will be used instead. If the optional all boolean is specified, all images specified // in the list will be pushed as well. func Push(ctx context.Context, name, destination string, options *images.PushOptions) (string, error) { - var ( - idr handlers.IDResponse - ) + var idr entities.IDResponse if options == nil { options = new(images.PushOptions) } diff --git a/pkg/domain/entities/filters.go b/pkg/domain/entities/filters.go index 2ddbffbcd..a42c5cd24 100644 --- a/pkg/domain/entities/filters.go +++ b/pkg/domain/entities/filters.go @@ -15,23 +15,17 @@ type Named interface { Name() string } -// Named interface allows filters to access Name() of object +// Names interface allows filters to access Name() of object type Names interface { Names() []string } -// IDOrName interface allows filters to access ID() or Name() of object +// IDOrNamed interface allows filters to access ID() or Name() of object type IDOrNamed interface { Identifier Named } -// IDOrName interface allows filters to access ID() or Names() of object -type IDOrNames interface { - Identifier - Names -} - type ImageFilter func(Image) bool type VolumeFilter func(Volume) bool type ContainerFilter func(Container) bool diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index bf7c33f2b..f1ba21650 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -54,6 +54,8 @@ type PlayKubeOptions struct { LogOptions []string // Start - don't start the pod if false Start types.OptionalBool + // ServiceContainer - creates a service container that is started before and is stopped after all pods. + ServiceContainer bool // Userns - define the user namespace to use. Userns string } diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index a19edcbf0..9cbbe2bf1 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -20,15 +20,15 @@ type PodKillOptions struct { type PodKillReport struct { Errs []error - Id string //nolint + Id string // nolint } type ListPodsReport struct { Cgroup string Containers []*ListPodContainer Created time.Time - Id string //nolint - InfraId string //nolint + Id string // nolint + InfraId string // nolint Name string Namespace string // Network names connected to infra container @@ -38,7 +38,7 @@ type ListPodsReport struct { } type ListPodContainer struct { - Id string //nolint + Id string // nolint Names string Status string } @@ -50,7 +50,7 @@ type PodPauseOptions struct { type PodPauseReport struct { Errs []error - Id string //nolint + Id string // nolint } type PodunpauseOptions struct { @@ -60,7 +60,7 @@ type PodunpauseOptions struct { type PodUnpauseReport struct { Errs []error - Id string //nolint + Id string // nolint } type PodStopOptions struct { @@ -72,7 +72,7 @@ type PodStopOptions struct { type PodStopReport struct { Errs []error - Id string //nolint + Id string // nolint } type PodRestartOptions struct { @@ -82,7 +82,7 @@ type PodRestartOptions struct { type PodRestartReport struct { Errs []error - Id string //nolint + Id string // nolint } type PodStartOptions struct { @@ -92,7 +92,7 @@ type PodStartOptions struct { type PodStartReport struct { Errs []error - Id string //nolint + Id string // nolint } type PodRmOptions struct { @@ -105,7 +105,7 @@ type PodRmOptions struct { type PodRmReport struct { Err error - Id string //nolint + Id string // nolint } // PddSpec is an abstracted version of PodSpecGen designed to eventually accept options @@ -287,7 +287,7 @@ func NewInfraContainerCreateOptions() ContainerCreateOptions { } type PodCreateReport struct { - Id string //nolint + Id string // nolint } func (p *PodCreateOptions) CPULimits() *specs.LinuxCPU { @@ -389,7 +389,7 @@ type PodPruneOptions struct { type PodPruneReport struct { Err error - Id string //nolint + Id string // nolint } type PodTopOptions struct { @@ -437,16 +437,33 @@ type PodStatsOptions struct { // PodStatsReport includes pod-resource statistics data. type PodStatsReport struct { - CPU string - MemUsage string + // Percentage of CPU utilized by pod + // example: 75.5% + CPU string + // Humanized Memory usage and maximum + // example: 12mb / 24mb + MemUsage string + // Memory usage and maximum in bytes + // example: 1,000,000 / 4,000,000 MemUsageBytes string - Mem string - NetIO string - BlockIO string - PIDS string - Pod string - CID string - Name string + // Percentage of Memory utilized by pod + // example: 50.5% + Mem string + // Network usage inbound + outbound + NetIO string + // Humanized disk usage read + write + BlockIO string + // Container PID + PIDS string + // Pod ID + // example: 62310217a19e + Pod string + // Container ID + // example: e43534f89a7d + CID string + // Pod Name + // example: elastic_pascal + Name string } // ValidatePodStatsOptions validates the specified slice and options. Allows @@ -475,7 +492,7 @@ func ValidatePodStatsOptions(args []string, options *PodStatsOptions) error { } } -// Converts PodLogOptions to ContainerLogOptions +// PodLogsOptionsToContainerLogsOptions converts PodLogOptions to ContainerLogOptions func PodLogsOptionsToContainerLogsOptions(options PodLogsOptions) ContainerLogsOptions { // PodLogsOptions are similar but contains few extra fields like ctrName // So cast other values as is so we can re-use the code diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go index bed3183e9..5ae8a4931 100644 --- a/pkg/domain/entities/types.go +++ b/pkg/domain/entities/types.go @@ -9,6 +9,7 @@ import ( "github.com/containers/podman/v4/libpod/events" "github.com/containers/podman/v4/pkg/specgen" "github.com/containers/storage/pkg/archive" + dockerAPI "github.com/docker/docker/api/types" ) type Container struct { @@ -26,8 +27,10 @@ type Report struct { type PodDeleteReport struct{ Report } -type VolumeDeleteOptions struct{} -type VolumeDeleteReport struct{ Report } +type ( + VolumeDeleteOptions struct{} + VolumeDeleteReport struct{ Report } +) type NetFlags struct { AddHosts []string `json:"add-host,omitempty"` @@ -59,7 +62,7 @@ type NetOptions struct { NetworkOptions map[string][]string `json:"network_options,omitempty"` } -// All CLI inspect commands and inspect sub-commands use the same options +// InspectOptions all CLI inspect commands and inspect sub-commands use the same options type InspectOptions struct { // Format - change the output to JSON or a Go template. Format string `json:",omitempty"` @@ -73,7 +76,7 @@ type InspectOptions struct { All bool `json:",omitempty"` } -// All API and CLI diff commands and diff sub-commands use the same options +// DiffOptions all API and CLI diff commands and diff sub-commands use the same options type DiffOptions struct { Format string `json:",omitempty"` // CLI only Latest bool `json:",omitempty"` // API and CLI, only supported by containers @@ -115,3 +118,11 @@ type BuildReport struct { // ID of the image. ID string } + +type IDOrNameResponse struct { + // The Id or Name of an object + IDOrName string +} + +// swagger:model +type IDResponse dockerAPI.IDResponse diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go index f2e60a0db..84f85b83f 100644 --- a/pkg/domain/entities/volumes.go +++ b/pkg/domain/entities/volumes.go @@ -4,75 +4,10 @@ import ( "net/url" "github.com/containers/podman/v4/libpod/define" - docker_api_types "github.com/docker/docker/api/types" - docker_api_types_volume "github.com/docker/docker/api/types/volume" ) -// Volume volume -// swagger:model Volume -type volume struct { - - // Date/Time the volume was created. - CreatedAt string `json:"CreatedAt,omitempty"` - - // Name of the volume driver used by the volume. - // Required: true - Driver string `json:"Driver"` - - // User-defined key/value metadata. - // Required: true - Labels map[string]string `json:"Labels"` - - // Mount path of the volume on the host. - // Required: true - Mountpoint string `json:"Mountpoint"` - - // Name of the volume. - // Required: true - Name string `json:"Name"` - - // The driver specific options used when creating the volume. - // - // Required: true - Options map[string]string `json:"Options"` - - // The level at which the volume exists. Either `global` for cluster-wide, - // or `local` for machine level. - // - // Required: true - Scope string `json:"Scope"` - - // Low-level details about the volume, provided by the volume driver. - // Details are returned as a map with key/value pairs: - // `{"key":"value","key2":"value2"}`. - // - // The `Status` field is optional, and is omitted if the volume driver - // does not support this feature. - // - Status map[string]interface{} `json:"Status,omitempty"` - - // usage data - UsageData *VolumeUsageData `json:"UsageData,omitempty"` -} - -type VolumeUsageData struct { - - // The number of containers referencing this volume. This field - // is set to `-1` if the reference-count is not available. - // - // Required: true - RefCount int64 `json:"RefCount"` - - // Amount of disk space used by the volume (in bytes). This information - // is only available for volumes created with the `"local"` volume - // driver. For volumes created with other volume drivers, this field - // is set to `-1` ("not available") - // - // Required: true - Size int64 `json:"Size"` -} - -// swagger:model VolumeCreate +// VolumeCreateOptions provides details for creating volumes +// swagger:model type VolumeCreateOptions struct { // New volume's name. Can be left blank Name string `schema:"name"` @@ -86,11 +21,6 @@ type VolumeCreateOptions struct { Options map[string]string `schema:"opts"` } -type IDOrNameResponse struct { - // The Id or Name of an object - IDOrName string -} - type VolumeConfigResponse struct { define.InspectVolumeData } @@ -103,7 +33,7 @@ type VolumeRmOptions struct { type VolumeRmReport struct { Err error - Id string //nolint + Id string // nolint } type VolumeInspectReport struct { @@ -124,74 +54,14 @@ type VolumeListReport struct { VolumeConfigResponse } -// VolumeListBody Volume list response -// swagger:model VolumeListBody -type VolumeListBody struct { - Volumes []docker_api_types_volume.VolumeListOKBody -} - -// Volume list response -// swagger:response VolumeListResponse -type SwagVolumeListResponse struct { - // in:body - Body struct { - VolumeListBody - } -} - /* * Docker API compatibility types */ -// swagger:model DockerVolumeCreate -type DockerVolumeCreate VolumeCreateBody - -// This response definition is used for both the create and inspect endpoints -// swagger:response DockerVolumeInfoResponse -type SwagDockerVolumeInfoResponse struct { - // in:body - Body struct { - volume - } -} - -// Volume prune response -// swagger:response DockerVolumePruneResponse -type SwagDockerVolumePruneResponse struct { - // in:body - Body struct { - docker_api_types.VolumesPruneReport - } -} - -// VolumeCreateBody Volume configuration -// swagger:model VolumeCreateBody -type VolumeCreateBody struct { - - // Name of the volume driver to use. - // Required: true - Driver string `json:"Driver"` - - // A mapping of driver options and values. These options are - // passed directly to the driver and are driver specific. - // - // Required: true - DriverOpts map[string]string `json:"DriverOpts"` - - // User-defined key/value metadata. - // Required: true - Labels map[string]string `json:"Labels"` - - // The new volume's name. If not specified, Docker generates a name. - // - // Required: true - Name string `json:"Name"` -} - // VolumeMountReport describes the response from volume mount type VolumeMountReport struct { Err error - Id string //nolint + Id string // nolint Name string Path string } @@ -199,5 +69,5 @@ type VolumeMountReport struct { // VolumeUnmountReport describes the response from umounting a volume type VolumeUnmountReport struct { Err error - Id string //nolint + Id string // nolint } diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 5ca678d6f..d2fafccb1 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -292,7 +292,13 @@ func (ic *ContainerEngine) removeContainer(ctx context.Context, ctr *libpod.Cont logrus.Debugf("Failed to remove container %s: %s", ctr.ID(), err.Error()) switch errors.Cause(err) { case define.ErrNoSuchCtr: - if options.Ignore { + // Ignore if the container does not exist (anymore) when either + // it has been requested by the user of if the container is a + // service one. Service containers are removed along with its + // pods which in turn are removed along with their infra + // container. Hence, there is an inherent race when removing + // infra containers with service containers in parallel. + if options.Ignore || ctr.IsService() { logrus.Debugf("Ignoring error (--allow-missing): %v", err) return nil } @@ -1107,7 +1113,7 @@ func (ic *ContainerEngine) GetContainerExitCode(ctx context.Context, ctr *libpod time.Sleep(250 * time.Millisecond) continue } - return int(event.ContainerExitCode) + return event.ContainerExitCode } logrus.Errorf("Could not retrieve exit code from event: %v", err) return define.ExecErrorCodeNotFound diff --git a/pkg/domain/infra/abi/parse/parse.go b/pkg/domain/infra/abi/parse/parse.go index 3bac2ef99..66794e592 100644 --- a/pkg/domain/infra/abi/parse/parse.go +++ b/pkg/domain/infra/abi/parse/parse.go @@ -43,7 +43,7 @@ func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error) if err != nil { return nil, errors.Wrapf(err, "cannot convert inodes %s to integer", splitO[1]) } - libpodOptions = append(libpodOptions, libpod.WithVolumeInodes(uint64(inodes))) + libpodOptions = append(libpodOptions, libpod.WithVolumeInodes(inodes)) finalVal = append(finalVal, o) // set option "INODES": "$size" volumeOptions["INODES"] = splitO[1] diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 019361694..e04ab3a1a 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -28,12 +28,74 @@ import ( "github.com/containers/podman/v4/pkg/specgenutil" "github.com/containers/podman/v4/pkg/util" "github.com/ghodss/yaml" + "github.com/opencontainers/go-digest" "github.com/pkg/errors" "github.com/sirupsen/logrus" yamlv2 "gopkg.in/yaml.v2" ) -func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { +// createServiceContainer creates a container that can later on +// be associated with the pods of a K8s yaml. It will be started along with +// the first pod. +func (ic *ContainerEngine) createServiceContainer(ctx context.Context, name string, options entities.PlayKubeOptions) (*libpod.Container, error) { + // Make sure to replace the service container as well if requested by + // the user. + if options.Replace { + if _, err := ic.ContainerRm(ctx, []string{name}, entities.RmOptions{Force: true, Ignore: true}); err != nil { + return nil, fmt.Errorf("replacing service container: %w", err) + } + } + + // Similar to infra containers, a service container is using the pause image. + image, err := generate.PullOrBuildInfraImage(ic.Libpod, "") + if err != nil { + return nil, fmt.Errorf("image for service container: %w", err) + } + + ctrOpts := entities.ContainerCreateOptions{ + // Inherited from infra containers + ImageVolume: "bind", + IsInfra: false, + MemorySwappiness: -1, + // No need to spin up slirp etc. + Net: &entities.NetOptions{Network: specgen.Namespace{NSMode: specgen.NoNetwork}}, + } + + // Create and fill out the runtime spec. + s := specgen.NewSpecGenerator(image, false) + if err := specgenutil.FillOutSpecGen(s, &ctrOpts, []string{}); err != nil { + return nil, fmt.Errorf("completing spec for service container: %w", err) + } + s.Name = name + + runtimeSpec, spec, opts, err := generate.MakeContainer(ctx, ic.Libpod, s, false, nil) + if err != nil { + return nil, fmt.Errorf("creating runtime spec for service container: %w", err) + } + opts = append(opts, libpod.WithIsService()) + opts = append(opts, libpod.WithSdNotifyMode(define.SdNotifyModeConmon)) + + // Create a new libpod container based on the spec. + ctr, err := ic.Libpod.NewContainer(ctx, runtimeSpec, spec, false, opts...) + if err != nil { + return nil, fmt.Errorf("creating service container: %w", err) + } + + return ctr, nil +} + +// Creates the name for a service container based on the provided content of a +// K8s yaml file. +func serviceContainerName(content []byte) string { + // The name of the service container is the first 12 + // characters of the yaml file's hash followed by the + // '-service' suffix to guarantee a predictable and + // discoverable name. + hash := digest.FromBytes(content).Encoded() + return hash[0:12] + "-service" +} + +func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options entities.PlayKubeOptions) (_ *entities.PlayKubeReport, finalErr error) { report := &entities.PlayKubeReport{} validKinds := 0 @@ -67,6 +129,25 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options return nil, errors.Wrap(err, "unable to read kube YAML") } + // TODO: create constants for the various "kinds" of yaml files. + var serviceContainer *libpod.Container + if options.ServiceContainer && (kind == "Pod" || kind == "Deployment") { + ctr, err := ic.createServiceContainer(ctx, serviceContainerName(content), options) + if err != nil { + return nil, err + } + serviceContainer = ctr + // Make sure to remove the container in case something goes wrong below. + defer func() { + if finalErr == nil { + return + } + if err := ic.Libpod.RemoveContainer(ctx, ctr, true, false, nil); err != nil { + logrus.Errorf("Cleaning up service container after failure: %v", err) + } + }() + } + switch kind { case "Pod": var podYAML v1.Pod @@ -90,7 +171,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options podYAML.Annotations[name] = val } - r, err := ic.playKubePod(ctx, podTemplateSpec.ObjectMeta.Name, &podTemplateSpec, options, &ipIndex, podYAML.Annotations, configMaps) + r, err := ic.playKubePod(ctx, podTemplateSpec.ObjectMeta.Name, &podTemplateSpec, options, &ipIndex, podYAML.Annotations, configMaps, serviceContainer) if err != nil { return nil, err } @@ -104,7 +185,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options return nil, errors.Wrap(err, "unable to read YAML as Kube Deployment") } - r, err := ic.playKubeDeployment(ctx, &deploymentYAML, options, &ipIndex, configMaps) + r, err := ic.playKubeDeployment(ctx, &deploymentYAML, options, &ipIndex, configMaps, serviceContainer) if err != nil { return nil, err } @@ -148,7 +229,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options return report, nil } -func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions, ipIndex *int, configMaps []v1.ConfigMap) (*entities.PlayKubeReport, error) { +func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions, ipIndex *int, configMaps []v1.ConfigMap, serviceContainer *libpod.Container) (*entities.PlayKubeReport, error) { var ( deploymentName string podSpec v1.PodTemplateSpec @@ -170,7 +251,7 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM // create "replicas" number of pods for i = 0; i < numReplicas; i++ { podName := fmt.Sprintf("%s-pod-%d", deploymentName, i) - podReport, err := ic.playKubePod(ctx, podName, &podSpec, options, ipIndex, deploymentYAML.Annotations, configMaps) + podReport, err := ic.playKubePod(ctx, podName, &podSpec, options, ipIndex, deploymentYAML.Annotations, configMaps, serviceContainer) if err != nil { return nil, errors.Wrapf(err, "error encountered while bringing up pod %s", podName) } @@ -179,7 +260,7 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM return &report, nil } -func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec, options entities.PlayKubeOptions, ipIndex *int, annotations map[string]string, configMaps []v1.ConfigMap) (*entities.PlayKubeReport, error) { +func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec, options entities.PlayKubeOptions, ipIndex *int, annotations map[string]string, configMaps []v1.ConfigMap, serviceContainer *libpod.Container) (*entities.PlayKubeReport, error) { var ( writer io.Writer playKubePod entities.PlayKubePod @@ -367,6 +448,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY podSpec.PodSpecGen.NoInfra = false podSpec.PodSpecGen.InfraContainerSpec = specgen.NewSpecGenerator(infraImage, false) podSpec.PodSpecGen.InfraContainerSpec.NetworkOptions = p.NetworkOptions + podSpec.PodSpecGen.InfraContainerSpec.SdNotifyMode = define.SdNotifyModeIgnore err = specgenutil.FillOutSpecGen(podSpec.PodSpecGen.InfraContainerSpec, &infraOptions, []string{}) if err != nil { @@ -374,6 +456,10 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } } + if serviceContainer != nil { + podSpec.PodSpecGen.ServiceContainerID = serviceContainer.ID() + } + // Create the Pod pod, err := generate.MakePod(&podSpec, ic.Libpod) if err != nil { @@ -446,10 +532,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if err != nil { return nil, err } + specGen.SdNotifyMode = define.SdNotifyModeIgnore rtSpec, spec, opts, err := generate.MakeContainer(ctx, ic.Libpod, specGen, false, nil) if err != nil { return nil, err } + opts = append(opts, libpod.WithSdNotifyMode(define.SdNotifyModeIgnore)) ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...) if err != nil { return nil, err @@ -500,6 +588,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if err != nil { return nil, err } + opts = append(opts, libpod.WithSdNotifyMode(define.SdNotifyModeIgnore)) ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...) if err != nil { return nil, err @@ -872,5 +961,6 @@ func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, _ e if err != nil { return nil, err } + return reports, nil } diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 17df0e3f8..10f3e70b1 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -216,9 +216,9 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System Tag: stat.Tag, ImageID: stat.ID, Created: stat.Created, - Size: int64(stat.Size), - SharedSize: int64(stat.SharedSize), - UniqueSize: int64(stat.UniqueSize), + Size: stat.Size, + SharedSize: stat.SharedSize, + UniqueSize: stat.UniqueSize, Containers: stat.Containers, } dfImages = append(dfImages, &report) diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go index e33c26032..6ee1e7e86 100644 --- a/pkg/errorhandling/errorhandling.go +++ b/pkg/errorhandling/errorhandling.go @@ -86,7 +86,7 @@ func Contains(err error, sub error) bool { // PodConflictErrorModel is used in remote connections with podman type PodConflictErrorModel struct { Errs []string - Id string //nolint + Id string // nolint } // ErrorModel is used in remote connections with podman @@ -97,7 +97,8 @@ type ErrorModel struct { // human error message, formatted for a human to read // example: human error message Message string `json:"message"` - // http response code + // HTTP response code + // min: 400 ResponseCode int `json:"response"` } diff --git a/pkg/k8s.io/apimachinery/pkg/api/resource/amount.go b/pkg/k8s.io/apimachinery/pkg/api/resource/amount.go index 9f76f9154..d05984dac 100644 --- a/pkg/k8s.io/apimachinery/pkg/api/resource/amount.go +++ b/pkg/k8s.io/apimachinery/pkg/api/resource/amount.go @@ -221,7 +221,7 @@ func (a int64Amount) AsCanonicalBytes(out []byte) (result []byte, exponent int32 exponent = int32(a.scale) amount, times := removeInt64Factors(mantissa, 10) - exponent += int32(times) + exponent += times // make sure exponent is a multiple of 3 var ok bool diff --git a/pkg/k8s.io/apimachinery/pkg/api/resource/quantity.go b/pkg/k8s.io/apimachinery/pkg/api/resource/quantity.go index 965d2ccaf..dcc5df219 100644 --- a/pkg/k8s.io/apimachinery/pkg/api/resource/quantity.go +++ b/pkg/k8s.io/apimachinery/pkg/api/resource/quantity.go @@ -293,7 +293,7 @@ func ParseQuantity(str string) (Quantity, error) { switch { case exponent >= 0 && len(denom) == 0: // only handle positive binary numbers with the fast path - mantissa = int64(int64(mantissa) << uint64(exponent)) + mantissa <<= uint64(exponent) // 1Mi (2^20) has ~6 digits of decimal precision, so exponent*3/10 -1 is roughly the precision precision = 15 - int32(len(num)) - int32(float32(exponent)*3/10) - 1 default: @@ -313,7 +313,7 @@ func ParseQuantity(str string) (Quantity, error) { if err != nil { return Quantity{}, ErrNumeric } - if result, ok := int64Multiply(value, int64(mantissa)); ok { + if result, ok := int64Multiply(value, mantissa); ok { if !positive { result = -result } diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go index 57fb36fc9..0b2874baf 100644 --- a/pkg/machine/wsl/machine.go +++ b/pkg/machine/wsl/machine.go @@ -36,6 +36,7 @@ var ( const ( ErrorSuccessRebootInitiated = 1641 ErrorSuccessRebootRequired = 3010 + currentMachineVersion = 2 ) const containersConf = `[containers] @@ -168,6 +169,8 @@ type MachineVM struct { Rootful bool // SSH identity, username, etc machine.SSHConfig + // machine version + Version int } type ExitCodeError struct { @@ -241,12 +244,29 @@ func readAndMigrate(configPath string, name string) (*MachineVM, error) { return vm, err } err = json.Unmarshal(b, vm) - if err == nil && vm.Created.IsZero() { - err = vm.migrate40(configPath) + if err == nil && vm.Version < currentMachineVersion { + err = vm.migrateMachine(configPath) } + return vm, err } +func (v *MachineVM) migrateMachine(configPath string) error { + if v.Created.IsZero() { + if err := v.migrate40(configPath); err != nil { + return err + } + } + + // Update older machines to use lingering + if err := enableUserLinger(v, toDist(v.Name)); err != nil { + return err + } + + v.Version = currentMachineVersion + return v.writeConfig() +} + func (v *MachineVM) migrate40(configPath string) error { v.ConfigPath = configPath fi, err := os.Stat(configPath) @@ -255,7 +275,7 @@ func (v *MachineVM) migrate40(configPath string) error { } v.Created = fi.ModTime() v.LastUp = getLegacyLastStart(v) - return v.writeConfig() + return nil } func getLegacyLastStart(vm *MachineVM) time.Time { @@ -284,6 +304,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { sshDir := filepath.Join(homeDir, ".ssh") v.IdentityPath = filepath.Join(sshDir, v.Name) v.Rootful = opts.Rootful + v.Version = currentMachineVersion if err := downloadDistro(v, opts); err != nil { return false, err @@ -486,6 +507,10 @@ func configureSystem(v *MachineVM, dist string) error { return errors.Wrap(err, "could not generate linger service for guest OS") } + if err := enableUserLinger(v, dist); err != nil { + return err + } + if err := pipeCmdPassThrough("wsl", withUser(lingerSetup, user), "-d", dist, "sh"); err != nil { return errors.Wrap(err, "could not configure systemd settomgs for guest OS") } @@ -501,6 +526,15 @@ func configureSystem(v *MachineVM, dist string) error { return nil } +func enableUserLinger(v *MachineVM, dist string) error { + lingerCmd := "mkdir -p /var/lib/systemd/linger; touch /var/lib/systemd/linger/" + v.RemoteUsername + if err := runCmdPassThrough("wsl", "-d", dist, "sh", "-c", lingerCmd); err != nil { + return errors.Wrap(err, "could not enable linger for remote user on guest OS") + } + + return nil +} + func installScripts(dist string) error { if err := pipeCmdPassThrough("wsl", enterns, "-d", dist, "sh", "-c", "cat > /usr/local/bin/enterns; chmod 755 /usr/local/bin/enterns"); err != nil { diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go index 8f83fc09b..ed2e5408d 100644 --- a/pkg/specgen/generate/config_linux.go +++ b/pkg/specgen/generate/config_linux.go @@ -327,7 +327,7 @@ func deviceFromPath(path string) (*spec.LinuxDevice, error) { var ( devType string mode = stat.Mode - devNumber = uint64(stat.Rdev) + devNumber = uint64(stat.Rdev) // nolint: unconvert m = os.FileMode(mode) ) diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index d8008b10b..cc376125f 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -303,8 +303,8 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error { if err := unix.Stat(k, &statT); err != nil { return err } - v.Major = (int64(unix.Major(uint64(statT.Rdev)))) - v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) + v.Major = (int64(unix.Major(uint64(statT.Rdev)))) // nolint: unconvert + v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) // nolint: unconvert if s.ResourceLimits.BlockIO == nil { s.ResourceLimits.BlockIO = new(spec.LinuxBlockIO) } @@ -317,8 +317,8 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error { if err := unix.Stat(k, &statT); err != nil { return err } - v.Major = (int64(unix.Major(uint64(statT.Rdev)))) - v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) + v.Major = (int64(unix.Major(uint64(statT.Rdev)))) // nolint: unconvert + v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) // nolint: unconvert s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v) } } @@ -328,8 +328,8 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error { if err := unix.Stat(k, &statT); err != nil { return err } - v.Major = (int64(unix.Major(uint64(statT.Rdev)))) - v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) + v.Major = (int64(unix.Major(uint64(statT.Rdev)))) // nolint: unconvert + v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) // nolint: unconvert s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v) } } @@ -339,8 +339,8 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error { if err := unix.Stat(k, &statT); err != nil { return err } - v.Major = (int64(unix.Major(uint64(statT.Rdev)))) - v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) + v.Major = (int64(unix.Major(uint64(statT.Rdev)))) // nolint: unconvert + v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) // nolint: unconvert s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v) } } diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index e4c149abf..f37d79798 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -381,6 +381,22 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener Options: options, } s.Volumes = append(s.Volumes, &cmVolume) + case KubeVolumeTypeCharDevice: + // We are setting the path as hostPath:mountPath to comply with pkg/specgen/generate.DeviceFromPath. + // The type is here just to improve readability as it is not taken into account when the actual device is created. + device := spec.LinuxDevice{ + Path: fmt.Sprintf("%s:%s", volumeSource.Source, volume.MountPath), + Type: "c", + } + s.Devices = append(s.Devices, device) + case KubeVolumeTypeBlockDevice: + // We are setting the path as hostPath:mountPath to comply with pkg/specgen/generate.DeviceFromPath. + // The type is here just to improve readability as it is not taken into account when the actual device is created. + device := spec.LinuxDevice{ + Path: fmt.Sprintf("%s:%s", volumeSource.Source, volume.MountPath), + Type: "b", + } + s.Devices = append(s.Devices, device) default: return nil, errors.Errorf("Unsupported volume source type") } diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go index 27881e77a..1d6d49b9d 100644 --- a/pkg/specgen/generate/kube/volume.go +++ b/pkg/specgen/generate/kube/volume.go @@ -22,8 +22,10 @@ type KubeVolumeType int const ( KubeVolumeTypeBindMount KubeVolumeType = iota - KubeVolumeTypeNamed KubeVolumeType = iota - KubeVolumeTypeConfigMap KubeVolumeType = iota + KubeVolumeTypeNamed + KubeVolumeTypeConfigMap + KubeVolumeTypeBlockDevice + KubeVolumeTypeCharDevice ) //nolint:revive @@ -78,7 +80,30 @@ func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource) (*KubeVolume, error) if st.Mode()&os.ModeSocket != os.ModeSocket { return nil, errors.Errorf("checking HostPathSocket: path %s is not a socket", hostPath.Path) } - + case v1.HostPathBlockDev: + dev, err := os.Stat(hostPath.Path) + if err != nil { + return nil, errors.Wrap(err, "error checking HostPathBlockDevice") + } + if dev.Mode()&os.ModeCharDevice == os.ModeCharDevice { + return nil, errors.Errorf("checking HostPathDevice: path %s is not a block device", hostPath.Path) + } + return &KubeVolume{ + Type: KubeVolumeTypeBlockDevice, + Source: hostPath.Path, + }, nil + case v1.HostPathCharDev: + dev, err := os.Stat(hostPath.Path) + if err != nil { + return nil, errors.Wrap(err, "error checking HostPathCharDevice") + } + if dev.Mode()&os.ModeCharDevice != os.ModeCharDevice { + return nil, errors.Errorf("checking HostPathCharDevice: path %s is not a character device", hostPath.Path) + } + return &KubeVolume{ + Type: KubeVolumeTypeCharDevice, + Source: hostPath.Path, + }, nil case v1.HostPathDirectory: case v1.HostPathFile: case v1.HostPathUnset: diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index b77c00f50..dda2de6e4 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -128,7 +128,7 @@ func makeCommand(s *specgen.SpecGenerator, imageData *libimage.ImageData, rtc *c if initPath == "" { return nil, errors.Errorf("no path to init binary found but container requested an init") } - finalCommand = append([]string{"/dev/init", "--"}, finalCommand...) + finalCommand = append([]string{define.ContainerInitPath, "--"}, finalCommand...) } return finalCommand, nil @@ -377,7 +377,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt if err := unix.Stat(k, &statT); err != nil { return nil, errors.Wrapf(err, "failed to inspect '%s' in --blkio-weight-device", k) } - g.AddLinuxResourcesBlockIOWeightDevice((int64(unix.Major(uint64(statT.Rdev)))), (int64(unix.Minor(uint64(statT.Rdev)))), *v.Weight) + g.AddLinuxResourcesBlockIOWeightDevice((int64(unix.Major(uint64(statT.Rdev)))), (int64(unix.Minor(uint64(statT.Rdev)))), *v.Weight) // nolint: unconvert } BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g) diff --git a/pkg/specgen/generate/pause_image.go b/pkg/specgen/generate/pause_image.go new file mode 100644 index 000000000..ddf35f230 --- /dev/null +++ b/pkg/specgen/generate/pause_image.go @@ -0,0 +1,95 @@ +package generate + +import ( + "context" + "fmt" + "io/ioutil" + "os" + + buildahDefine "github.com/containers/buildah/define" + "github.com/containers/common/pkg/config" + "github.com/containers/podman/v4/libpod" + "github.com/containers/podman/v4/libpod/define" +) + +// PullOrBuildInfraImage pulls down the specified image or the one set in +// containers.conf. If none is set, it builds a local pause image. +func PullOrBuildInfraImage(rt *libpod.Runtime, imageName string) (string, error) { + rtConfig, err := rt.GetConfigNoCopy() + if err != nil { + return "", err + } + + if imageName == "" { + imageName = rtConfig.Engine.InfraImage + } + + if imageName != "" { + _, err := rt.LibimageRuntime().Pull(context.Background(), imageName, config.PullPolicyMissing, nil) + if err != nil { + return "", err + } + return imageName, nil + } + + name, err := buildPauseImage(rt, rtConfig) + if err != nil { + return "", fmt.Errorf("building local pause image: %w", err) + } + return name, nil +} + +func buildPauseImage(rt *libpod.Runtime, rtConfig *config.Config) (string, error) { + version, err := define.GetVersion() + if err != nil { + return "", err + } + imageName := fmt.Sprintf("localhost/podman-pause:%s-%d", version.Version, version.Built) + + // First check if the image has already been built. + if _, _, err := rt.LibimageRuntime().LookupImage(imageName, nil); err == nil { + return imageName, nil + } + + // Also look into the path as some distributions install catatonit in + // /usr/bin. + catatonitPath, err := rtConfig.FindHelperBinary("catatonit", true) + if err != nil { + return "", fmt.Errorf("finding pause binary: %w", err) + } + + buildContent := fmt.Sprintf(`FROM scratch +COPY %s /catatonit +ENTRYPOINT ["/catatonit", "-P"]`, catatonitPath) + + tmpF, err := ioutil.TempFile("", "pause.containerfile") + if err != nil { + return "", err + } + if _, err := tmpF.WriteString(buildContent); err != nil { + return "", err + } + if err := tmpF.Close(); err != nil { + return "", err + } + defer os.Remove(tmpF.Name()) + + buildOptions := buildahDefine.BuildOptions{ + CommonBuildOpts: &buildahDefine.CommonBuildOptions{}, + Output: imageName, + Quiet: true, + IgnoreFile: "/dev/null", // makes sure to not read a local .ignorefile (see #13529) + IIDFile: "/dev/null", // prevents Buildah from writing the ID on stdout + IDMappingOptions: &buildahDefine.IDMappingOptions{ + // Use the host UID/GID mappings for the build to avoid issues when + // running with a custom mapping (BZ #2083997). + HostUIDMapping: true, + HostGIDMapping: true, + }, + } + if _, _, err := rt.Build(context.Background(), buildOptions, tmpF.Name()); err != nil { + return "", err + } + + return imageName, nil +} diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go index fce32d688..5b7bb2b57 100644 --- a/pkg/specgen/generate/pod_create.go +++ b/pkg/specgen/generate/pod_create.go @@ -2,13 +2,8 @@ package generate import ( "context" - "fmt" - "io/ioutil" "net" - "os" - buildahDefine "github.com/containers/buildah/define" - "github.com/containers/common/pkg/config" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/domain/entities" @@ -17,98 +12,18 @@ import ( "github.com/sirupsen/logrus" ) -func buildPauseImage(rt *libpod.Runtime, rtConfig *config.Config) (string, error) { - version, err := define.GetVersion() - if err != nil { - return "", err - } - imageName := fmt.Sprintf("localhost/podman-pause:%s-%d", version.Version, version.Built) - - // First check if the image has already been built. - if _, _, err := rt.LibimageRuntime().LookupImage(imageName, nil); err == nil { - return imageName, nil - } - - // Also look into the path as some distributions install catatonit in - // /usr/bin. - catatonitPath, err := rtConfig.FindHelperBinary("catatonit", true) - if err != nil { - return "", fmt.Errorf("finding pause binary: %w", err) - } - - buildContent := fmt.Sprintf(`FROM scratch -COPY %s /catatonit -ENTRYPOINT ["/catatonit", "-P"]`, catatonitPath) - - tmpF, err := ioutil.TempFile("", "pause.containerfile") - if err != nil { - return "", err - } - if _, err := tmpF.WriteString(buildContent); err != nil { - return "", err - } - if err := tmpF.Close(); err != nil { - return "", err - } - defer os.Remove(tmpF.Name()) - - buildOptions := buildahDefine.BuildOptions{ - CommonBuildOpts: &buildahDefine.CommonBuildOptions{}, - Output: imageName, - Quiet: true, - IgnoreFile: "/dev/null", // makes sure to not read a local .ignorefile (see #13529) - IIDFile: "/dev/null", // prevents Buildah from writing the ID on stdout - } - if _, _, err := rt.Build(context.Background(), buildOptions, tmpF.Name()); err != nil { - return "", err - } - - return imageName, nil -} - -func pullOrBuildInfraImage(p *entities.PodSpec, rt *libpod.Runtime) error { - if p.PodSpecGen.NoInfra { - return nil - } - - rtConfig, err := rt.GetConfigNoCopy() - if err != nil { - return err - } - - // NOTE: we need pull down the infra image if it was explicitly set by - // the user (or containers.conf) to the non-default one. - imageName := p.PodSpecGen.InfraImage - if imageName == "" { - imageName = rtConfig.Engine.InfraImage - } - - if imageName != "" { - _, err := rt.LibimageRuntime().Pull(context.Background(), imageName, config.PullPolicyMissing, nil) - if err != nil { - return err - } - } else { - name, err := buildPauseImage(rt, rtConfig) - if err != nil { - return fmt.Errorf("building local pause image: %w", err) - } - imageName = name - } - - p.PodSpecGen.InfraImage = imageName - p.PodSpecGen.InfraContainerSpec.RawImageName = imageName - - return nil -} - func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) { if err := p.PodSpecGen.Validate(); err != nil { return nil, err } - if err := pullOrBuildInfraImage(p, rt); err != nil { - return nil, err + if !p.PodSpecGen.NoInfra { + imageName, err := PullOrBuildInfraImage(rt, p.PodSpecGen.InfraImage) + if err != nil { + return nil, err + } + p.PodSpecGen.InfraImage = imageName + p.PodSpecGen.InfraContainerSpec.RawImageName = imageName } if !p.PodSpecGen.NoInfra && p.PodSpecGen.InfraContainerSpec != nil { @@ -180,6 +95,11 @@ func createPodOptions(p *specgen.PodSpecGenerator) ([]libpod.PodCreateOption, er options = append(options, libpod.WithPodUser()) } } + + if len(p.ServiceContainerID) > 0 { + options = append(options, libpod.WithServiceContainer(p.ServiceContainerID)) + } + if len(p.CgroupParent) > 0 { options = append(options, libpod.WithPodCgroupParent(p.CgroupParent)) } diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go index f30fc4671..0a4d03780 100644 --- a/pkg/specgen/generate/storage.go +++ b/pkg/specgen/generate/storage.go @@ -20,9 +20,7 @@ import ( "github.com/sirupsen/logrus" ) -var ( - errDuplicateDest = errors.Errorf("duplicate mount destination") -) +var errDuplicateDest = errors.Errorf("duplicate mount destination") // Produce final mounts and named volumes for a container func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *libimage.Image) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, error) { @@ -359,7 +357,7 @@ func getVolumesFrom(volumesFrom []string, runtime *libpod.Runtime) (map[string]s // This does *NOT* modify the container command - that must be done elsewhere. func addContainerInitBinary(s *specgen.SpecGenerator, path string) (spec.Mount, error) { mount := spec.Mount{ - Destination: "/dev/init", + Destination: define.ContainerInitPath, Type: define.TypeBind, Source: path, Options: []string{define.TypeBind, "ro"}, diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go index 1bb64448f..603506241 100644 --- a/pkg/specgen/podspecgen.go +++ b/pkg/specgen/podspecgen.go @@ -204,6 +204,9 @@ type PodSpecGenerator struct { PodStorageConfig PodSecurityConfig InfraContainerSpec *SpecGenerator `json:"-"` + + // The ID of the pod's service container. + ServiceContainerID string `json:"serviceContainerID,omitempty"` } type PodResourceConfig struct { diff --git a/pkg/util/utils_windows.go b/pkg/util/utils_windows.go index 2732124f2..b91680f7a 100644 --- a/pkg/util/utils_windows.go +++ b/pkg/util/utils_windows.go @@ -4,6 +4,9 @@ package util import ( + "path/filepath" + + "github.com/containers/storage/pkg/homedir" "github.com/pkg/errors" ) @@ -34,7 +37,12 @@ func GetRootlessPauseProcessPidPathGivenDir(unused string) (string, error) { // GetRuntimeDir returns the runtime directory func GetRuntimeDir() (string, error) { - return "", errors.New("this function is not implemented for windows") + data, err := homedir.GetDataHome() + if err != nil { + return "", err + } + runtimeDir := filepath.Join(data, "containers", "podman") + return runtimeDir, nil } // GetRootlessConfigHomeDir returns the config home directory when running as non root diff --git a/podman.spec.rpkg b/podman.spec.rpkg index 937253918..c9127c2d9 100644 --- a/podman.spec.rpkg +++ b/podman.spec.rpkg @@ -13,17 +13,9 @@ %endif %if ! 0%{?gobuild:1} -%define gobuild(o:) GO111MODULE=off go build -buildmode pie -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '-Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld '" -a -v -x %{?**}; +%define gobuild(o:) go build -buildmode pie -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '-Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld '" -a -v -x %{?**}; %endif -%global provider github -%global provider_tld com -%global project containers -%global repo %{name} -# https://github.com/containers/%%{name} -%global import_path %{provider}.%{provider_tld}/%{project}/%{repo} -%global git0 https://%{import_path} - # git_dir_name returns repository name derived from remote Git repository URL Name: {{{ git_dir_name }}} @@ -156,8 +148,7 @@ connections as well. # This will invoke `make` command in the directory with the extracted sources. %build %set_build_flags -export GO111MODULE=off -export GOPATH=$(pwd)/_build:$(pwd) +%global gomodulesmode GO111MODULE=on export CGO_CFLAGS=$CFLAGS # These extra flags present in $CFLAGS have been skipped for now as they break the build CGO_CFLAGS=$(echo $CGO_CFLAGS | sed 's/-flto=auto//g') @@ -168,33 +159,26 @@ CGO_CFLAGS=$(echo $CGO_CFLAGS | sed 's/-specs=\/usr\/lib\/rpm\/redhat\/redhat-an export CGO_CFLAGS+=" -m64 -mtune=generic -fcf-protection=full" %endif -mkdir _build -pushd _build -mkdir -p src/%{provider}.%{provider_tld}/%{project} -ln -s ../../../../ src/%{import_path} -popd -ln -s vendor src - %if 0%{?rhel} rm -rf vendor/github.com/containers/storage/drivers/register/register_btrfs.go %endif # build date. FIXME: Makefile uses '/v2/libpod', that doesn't work here? -LDFLAGS="-X %{import_path}/libpod/define.buildInfo=$(date +%s)" +LDFLAGS="-X ./libpod/define.buildInfo=$(date +%s)" # build rootlessport first -%gobuild -o bin/rootlessport %{import_path}/cmd/rootlessport +%gobuild -o bin/rootlessport ./cmd/rootlessport # set base buildtags common to both %%{name} and %%{name}-remote export BASEBUILDTAGS="seccomp exclude_graphdriver_devicemapper $(hack/selinux_tag.sh) $(hack/systemd_tag.sh) $(hack/libsubid_tag.sh)" # build %%{name} export BUILDTAGS="$BASEBUILDTAGS $(hack/btrfs_installed_tag.sh) $(hack/btrfs_tag.sh)" -%gobuild -o bin/%{name} %{import_path}/cmd/%{name} +%gobuild -o bin/%{name} ./cmd/%{name} # build %%{name}-remote export BUILDTAGS="$BASEBUILDTAGS exclude_graphdriver_btrfs btrfs_noversion remote" -%gobuild -o bin/%{name}-remote %{import_path}/cmd/%{name} +%gobuild -o bin/%{name}-remote ./cmd/%{name} make docs docker-docs @@ -242,11 +226,13 @@ done %{_unitdir}/%{name}.service %{_unitdir}/%{name}.socket %{_unitdir}/%{name}-restart.service +%{_unitdir}/%{name}-play-kube@.service %{_userunitdir}/%{name}-auto-update.service %{_userunitdir}/%{name}-auto-update.timer %{_userunitdir}/%{name}.service %{_userunitdir}/%{name}.socket %{_userunitdir}/%{name}-restart.service +%{_userunitdir}/%{name}-play-kube@.service %{_tmpfilesdir}/%{name}.conf %if 0%{?fedora} >= 36 %{_modulesloaddir}/%{name}-iptables.conf diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at index 9526183e3..fd04e3f1b 100644 --- a/test/apiv2/10-images.at +++ b/test/apiv2/10-images.at @@ -156,6 +156,17 @@ t GET images/json?filters='{"reference":["test1"]}' 200 length=1 t DELETE libpod/images/test1:latest 200 +# to be used in prune until filter tests +podman image build -t docker.io/library/test1:latest -<<EOF +from alpine +RUN >file4 +EOF +podman create --name test1 test1 echo hi + +t DELETE images/test1:latest 409 +podman rm test1 +t DELETE images/test1:latest 200 + t GET "images/get?names=alpine" 200 '[POSIX tar archive]' podman pull busybox @@ -190,6 +201,10 @@ t POST "libpod/build?dockerfile=containerfile" $CONTAINERFILE_TAR application/js t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 200 \ .stream~"STEP 1/1: FROM $IMAGE" +# Libpod: allow building from url: https://github.com/alpinelinux/docker-alpine.git and must ignore any provided tar +t POST "libpod/build?remote=https%3A%2F%2Fgithub.com%2Falpinelinux%2Fdocker-alpine.git" $CONTAINERFILE_TAR 200 \ + .stream~"STEP 1/5: FROM alpine:3.14" + # Build api response header must contain Content-type: application/json t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 200 response_headers=$(cat "$WORKDIR/curl.headers.out") diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at index 7a38dfea0..4d32a1031 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -477,8 +477,7 @@ for endpoint in containers/create libpod/containers/create; do t POST libpod/containers/$cid/init 204 - t GET libpod/containers/$cid/json 200 \ - .HostsPath="" + t GET libpod/containers/$cid/json 200 t DELETE containers/$cid 204 done diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go index b5cec5fff..dcdd17143 100644 --- a/test/e2e/build_test.go +++ b/test/e2e/build_test.go @@ -786,17 +786,18 @@ RUN ls /dev/test1`, ALPINE) It("podman build use absolute path even if given relative", func() { containerFile := fmt.Sprintf(`FROM %s`, ALPINE) - err = os.Mkdir("relative", 0755) + relativeDir := filepath.Join(podmanTest.TempDir, "relativeDir") + containerFilePath := filepath.Join(relativeDir, "Containerfile") + buildRoot := filepath.Join(relativeDir, "build-root") + + err = os.Mkdir(relativeDir, 0755) Expect(err).To(BeNil()) - containerFilePath := filepath.Join("relative", "Containerfile") - err = os.Mkdir("relative/build-root", 0755) + err = os.Mkdir(buildRoot, 0755) Expect(err).To(BeNil()) err = ioutil.WriteFile(containerFilePath, []byte(containerFile), 0755) Expect(err).To(BeNil()) - build := podmanTest.Podman([]string{"build", "-f", "./relative/Containerfile", "./relative/build-root"}) + build := podmanTest.Podman([]string{"build", "-f", containerFilePath, buildRoot}) build.WaitWithDefaultTimeout() Expect(build).To(Exit(0)) - err = os.RemoveAll("relative") - Expect(err).To(BeNil()) }) }) diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go index b48e1ed62..819efa628 100644 --- a/test/e2e/containers_conf_test.go +++ b/test/e2e/containers_conf_test.go @@ -425,6 +425,7 @@ var _ = Describe("Verify podman containers.conf usage", func() { Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(Equal("/var/tmp")) + storagePath := filepath.Join(podmanTest.TempDir, "storage") configPath := filepath.Join(podmanTest.TempDir, "containers.conf") os.Setenv("CONTAINERS_CONF", configPath) @@ -441,7 +442,7 @@ var _ = Describe("Verify podman containers.conf usage", func() { Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(Equal("/foobar")) - containersConf = []byte("[engine]\nimage_copy_tmp_dir=\"storage\"") + containersConf = []byte(fmt.Sprintf("[engine]\nimage_copy_tmp_dir=%q", storagePath)) err = ioutil.WriteFile(configPath, containersConf, os.ModePerm) Expect(err).ToNot(HaveOccurred()) if IsRemote() { @@ -451,19 +452,18 @@ var _ = Describe("Verify podman containers.conf usage", func() { session = podmanTest.Podman([]string{"info", "--format", "{{.Store.ImageCopyTmpDir}}"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - Expect(session.Out.Contents()).To(ContainSubstring("containers/storage/tmp")) + Expect(session.Out.Contents()).To(ContainSubstring(storagePath)) containersConf = []byte("[engine]\nimage_copy_tmp_dir=\"storage1\"") err = ioutil.WriteFile(configPath, containersConf, os.ModePerm) Expect(err).ToNot(HaveOccurred()) - if IsRemote() { - podmanTest.RestartRemoteService() - } - session = podmanTest.Podman([]string{"info", "--format", "{{.Store.ImageCopyTmpDir}}"}) - session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) - Expect(session.Err.Contents()).To(ContainSubstring("invalid image_copy_tmp_dir")) + if !IsRemote() { + session = podmanTest.Podman([]string{"info", "--format", "{{.Store.ImageCopyTmpDir}}"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(125)) + Expect(session.Err.Contents()).To(ContainSubstring("invalid image_copy_tmp_dir value \"storage1\" (relative paths are not accepted)")) + } }) // FIXME not sure why this is here diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go index bce8b78c6..3ae130c6d 100644 --- a/test/e2e/login_logout_test.go +++ b/test/e2e/login_logout_test.go @@ -142,7 +142,7 @@ var _ = Describe("Podman login and logout", func() { defer registriesConf.Close() defer os.Remove(registriesConf.Name()) - err = ioutil.WriteFile(registriesConf.Name(), []byte(registriesConfWithSearch), os.ModePerm) + err = ioutil.WriteFile(registriesConf.Name(), registriesConfWithSearch, os.ModePerm) Expect(err).To(BeNil()) // Environment is per-process, so this looks very unsafe; actually it seems fine because tests are not diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index c67a4baed..715455521 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -475,7 +475,7 @@ var _ = Describe("Podman network", func() { defer podmanTest.removeNetwork(netName) Expect(session).Should(Exit(0)) - interval := time.Duration(250 * time.Millisecond) + interval := 250 * time.Millisecond for i := 0; i < 6; i++ { n := podmanTest.Podman([]string{"network", "exists", netName}) n.WaitWithDefaultTimeout() @@ -490,7 +490,7 @@ var _ = Describe("Podman network", func() { top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx}) top.WaitWithDefaultTimeout() Expect(top).Should(Exit(0)) - interval = time.Duration(250 * time.Millisecond) + interval = 250 * time.Millisecond // Wait for the nginx service to be running for i := 0; i < 6; i++ { // Test curl against the container's name @@ -526,7 +526,7 @@ var _ = Describe("Podman network", func() { defer podmanTest.removeNetwork(netName) Expect(session).Should(Exit(0)) - interval := time.Duration(250 * time.Millisecond) + interval := 250 * time.Millisecond for i := 0; i < 6; i++ { n := podmanTest.Podman([]string{"network", "exists", netName}) n.WaitWithDefaultTimeout() @@ -541,7 +541,7 @@ var _ = Describe("Podman network", func() { top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx}) top.WaitWithDefaultTimeout() Expect(top).Should(Exit(0)) - interval = time.Duration(250 * time.Millisecond) + interval = 250 * time.Millisecond // Wait for the nginx service to be running for i := 0; i < 6; i++ { // Test curl against the container's name diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 216c3357c..31044f68b 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -21,6 +21,7 @@ import ( "github.com/containers/podman/v4/pkg/util" . "github.com/containers/podman/v4/test/utils" "github.com/containers/storage/pkg/stringid" + "github.com/google/uuid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/format" @@ -3685,4 +3686,150 @@ ENV OPENJ9_JAVA_OPTIONS=%q Expect(usernsInCtr).Should(Exit(0)) Expect(string(usernsInCtr.Out.Contents())).To(Not(Equal(string(initialUsernsConfig)))) }) + + // Check the block devices are exposed inside container + It("ddpodman play kube expose block device inside container", func() { + SkipIfRootless("It needs root access to create devices") + + // randomize the folder name to avoid error when running tests with multiple nodes + uuid, err := uuid.NewUUID() + Expect(err).To(BeNil()) + devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6]) + Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil()) + defer os.RemoveAll(devFolder) + + devicePath := fmt.Sprintf("%s/blockdevice", devFolder) + mknod := SystemExec("mknod", []string{devicePath, "b", "7", "0"}) + mknod.WaitWithDefaultTimeout() + Expect(mknod).Should(Exit(0)) + + blockVolume := getHostPathVolume("BlockDevice", devicePath) + + pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + // Container should be in running state + inspect := podmanTest.Podman([]string{"inspect", "--format", "{{.State.Status}}", "testPod-" + defaultCtrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring("running")) + + // Container should have a block device /dev/loop1 + inspect = podmanTest.Podman([]string{"inspect", "--format", "{{.HostConfig.Devices}}", "testPod-" + defaultCtrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(devicePath)) + }) + + // Check the char devices are exposed inside container + It("ddpodman play kube expose character device inside container", func() { + SkipIfRootless("It needs root access to create devices") + + // randomize the folder name to avoid error when running tests with multiple nodes + uuid, err := uuid.NewUUID() + Expect(err).To(BeNil()) + devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6]) + Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil()) + defer os.RemoveAll(devFolder) + + devicePath := fmt.Sprintf("%s/chardevice", devFolder) + mknod := SystemExec("mknod", []string{devicePath, "c", "3", "1"}) + mknod.WaitWithDefaultTimeout() + Expect(mknod).Should(Exit(0)) + + charVolume := getHostPathVolume("CharDevice", devicePath) + + pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + // Container should be in running state + inspect := podmanTest.Podman([]string{"inspect", "--format", "{{.State.Status}}", "testPod-" + defaultCtrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring("running")) + + // Container should have a block device /dev/loop1 + inspect = podmanTest.Podman([]string{"inspect", "--format", "{{.HostConfig.Devices}}", "testPod-" + defaultCtrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(devicePath)) + }) + + It("podman play kube reports error when the device does not exists", func() { + SkipIfRootless("It needs root access to create devices") + + devicePath := "/dev/foodevdir/baddevice" + + blockVolume := getHostPathVolume("BlockDevice", devicePath) + + pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(125)) + }) + + It("ddpodman play kube reports error when we try to expose char device as block device", func() { + SkipIfRootless("It needs root access to create devices") + + // randomize the folder name to avoid error when running tests with multiple nodes + uuid, err := uuid.NewUUID() + Expect(err).To(BeNil()) + devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6]) + Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil()) + defer os.RemoveAll(devFolder) + + devicePath := fmt.Sprintf("%s/chardevice", devFolder) + mknod := SystemExec("mknod", []string{devicePath, "c", "3", "1"}) + mknod.WaitWithDefaultTimeout() + Expect(mknod).Should(Exit(0)) + + charVolume := getHostPathVolume("BlockDevice", devicePath) + + pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(125)) + }) + + It("ddpodman play kube reports error when we try to expose block device as char device", func() { + SkipIfRootless("It needs root access to create devices") + + // randomize the folder name to avoid error when running tests with multiple nodes + uuid, err := uuid.NewUUID() + Expect(err).To(BeNil()) + devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6]) + Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil()) + + devicePath := fmt.Sprintf("%s/blockdevice", devFolder) + mknod := SystemExec("mknod", []string{devicePath, "b", "7", "0"}) + mknod.WaitWithDefaultTimeout() + Expect(mknod).Should(Exit(0)) + + charVolume := getHostPathVolume("CharDevice", devicePath) + + pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(125)) + }) + }) diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index c9990b70f..3b32b4b82 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -731,7 +731,7 @@ EXPOSE 2004-2005/tcp`, ALPINE) linkAttr.Name = name m, err := net.ParseMAC(mac) Expect(err).To(BeNil()) - linkAttr.HardwareAddr = net.HardwareAddr(m) + linkAttr.HardwareAddr = m eth := &netlink.Dummy{LinkAttrs: linkAttr} err = netlink.LinkAdd(eth) Expect(err).To(BeNil()) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 182ae1888..828e92170 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/containers/common/pkg/cgroups" + "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/rootless" . "github.com/containers/podman/v4/test/utils" "github.com/containers/storage/pkg/stringid" @@ -286,19 +287,20 @@ var _ = Describe("Podman run", func() { result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) conData := result.InspectContainerToJSON() - Expect(conData[0]).To(HaveField("Path", "/dev/init")) + Expect(conData[0]).To(HaveField("Path", define.ContainerInitPath)) Expect(conData[0].Config.Annotations).To(HaveKeyWithValue("io.podman.annotations.init", "TRUE")) }) It("podman run a container with --init and --init-path", func() { - session := podmanTest.Podman([]string{"run", "--name", "test", "--init", "--init-path", "/usr/libexec/podman/catatonit", ALPINE, "ls"}) + // Also bind-mount /dev (#14251). + session := podmanTest.Podman([]string{"run", "-v", "/dev:/dev", "--name", "test", "--init", "--init-path", "/usr/libexec/podman/catatonit", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) result := podmanTest.Podman([]string{"inspect", "test"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) conData := result.InspectContainerToJSON() - Expect(conData[0]).To(HaveField("Path", "/dev/init")) + Expect(conData[0]).To(HaveField("Path", define.ContainerInitPath)) Expect(conData[0].Config.Annotations).To(HaveKeyWithValue("io.podman.annotations.init", "TRUE")) }) diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go index 536eefda7..897e49ef7 100644 --- a/test/e2e/save_test.go +++ b/test/e2e/save_test.go @@ -164,12 +164,13 @@ var _ = Describe("Podman save", func() { err = cmd.Run() Expect(err).To(BeNil()) - cmd = exec.Command("cp", "/etc/containers/registries.d/default.yaml", "default.yaml") + defaultYaml := filepath.Join(podmanTest.TempDir, "default.yaml") + cmd = exec.Command("cp", "/etc/containers/registries.d/default.yaml", defaultYaml) if err = cmd.Run(); err != nil { Skip("no signature store to verify") } defer func() { - cmd = exec.Command("cp", "default.yaml", "/etc/containers/registries.d/default.yaml") + cmd = exec.Command("cp", defaultYaml, "/etc/containers/registries.d/default.yaml") err := cmd.Run() Expect(err).ToNot(HaveOccurred()) }() diff --git a/test/e2e/system_df_test.go b/test/e2e/system_df_test.go index ba4a40ab4..5a23fc0bb 100644 --- a/test/e2e/system_df_test.go +++ b/test/e2e/system_df_test.go @@ -66,7 +66,7 @@ var _ = Describe("podman system df", func() { images := strings.Fields(session.OutputToStringArray()[1]) containers := strings.Fields(session.OutputToStringArray()[2]) volumes := strings.Fields(session.OutputToStringArray()[3]) - Expect(images[1]).To(Equal(string(totImages)), "total images expected") + Expect(images[1]).To(Equal(totImages), "total images expected") Expect(containers[1]).To(Equal("2"), "total containers expected") Expect(volumes[2]).To(Equal("2"), "total volumes expected") Expect(volumes[6]).To(Equal("(50%)"), "percentage usage expected") diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go index 09e5da8a0..0bf5acbf1 100644 --- a/test/e2e/volume_create_test.go +++ b/test/e2e/volume_create_test.go @@ -3,6 +3,7 @@ package integration import ( "fmt" "os" + "path/filepath" . "github.com/containers/podman/v4/test/utils" . "github.com/onsi/ginkgo" @@ -90,7 +91,8 @@ var _ = Describe("Podman volume create", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - session = podmanTest.Podman([]string{"volume", "export", volName, "--output=hello.tar"}) + helloTar := filepath.Join(podmanTest.TempDir, "hello.tar") + session = podmanTest.Podman([]string{"volume", "export", volName, "--output", helloTar}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -98,7 +100,7 @@ var _ = Describe("Podman volume create", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - session = podmanTest.Podman([]string{"volume", "import", "my_vol2", "hello.tar"}) + session = podmanTest.Podman([]string{"volume", "import", "my_vol2", helloTar}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(Equal(""), "output of volume import") diff --git a/test/system/170-run-userns.bats b/test/system/170-run-userns.bats index d754306b2..b80351902 100644 --- a/test/system/170-run-userns.bats +++ b/test/system/170-run-userns.bats @@ -36,6 +36,19 @@ function _require_crun() { is "$output" ".*457" "Check group leaked into container" } +@test "rootful pod with custom ID mapping" { + skip_if_rootless "does not work rootless - rootful feature" + skip_if_remote "remote --uidmap is broken (see #14233)" + random_pod_name=$(random_string 30) + run_podman pod create --uidmap 0:200000:5000 --name=$random_pod_name + run_podman pod start $random_pod_name + + # Remove the pod and the pause image + run_podman pod rm $random_pod_name + run_podman version --format "{{.Server.Version}}-{{.Server.Built}}" + run_podman rmi -f localhost/podman-pause:$output +} + @test "podman --remote --group-add keep-groups " { if is_remote; then run_podman 125 run --rm --group-add keep-groups $IMAGE id diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index 39982848f..4250f2680 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -408,19 +408,6 @@ EOF run_podman pod rm test } -# Wait for the pod (1st arg) to transition into the state (2nd arg) -function _ensure_pod_state() { - for i in {0..5}; do - run_podman pod inspect $1 --format "{{.State}}" - if [[ $output == "$2" ]]; then - break - fi - sleep 0.5 - done - - is "$output" "$2" "unexpected pod state" -} - @test "pod exit policies" { # Test setting exit policies run_podman pod create diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats index d0da654ad..567fa89c1 100644 --- a/test/system/250-systemd.bats +++ b/test/system/250-systemd.bats @@ -292,4 +292,80 @@ LISTEN_FDNAMES=listen_fdnames" | sort) run_podman network rm -f $netname } +@test "podman-play-kube@.service template" { + skip_if_remote "systemd units do not work with remote clients" + + # If running from a podman source directory, build and use the source + # version of the play-kube-@ unit file + unit_name="podman-play-kube@.service" + unit_file="contrib/systemd/system/${unit_name}" + if [[ -e ${unit_file}.in ]]; then + echo "# [Building & using $unit_name from source]" >&3 + BINDIR=$(dirname $PODMAN) make $unit_file + cp $unit_file $UNIT_DIR/$unit_name + fi + + # Create the YAMl file + yaml_source="$PODMAN_TMPDIR/test.yaml" + cat >$yaml_source <<EOF +apiVersion: v1 +kind: Pod +metadata: + labels: + app: test + name: test_pod +spec: + containers: + - command: + - top + image: $IMAGE + name: test + resources: {} +EOF + + # Dispatch the YAML file + service_name="podman-play-kube@$(systemd-escape $yaml_source).service" + systemctl start $service_name + systemctl is-active $service_name + + # The name of the service container is predictable: the first 12 characters + # of the hash of the YAML file followed by the "-service" suffix + yaml_sha=$(sha256sum $yaml_source) + service_container="${yaml_sha:0:12}-service" + + # Make sure that the service container exists and runs. + run_podman container inspect $service_container --format "{{.State.Running}}" + is "$output" "true" + + # Check for an error when trying to remove the service container + run_podman 125 container rm $service_container + is "$output" "Error: container .* is the service container of pod(s) .* and cannot be removed without removing the pod(s)" + + # Kill the pod and make sure the service is not running. + # The restart policy is set to "never" since there is no + # design yet for propagating exit codes up to the service + # container. + run_podman pod kill test_pod + for i in {0..5}; do + run systemctl is-failed $service_name + if [[ $output == "failed" ]]; then + break + fi + sleep 0.5 + done + is "$output" "failed" "systemd service transitioned to 'failed' state" + + # Now stop and start the service again. + systemctl stop $service_name + systemctl start $service_name + systemctl is-active $service_name + run_podman container inspect $service_container --format "{{.State.Running}}" + is "$output" "true" + + # Clean up + systemctl stop $service_name + run_podman 1 container exists $service_container + run_podman 1 pod exists test_pod +} + # vim: filetype=sh diff --git a/test/system/255-auto-update.bats b/test/system/255-auto-update.bats index 6cdae2ada..6cee939fb 100644 --- a/test/system/255-auto-update.bats +++ b/test/system/255-auto-update.bats @@ -135,15 +135,27 @@ function _confirm_update() { # This test can fail in dev. environment because of SELinux. # quick fix: chcon -t container_runtime_exec_t ./bin/podman @test "podman auto-update - label io.containers.autoupdate=image" { + since=$(date --iso-8601=seconds) + run_podman auto-update + is "$output" "" + run_podman events --filter type=system --since $since --stream=false + is "$output" "" + generate_service alpine image _wait_service_ready container-$cname.service + since=$(date --iso-8601=seconds) run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}" is "$output" ".*container-$cname.service,quay.io/libpod/alpine:latest,pending,registry.*" "Image update is pending." + run_podman events --filter type=system --since $since --stream=false + is "$output" ".* system auto-update" + since=$(date --iso-8601=seconds) run_podman auto-update --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}" is "$output" "Trying to pull.*" "Image is updated." is "$output" ".*container-$cname.service,quay.io/libpod/alpine:latest,true,registry.*" "Image is updated." + run_podman events --filter type=system --since $since --stream=false + is "$output" ".* system auto-update" _confirm_update $cname $ori_image } diff --git a/test/system/260-sdnotify.bats b/test/system/260-sdnotify.bats index 88d84c86f..59456de24 100644 --- a/test/system/260-sdnotify.bats +++ b/test/system/260-sdnotify.bats @@ -172,4 +172,52 @@ READY=1" "sdnotify sent MAINPID and READY" _stop_socat } +@test "sdnotify : play kube" { + # Create the YAMl file + yaml_source="$PODMAN_TMPDIR/test.yaml" + cat >$yaml_source <<EOF +apiVersion: v1 +kind: Pod +metadata: + labels: + app: test + name: test_pod +spec: + containers: + - command: + - top + image: $IMAGE + name: test + resources: {} +EOF + + # The name of the service container is predictable: the first 12 characters + # of the hash of the YAML file followed by the "-service" suffix + yaml_sha=$(sha256sum $yaml_source) + service_container="${yaml_sha:0:12}-service" + + + export NOTIFY_SOCKET=$PODMAN_TMPDIR/conmon.sock + _start_socat + + run_podman play kube --service-container=true $yaml_source + run_podman container inspect $service_container --format "{{.State.ConmonPid}}" + mainPID="$output" + # The 'echo's help us debug failed runs + run cat $_SOCAT_LOG + echo "socat log:" + echo "$output" + + is "$output" "MAINPID=$mainPID +READY=1" "sdnotify sent MAINPID and READY" + + _stop_socat + + # Clean up pod and pause image + run_podman play kube --down $PODMAN_TMPDIR/test.yaml + run_podman version --format "{{.Server.Version}}-{{.Server.Built}}" + podman rmi -f localhost/podman-pause:$output +} + + # vim: filetype=sh diff --git a/test/system/700-play.bats b/test/system/700-play.bats index 7988b26a4..6c2a8c8b1 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -100,6 +100,65 @@ RELABEL="system_u:object_r:container_file_t:s0" run_podman pod rm -t 0 -f test_pod } +@test "podman play --service-container" { + skip_if_remote "service containers only work locally" + + # Create the YAMl file + yaml_source="$PODMAN_TMPDIR/test.yaml" + cat >$yaml_source <<EOF +apiVersion: v1 +kind: Pod +metadata: + labels: + app: test + name: test_pod +spec: + containers: + - command: + - top + image: $IMAGE + name: test + resources: {} +EOF + run_podman play kube --service-container=true $yaml_source + + # The name of the service container is predictable: the first 12 characters + # of the hash of the YAML file followed by the "-service" suffix + yaml_sha=$(sha256sum $yaml_source) + service_container="${yaml_sha:0:12}-service" + + # Make sure that the service container exists and runs. + run_podman container inspect $service_container --format "{{.State.Running}}" + is "$output" "true" + + # Stop the *main* container and make sure that + # 1) The pod transitions to Exited + # 2) The service container is stopped + # #) The service container is marked as an service container + run_podman stop test_pod-test + _ensure_pod_state test_pod Exited + _ensure_container_running $service_container false + run_podman container inspect $service_container --format "{{.IsService}}" + is "$output" "true" + + # Restart the pod, make sure the service is running again + run_podman pod restart test_pod + run_podman container inspect $service_container --format "{{.State.Running}}" + is "$output" "true" + + # Check for an error when trying to remove the service container + run_podman 125 container rm $service_container + is "$output" "Error: container .* is the service container of pod(s) .* and cannot be removed without removing the pod(s)" + + # Kill the pod and make sure the service is not running + run_podman pod kill test_pod + _ensure_container_running $service_container false + + # Remove the pod and make sure the service is removed along with it + run_podman pod rm test_pod + run_podman 1 container exists $service_container +} + @test "podman play --network" { TESTDIR=$PODMAN_TMPDIR/testdir mkdir -p $TESTDIR diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 138d668f4..6868f2691 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -392,6 +392,32 @@ function pause_image() { echo "localhost/podman-pause:$output" } +# Wait for the pod (1st arg) to transition into the state (2nd arg) +function _ensure_pod_state() { + for i in {0..5}; do + run_podman pod inspect $1 --format "{{.State}}" + if [[ $output == "$2" ]]; then + break + fi + sleep 0.5 + done + + is "$output" "$2" "unexpected pod state" +} + +# Wait for the container's (1st arg) running state (2nd arg) +function _ensure_container_running() { + for i in {0..5}; do + run_podman container inspect $1 --format "{{.State.Running}}" + if [[ $output == "$2" ]]; then + break + fi + sleep 0.5 + done + + is "$output" "$2" "unexpected pod state" +} + ########################### # _add_label_if_missing # make sure skip messages include rootless/remote ########################### diff --git a/utils/utils.go b/utils/utils.go index d0e3dbb46..fd66ac2ed 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -192,7 +192,7 @@ func moveProcessPIDFileToScope(pidPath, slice, scope string) error { } func moveProcessToScope(pid int, slice, scope string) error { - err := RunUnderSystemdScope(int(pid), slice, scope) + err := RunUnderSystemdScope(pid, slice, scope) // If the PID is not valid anymore, do not return an error. if dbusErr, ok := err.(dbus.Error); ok { if dbusErr.Name == "org.freedesktop.DBus.Error.UnixProcessIdUnknown" { diff --git a/vendor/github.com/containers/common/libimage/image.go b/vendor/github.com/containers/common/libimage/image.go index 661ca159b..d7c4fcd51 100644 --- a/vendor/github.com/containers/common/libimage/image.go +++ b/vendor/github.com/containers/common/libimage/image.go @@ -608,7 +608,7 @@ func (i *Image) RepoTags() ([]string, error) { // NamedTaggedRepoTags returns the repotags associated with the image as a // slice of reference.NamedTagged. func (i *Image) NamedTaggedRepoTags() ([]reference.NamedTagged, error) { - var repoTags []reference.NamedTagged + repoTags := make([]reference.NamedTagged, 0, len(i.Names())) for _, name := range i.Names() { parsed, err := reference.Parse(name) if err != nil { diff --git a/vendor/github.com/containers/common/libimage/load.go b/vendor/github.com/containers/common/libimage/load.go index 4dfac7106..c2d066645 100644 --- a/vendor/github.com/containers/common/libimage/load.go +++ b/vendor/github.com/containers/common/libimage/load.go @@ -32,8 +32,8 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ( options = &LoadOptions{} } - var loadErrors []error - + // we have 4 functions, so a maximum of 4 errors + loadErrors := make([]error, 0, 4) for _, f := range []func() ([]string, string, error){ // OCI func() ([]string, string, error) { @@ -88,6 +88,8 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ( } // Give a decent error message if nothing above worked. + // we want the colon here for the multiline error + //nolint:revive 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) diff --git a/vendor/github.com/containers/common/libimage/normalize.go b/vendor/github.com/containers/common/libimage/normalize.go index 7ceb62830..b36bbf396 100644 --- a/vendor/github.com/containers/common/libimage/normalize.go +++ b/vendor/github.com/containers/common/libimage/normalize.go @@ -115,7 +115,7 @@ type NameTagPair struct { func ToNameTagPairs(repoTags []reference.Named) ([]NameTagPair, error) { none := "<none>" - var pairs []NameTagPair + pairs := make([]NameTagPair, 0, len(repoTags)) for i, named := range repoTags { pair := NameTagPair{ Name: named.Name(), diff --git a/vendor/github.com/containers/common/libimage/pull.go b/vendor/github.com/containers/common/libimage/pull.go index ff93b6ed8..4ce8add2f 100644 --- a/vendor/github.com/containers/common/libimage/pull.go +++ b/vendor/github.com/containers/common/libimage/pull.go @@ -413,11 +413,11 @@ func (r *Runtime) imagesIDsForManifest(manifestBytes []byte, sys *types.SystemCo } imageDigest = d } - var results []string images, err := r.store.ImagesByDigest(imageDigest) if err != nil { return nil, errors.Wrapf(err, "listing images by manifest digest") } + results := make([]string, 0, len(images)) for _, image := range images { results = append(results, image.ID) } diff --git a/vendor/github.com/containers/common/libimage/runtime.go b/vendor/github.com/containers/common/libimage/runtime.go index 974b50b50..472482410 100644 --- a/vendor/github.com/containers/common/libimage/runtime.go +++ b/vendor/github.com/containers/common/libimage/runtime.go @@ -6,6 +6,7 @@ import ( "os" "strings" + "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/pkg/shortnames" storageTransport "github.com/containers/image/v5/storage" @@ -22,13 +23,16 @@ import ( var json = jsoniter.ConfigCompatibleWithStandardLibrary // tmpdir returns a path to a temporary directory. -func tmpdir() string { - tmpdir := os.Getenv("TMPDIR") - if tmpdir == "" { - tmpdir = "/var/tmp" +func tmpdir() (string, error) { + var tmpdir string + defaultContainerConfig, err := config.Default() + if err == nil { + tmpdir, err = defaultContainerConfig.ImageCopyTmpDir() + if err == nil { + return tmpdir, nil + } } - - return tmpdir + return tmpdir, err } // RuntimeOptions allow for creating a customized Runtime. @@ -103,7 +107,11 @@ func RuntimeFromStore(store storage.Store, options *RuntimeOptions) (*Runtime, e systemContext = types.SystemContext{} } if systemContext.BigFilesTemporaryDir == "" { - systemContext.BigFilesTemporaryDir = tmpdir() + tmpdir, err := tmpdir() + if err != nil { + return nil, err + } + systemContext.BigFilesTemporaryDir = tmpdir } setRegistriesConfPath(&systemContext) @@ -224,16 +232,15 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image, } logrus.Debugf("Found image %q in local containers storage (%s)", name, storageRef.StringWithinTransport()) return r.storageToImage(img, storageRef), "", nil - } else { - // Docker compat: strip off the tag iff name is tagged and digested - // (e.g., fedora:latest@sha256...). In that case, the tag is stripped - // off and entirely ignored. The digest is the sole source of truth. - normalizedName, err := normalizeTaggedDigestedString(name) - if err != nil { - return nil, "", err - } - name = normalizedName } + // Docker compat: strip off the tag iff name is tagged and digested + // (e.g., fedora:latest@sha256...). In that case, the tag is stripped + // off and entirely ignored. The digest is the sole source of truth. + normalizedName, err := normalizeTaggedDigestedString(name) + if err != nil { + return nil, "", err + } + name = normalizedName byDigest := false originalName := name diff --git a/vendor/github.com/containers/common/libnetwork/cni/config.go b/vendor/github.com/containers/common/libnetwork/cni/config.go index c6967b600..f6954db05 100644 --- a/vendor/github.com/containers/common/libnetwork/cni/config.go +++ b/vendor/github.com/containers/common/libnetwork/cni/config.go @@ -96,7 +96,7 @@ func (n *cniNetwork) networkCreate(newNetwork *types.Network, defaultNet bool) ( newNetwork.ID = getNetworkIDFromName(newNetwork.Name) // when we do not have ipam we must disable dns - internalutil.IpamNoneDisableDns(newNetwork) + internalutil.IpamNoneDisableDNS(newNetwork) // FIXME: Should this be a hard error? if newNetwork.DNSEnabled && newNetwork.Internal && hasDNSNamePlugin(n.cniPluginDirs) { diff --git a/vendor/github.com/containers/common/libnetwork/cni/run.go b/vendor/github.com/containers/common/libnetwork/cni/run.go index c7fa86ed0..c5461d74c 100644 --- a/vendor/github.com/containers/common/libnetwork/cni/run.go +++ b/vendor/github.com/containers/common/libnetwork/cni/run.go @@ -106,7 +106,7 @@ func (n *cniNetwork) Setup(namespacePath string, options types.SetupOptions) (ma } // CNIResultToStatus convert the cni result to status block -// nolint:golint +// nolint:golint,revive func CNIResultToStatus(res cnitypes.Result) (types.StatusBlock, error) { result := types.StatusBlock{} cniResult, err := types040.GetResult(res) diff --git a/vendor/github.com/containers/common/libnetwork/internal/util/create.go b/vendor/github.com/containers/common/libnetwork/internal/util/create.go index c1a4bee75..d4d574065 100644 --- a/vendor/github.com/containers/common/libnetwork/internal/util/create.go +++ b/vendor/github.com/containers/common/libnetwork/internal/util/create.go @@ -41,7 +41,7 @@ func CommonNetworkCreate(n NetUtil, network *types.Network) error { return nil } -func IpamNoneDisableDns(network *types.Network) { +func IpamNoneDisableDNS(network *types.Network) { if network.IPAMOptions[types.Driver] == types.NoneIPAMDriver { logrus.Debugf("dns disabled for network %q because ipam driver is set to none", network.Name) network.DNSEnabled = false diff --git a/vendor/github.com/containers/common/libnetwork/netavark/config.go b/vendor/github.com/containers/common/libnetwork/netavark/config.go index 0bb0539b2..f2c72ab9e 100644 --- a/vendor/github.com/containers/common/libnetwork/netavark/config.go +++ b/vendor/github.com/containers/common/libnetwork/netavark/config.go @@ -121,7 +121,7 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo } // when we do not have ipam we must disable dns - internalutil.IpamNoneDisableDns(newNetwork) + internalutil.IpamNoneDisableDNS(newNetwork) // add gateway when not internal or dns enabled addGateway := !newNetwork.Internal || newNetwork.DNSEnabled diff --git a/vendor/github.com/containers/common/libnetwork/network/interface.go b/vendor/github.com/containers/common/libnetwork/network/interface.go index 893bdea2e..e70f096a4 100644 --- a/vendor/github.com/containers/common/libnetwork/network/interface.go +++ b/vendor/github.com/containers/common/libnetwork/network/interface.go @@ -46,6 +46,9 @@ const ( // 1. read ${graphroot}/defaultNetworkBackend // 2. find netavark binary (if not installed use CNI) // 3. check containers, images and CNI networks and if there are some we have an existing install and should continue to use CNI +// +// revive does not like the name because the package is already called network +//nolint:revive func NetworkBackend(store storage.Store, conf *config.Config, syslog bool) (types.NetworkBackend, types.ContainerNetwork, error) { backend := types.NetworkBackend(conf.Network.NetworkBackend) if backend == "" { 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 35f79a1ad..1fd269255 100644 --- a/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go +++ b/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go @@ -251,19 +251,17 @@ func CheckProfileAndLoadDefault(name string) (string, error) { if unshare.IsRootless() { if name != "" { return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name) - } else { - logrus.Debug("Skipping loading default AppArmor profile (rootless mode)") - return "", nil } + logrus.Debug("Skipping loading default AppArmor profile (rootless mode)") + return "", nil } // Check if AppArmor is disabled and error out if a profile is to be set. if !runcaa.IsEnabled() { if name == "" { return "", nil - } else { - return "", errors.Errorf("profile %q specified but AppArmor is disabled on the host", name) } + return "", errors.Errorf("profile %q specified but AppArmor is disabled on the host", name) } if name == "" { diff --git a/vendor/github.com/containers/common/pkg/auth/auth.go b/vendor/github.com/containers/common/pkg/auth/auth.go index 6765c9e5b..188e06c12 100644 --- a/vendor/github.com/containers/common/pkg/auth/auth.go +++ b/vendor/github.com/containers/common/pkg/auth/auth.go @@ -26,8 +26,8 @@ func GetDefaultAuthFile() string { if authfile := os.Getenv("REGISTRY_AUTH_FILE"); authfile != "" { return authfile } - if auth_env := os.Getenv("DOCKER_CONFIG"); auth_env != "" { - return filepath.Join(auth_env, "config.json") + if authEnv := os.Getenv("DOCKER_CONFIG"); authEnv != "" { + return filepath.Join(authEnv, "config.json") } return "" } @@ -313,7 +313,7 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri fmt.Printf("Not logged into %s with current tool. Existing credentials were established via docker login. Please use docker logout instead.\n", key) return nil } - return errors.Errorf("Not logged into %s\n", key) + return errors.Errorf("not logged into %s", key) default: return errors.Wrapf(err, "logging out of %q", key) } diff --git a/vendor/github.com/containers/common/pkg/capabilities/capabilities.go b/vendor/github.com/containers/common/pkg/capabilities/capabilities.go index 10c5dd7c4..b8e3fbcb5 100644 --- a/vendor/github.com/containers/common/pkg/capabilities/capabilities.go +++ b/vendor/github.com/containers/common/pkg/capabilities/capabilities.go @@ -104,8 +104,8 @@ func AllCapabilities() []string { // NormalizeCapabilities normalizes caps by adding a "CAP_" prefix (if not yet // present). func NormalizeCapabilities(caps []string) ([]string, error) { - normalized := make([]string, len(caps)) - for i, c := range caps { + normalized := make([]string, 0, len(caps)) + for _, c := range caps { c = strings.ToUpper(c) if c == All { normalized = append(normalized, c) @@ -117,7 +117,7 @@ func NormalizeCapabilities(caps []string) ([]string, error) { if !stringInSlice(c, capabilityList) { return nil, errors.Wrapf(ErrUnknownCapability, "%q", c) } - normalized[i] = c + normalized = append(normalized, c) } sort.Strings(normalized) return normalized, nil @@ -140,8 +140,6 @@ func ValidateCapabilities(caps []string) error { // "ALL" in capAdd adds returns known capabilities // "All" in capDrop returns only the capabilities specified in capAdd func MergeCapabilities(base, adds, drops []string) ([]string, error) { - var caps []string - // Normalize the base capabilities base, err := NormalizeCapabilities(base) if err != nil { @@ -189,6 +187,7 @@ func MergeCapabilities(base, adds, drops []string) ([]string, error) { } } + caps := make([]string, 0, len(base)+len(capAdd)) // Drop any capabilities in capDrop that are in base for _, cap := range base { if stringInSlice(cap, capDrop) { diff --git a/vendor/github.com/containers/common/pkg/cgroups/cgroups_supported.go b/vendor/github.com/containers/common/pkg/cgroups/cgroups_supported.go index edb28ad18..5c6c199e0 100644 --- a/vendor/github.com/containers/common/pkg/cgroups/cgroups_supported.go +++ b/vendor/github.com/containers/common/pkg/cgroups/cgroups_supported.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strconv" "strings" "sync" "syscall" @@ -96,6 +97,22 @@ func UserOwnsCurrentSystemdCgroup() (bool, error) { // It differs from os.RemoveAll as it doesn't attempt to unlink files. // On cgroupfs we are allowed only to rmdir empty directories. func rmDirRecursively(path string) error { + killProcesses := func(signal syscall.Signal) { + if signal == unix.SIGKILL { + if err := ioutil.WriteFile(filepath.Join(path, "cgroup.kill"), []byte("1"), 0600); err == nil { + return + } + } + // kill all the processes that are still part of the cgroup + if procs, err := ioutil.ReadFile(filepath.Join(path, "cgroup.procs")); err == nil { + for _, pidS := range strings.Split(string(procs), "\n") { + if pid, err := strconv.Atoi(pidS); err == nil { + _ = unix.Kill(pid, signal) + } + } + } + } + if err := os.Remove(path); err == nil || os.IsNotExist(err) { return nil } @@ -118,8 +135,16 @@ func rmDirRecursively(path string) error { return nil } if errors.Is(err, unix.EBUSY) { - // attempt up to 5 seconds if the cgroup is busy - if attempts < 500 { + // send a SIGTERM after 3 second + if attempts == 300 { + killProcesses(unix.SIGTERM) + } + // send SIGKILL after 8 seconds + if attempts == 800 { + killProcesses(unix.SIGKILL) + } + // give up after 10 seconds + if attempts < 1000 { time.Sleep(time.Millisecond * 10) attempts++ continue diff --git a/vendor/github.com/containers/common/pkg/completion/completion.go b/vendor/github.com/containers/common/pkg/completion/completion.go index c90bf540b..b5e6d6d30 100644 --- a/vendor/github.com/containers/common/pkg/completion/completion.go +++ b/vendor/github.com/containers/common/pkg/completion/completion.go @@ -51,7 +51,7 @@ func AutocompleteCapabilities(cmd *cobra.Command, args []string, toComplete stri offset = 4 } - var completions []string + completions := make([]string, 0, len(caps)) for _, cap := range caps { completions = append(completions, convertCase(cap)[offset:]) } diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go index a86eca88e..25572968f 100644 --- a/vendor/github.com/containers/common/pkg/config/config.go +++ b/vendor/github.com/containers/common/pkg/config/config.go @@ -24,10 +24,6 @@ const ( // _configPath is the path to the containers/containers.conf // inside a given config directory. _configPath = "containers/containers.conf" - // DefaultContainersConfig holds the default containers config path - DefaultContainersConfig = "/usr/share/" + _configPath - // OverrideContainersConfig holds the default config path overridden by the root user - OverrideContainersConfig = "/etc/" + _configPath // UserOverrideContainersConfig holds the containers config path overridden by the rootless user UserOverrideContainersConfig = ".config/" + _configPath ) @@ -553,6 +549,9 @@ type SecretConfig struct { } // ConfigMapConfig represents the "configmap" TOML config table +// +// revive does not like the name because the package is already called config +//nolint:revive type ConfigMapConfig struct { // Driver specifies the configmap driver to use. // Current valid value: @@ -800,7 +799,7 @@ func (c *Config) Validate() error { func (c *EngineConfig) findRuntime() string { // Search for crun first followed by runc, kata, runsc - for _, name := range []string{"crun", "runc", "kata", "runsc"} { + for _, name := range []string{"crun", "runc", "runj", "kata", "runsc"} { for _, v := range c.OCIRuntimes[name] { if _, err := os.Stat(v); err == nil { return name @@ -1215,14 +1214,14 @@ func (c *Config) ActiveDestination() (uri, identity string, err error) { // FindHelperBinary will search the given binary name in the configured directories. // If searchPATH is set to true it will also search in $PATH. func (c *Config) FindHelperBinary(name string, searchPATH bool) (string, error) { - dir_list := c.Engine.HelperBinariesDir + dirList := c.Engine.HelperBinariesDir // If set, search this directory first. This is used in testing. if dir, found := os.LookupEnv("CONTAINERS_HELPER_BINARY_DIR"); found { - dir_list = append([]string{dir}, dir_list...) + dirList = append([]string{dir}, dirList...) } - for _, path := range dir_list { + for _, path := range dirList { fullpath := filepath.Join(path, name) if fi, err := os.Stat(fullpath); err == nil && fi.Mode().IsRegular() { return fullpath, nil diff --git a/vendor/github.com/containers/common/pkg/config/config_darwin.go b/vendor/github.com/containers/common/pkg/config/config_darwin.go index 5abb51f30..0ab9e0294 100644 --- a/vendor/github.com/containers/common/pkg/config/config_darwin.go +++ b/vendor/github.com/containers/common/pkg/config/config_darwin.go @@ -4,6 +4,14 @@ import ( "os" ) +const ( + // OverrideContainersConfig holds the default config path overridden by the root user + OverrideContainersConfig = "/etc/" + _configPath + + // DefaultContainersConfig holds the default containers config path + DefaultContainersConfig = "/usr/share/" + _configPath +) + // podman remote clients on darwin cannot use unshare.isRootless() to determine the configuration file locations. func customConfigFile() (string, error) { if path, found := os.LookupEnv("CONTAINERS_CONF"); found { diff --git a/vendor/github.com/containers/common/pkg/config/config_freebsd.go b/vendor/github.com/containers/common/pkg/config/config_freebsd.go index 85404a48d..d69812356 100644 --- a/vendor/github.com/containers/common/pkg/config/config_freebsd.go +++ b/vendor/github.com/containers/common/pkg/config/config_freebsd.go @@ -4,6 +4,14 @@ import ( "os" ) +const ( + // OverrideContainersConfig holds the default config path overridden by the root user + OverrideContainersConfig = "/usr/local/etc/" + _configPath + + // DefaultContainersConfig holds the default containers config path + DefaultContainersConfig = "/usr/local/share/" + _configPath +) + // podman remote clients on freebsd cannot use unshare.isRootless() to determine the configuration file locations. func customConfigFile() (string, error) { if path, found := os.LookupEnv("CONTAINERS_CONF"); found { diff --git a/vendor/github.com/containers/common/pkg/config/config_linux.go b/vendor/github.com/containers/common/pkg/config/config_linux.go index da0ae871a..4f0889f29 100644 --- a/vendor/github.com/containers/common/pkg/config/config_linux.go +++ b/vendor/github.com/containers/common/pkg/config/config_linux.go @@ -7,6 +7,14 @@ import ( selinux "github.com/opencontainers/selinux/go-selinux" ) +const ( + // OverrideContainersConfig holds the default config path overridden by the root user + OverrideContainersConfig = "/etc/" + _configPath + + // DefaultContainersConfig holds the default containers config path + DefaultContainersConfig = "/usr/share/" + _configPath +) + func selinuxEnabled() bool { return selinux.GetEnabled() } diff --git a/vendor/github.com/containers/common/pkg/config/config_windows.go b/vendor/github.com/containers/common/pkg/config/config_windows.go index dbe7ba00d..6c9d58485 100644 --- a/vendor/github.com/containers/common/pkg/config/config_windows.go +++ b/vendor/github.com/containers/common/pkg/config/config_windows.go @@ -2,6 +2,14 @@ package config import "os" +const ( + // OverrideContainersConfig holds the default config path overridden by the root user + OverrideContainersConfig = "/etc/" + _configPath + + // DefaultContainersConfig holds the default containers config path + DefaultContainersConfig = "/usr/share/" + _configPath +) + // podman remote clients on windows cannot use unshare.isRootless() to determine the configuration file locations. func customConfigFile() (string, error) { if path, found := os.LookupEnv("CONTAINERS_CONF"); found { diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf-freebsd b/vendor/github.com/containers/common/pkg/config/containers.conf-freebsd new file mode 100644 index 000000000..50480fe73 --- /dev/null +++ b/vendor/github.com/containers/common/pkg/config/containers.conf-freebsd @@ -0,0 +1,636 @@ +# The containers configuration file specifies all of the available configuration +# command-line options/flags for container engine tools like Podman & Buildah, +# but in a TOML format that can be easily modified and versioned. + +# Please refer to containers.conf(5) for details of all configuration options. +# Not all container engines implement all of the options. +# All of the options have hard coded defaults and these options will override +# the built in defaults. Users can then override these options via the command +# line. Container engines will read containers.conf files in up to three +# locations in the following order: +# 1. /usr/local/share/containers/containers.conf +# 2. /usr/local/etc/containers/containers.conf +# 3. $HOME/.config/containers/containers.conf (Rootless containers ONLY) +# Items specified in the latter containers.conf, if they exist, override the +# previous containers.conf settings, or the default settings. + +[containers] + +# List of annotation. Specified as +# "key = value" +# If it is empty or commented out, no annotations will be added +# +#annotations = [] + +# The hosts entries from the base hosts file are added to the containers hosts +# file. This must be either an absolute path or as special values "image" which +# uses the hosts file from the container image or "none" which means +# no base hosts file is used. The default is "" which will use /etc/hosts. +# +#base_hosts_file = "" + +# List of default capabilities for containers. If it is empty or commented out, +# the default capabilities defined in the container engine will be added. +# +default_capabilities = [ + "CHOWN", + "DAC_OVERRIDE", + "FOWNER", + "FSETID", + "KILL", + "NET_BIND_SERVICE", + "SETFCAP", + "SETGID", + "SETPCAP", + "SETUID", + "SYS_CHROOT" +] + +# A list of sysctls to be set in containers by default, +# specified as "name=value", +# for example:"net.ipv4.ping_group_range=0 0". +# +default_sysctls = [ + "net.ipv4.ping_group_range=0 0", +] + +# A list of ulimits to be set in containers by default, specified as +# "<ulimit name>=<soft limit>:<hard limit>", for example: +# "nofile=1024:2048" +# See setrlimit(2) for a list of resource names. +# Any limit not specified here will be inherited from the process launching the +# container engine. +# Ulimits has limits for non privileged container engines. +# +#default_ulimits = [ +# "nofile=1280:2560", +#] + +# List of devices. Specified as +# "<device-on-host>:<device-on-container>:<permissions>", for example: +# "/dev/sdc:/dev/xvdc:rwm". +# If it is empty or commented out, only the default devices will be used +# +#devices = [] + +# List of default DNS options to be added to /etc/resolv.conf inside of the container. +# +#dns_options = [] + +# List of default DNS search domains to be added to /etc/resolv.conf inside of the container. +# +#dns_searches = [] + +# Set default DNS servers. +# This option can be used to override the DNS configuration passed to the +# container. The special value "none" can be specified to disable creation of +# /etc/resolv.conf in the container. +# The /etc/resolv.conf file in the image will be used without changes. +# +#dns_servers = [] + +# Environment variable list for the conmon process; used for passing necessary +# environment variables to conmon or the runtime. +# +#env = [ +# "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", +# "TERM=xterm", +#] + +# Pass all host environment variables into the container. +# +#env_host = false + +# Set the ip for the host.containers.internal entry in the containers /etc/hosts +# file. This can be set to "none" to disable adding this entry. By default it +# will automatically choose the host ip. +# +# NOTE: When using podman machine this entry will never be added to the containers +# hosts file instead the gvproxy dns resolver will resolve this hostname. Therefore +# it is not possible to disable the entry in this case. +# +#host_containers_internal_ip = "" + +# Default proxy environment variables passed into the container. +# The environment variables passed in include: +# http_proxy, https_proxy, ftp_proxy, no_proxy, and the upper case versions of +# these. This option is needed when host system uses a proxy but container +# should not use proxy. Proxy environment variables specified for the container +# in any other way will override the values passed from the host. +# +#http_proxy = true + +# Run an init inside the container that forwards signals and reaps processes. +# +#init = false + +# Container init binary, if init=true, this is the init binary to be used for containers. +# +#init_path = "/usr/local/libexec/podman/catatonit" + +# Default way to to create an IPC namespace (POSIX SysV IPC) for the container +# Options are: +# "host" Share host IPC Namespace with the container. +# "none" Create shareable IPC Namespace for the container without a private /dev/shm. +# "private" Create private IPC Namespace for the container, other containers are not allowed to share it. +# "shareable" Create shareable IPC Namespace for the container. +# +#ipcns = "shareable" + +# keyring tells the container engine whether to create +# a kernel keyring for use within the container. +# +#keyring = true + +# label tells the container engine whether to use container separation using +# MAC(SELinux) labeling or not. +# The label flag is ignored on label disabled systems. +# +#label = true + +# Logging driver for the container. Available options: k8s-file and journald. +# +#log_driver = "k8s-file" + +# Maximum size allowed for the container log file. Negative numbers indicate +# that no size limit is imposed. If positive, it must be >= 8192 to match or +# exceed conmon's read buffer. The file is truncated and re-opened so the +# limit is never exceeded. +# +#log_size_max = -1 + +# Specifies default format tag for container log messages. +# This is useful for creating a specific tag for container log messages. +# Containers logs default to truncated container ID as a tag. +# +#log_tag = "" + +# Default way to to create a Network namespace for the container +# Options are: +# `private` Create private Network Namespace for the container. +# `host` Share host Network Namespace with the container. +# `none` Containers do not use the network +# +#netns = "private" + +# Create /etc/hosts for the container. By default, container engine manage +# /etc/hosts, automatically adding the container's own IP address. +# +#no_hosts = false + +# Default way to to create a PID namespace for the container +# Options are: +# `private` Create private PID Namespace for the container. +# `host` Share host PID Namespace with the container. +# +#pidns = "private" + +# Maximum number of processes allowed in a container. +# +#pids_limit = 2048 + +# Copy the content from the underlying image into the newly created volume +# when the container is created instead of when it is started. If false, +# the container engine will not copy the content until the container is started. +# Setting it to true may have negative performance implications. +# +#prepare_volume_on_create = false + +# Set timezone in container. Takes IANA timezones as well as "local", +# which sets the timezone in the container to match the host machine. +# +#tz = "" + +# Set umask inside the container +# +#umask = "0022" + +# Default way to to create a User namespace for the container +# Options are: +# `auto` Create unique User Namespace for the container. +# `host` Share host User Namespace with the container. +# +#userns = "host" + +# Number of UIDs to allocate for the automatic container creation. +# UIDs are allocated from the "container" UIDs listed in +# /etc/subuid & /etc/subgid +# +#userns_size = 65536 + +# Default way to to create a UTS namespace for the container +# Options are: +# `private` Create private UTS Namespace for the container. +# `host` Share host UTS Namespace with the container. +# +#utsns = "private" + +# List of volumes. Specified as +# "<directory-on-host>:<directory-in-container>:<options>", for example: +# "/db:/var/lib/db:ro". +# If it is empty or commented out, no volumes will be added +# +#volumes = [] + +[secrets] +#driver = "file" + +[secrets.opts] +#root = "/example/directory" + +[network] + +# Network backend determines what network driver will be used to set up and tear down container networks. +# Valid values are "cni" and "netavark". +# The default value is empty which means that it will automatically choose CNI or netavark. If there are +# already containers/images or CNI networks preset it will choose CNI. +# +# Before changing this value all containers must be stopped otherwise it is likely that +# iptables rules and network interfaces might leak on the host. A reboot will fix this. +# +#network_backend = "" + +# Path to directory where CNI plugin binaries are located. +# +#cni_plugin_dirs = [ +# "/usr/local/libexec/cni", +# "/usr/libexec/cni", +# "/usr/local/lib/cni", +# "/usr/lib/cni", +# "/opt/cni/bin", +#] + +# The network name of the default network to attach pods to. +# +#default_network = "podman" + +# The default subnet for the default network given in default_network. +# If a network with that name does not exist, a new network using that name and +# this subnet will be created. +# Must be a valid IPv4 CIDR prefix. +# +#default_subnet = "10.88.0.0/16" + +# DefaultSubnetPools is a list of subnets and size which are used to +# allocate subnets automatically for podman network create. +# It will iterate through the list and will pick the first free subnet +# with the given size. This is only used for ipv4 subnets, ipv6 subnets +# are always assigned randomly. +# +#default_subnet_pools = [ +# {"base" = "10.89.0.0/16", "size" = 24}, +# {"base" = "10.90.0.0/15", "size" = 24}, +# {"base" = "10.92.0.0/14", "size" = 24}, +# {"base" = "10.96.0.0/11", "size" = 24}, +# {"base" = "10.128.0.0/9", "size" = 24}, +#] + +# Path to the directory where network configuration files are located. +# For the CNI backend the default is "/etc/cni/net.d" as root +# and "$HOME/.config/cni/net.d" as rootless. +# For the netavark backend "/etc/containers/networks" is used as root +# and "$graphroot/networks" as rootless. +# +#network_config_dir = "/usr/local/etc/cni/net.d/" + +[engine] +# Index to the active service +# +#active_service = production + +# The compression format to use when pushing an image. +# Valid options are: `gzip`, `zstd` and `zstd:chunked`. +# +#compression_format = "gzip" + +# Environment variables to pass into conmon +# +#conmon_env_vars = [ +# "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +#] + +# Paths to look for the conmon container manager binary +# +#conmon_path = [ +# "/usr/libexec/podman/conmon", +# "/usr/local/libexec/podman/conmon", +# "/usr/local/lib/podman/conmon", +# "/usr/bin/conmon", +# "/usr/sbin/conmon", +# "/usr/local/bin/conmon", +# "/usr/local/sbin/conmon" +#] + +# Enforces using docker.io for completing short names in Podman's compatibility +# REST API. Note that this will ignore unqualified-search-registries and +# short-name aliases defined in containers-registries.conf(5). +#compat_api_enforce_docker_hub = true + +# Specify the keys sequence used to detach a container. +# Format is a single character [a-Z] or a comma separated sequence of +# `ctrl-<value>`, where `<value>` is one of: +# `a-z`, `@`, `^`, `[`, `\`, `]`, `^` or `_` +# +#detach_keys = "ctrl-p,ctrl-q" + +# Determines whether engine will reserve ports on the host when they are +# forwarded to containers. When enabled, when ports are forwarded to containers, +# ports are held open by as long as the container is running, ensuring that +# they cannot be reused by other programs on the host. However, this can cause +# significant memory usage if a container has many ports forwarded to it. +# Disabling this can save memory. +# +#enable_port_reservation = true + +# Environment variables to be used when running the container engine (e.g., Podman, Buildah). +# For example "http_proxy=internal.proxy.company.com". +# Note these environment variables will not be used within the container. +# Set the env section under [containers] table, if you want to set environment variables for the container. +# +#env = [] + +# Define where event logs will be stored, when events_logger is "file". +#events_logfile_path="" + +# Sets the maximum size for events_logfile_path. +# The size can be b (bytes), k (kilobytes), m (megabytes), or g (gigabytes). +# The format for the size is `<number><unit>`, e.g., `1b` or `3g`. +# If no unit is included then the size will be read in bytes. +# When the limit is exceeded, the logfile will be rotated and the old one will be deleted. +# If the maximum size is set to 0, then no limit will be applied, +# and the logfile will not be rotated. +#events_logfile_max_size = "1m" + +# Selects which logging mechanism to use for container engine events. +# Valid values are `journald`, `file` and `none`. +# +#events_logger = "file" + +# A is a list of directories which are used to search for helper binaries. +# +#helper_binaries_dir = [ +# "/usr/local/libexec/podman", +# "/usr/local/lib/podman", +# "/usr/libexec/podman", +# "/usr/lib/podman", +#] + +# Path to OCI hooks directories for automatically executed hooks. +# +#hooks_dir = [ +# "/usr/local/share/containers/oci/hooks.d", +#] + +# Manifest Type (oci, v2s2, or v2s1) to use when pulling, pushing, building +# container images. By default image pulled and pushed match the format of the +# source image. Building/committing defaults to OCI. +# +#image_default_format = "" + +# Default transport method for pulling and pushing for images +# +#image_default_transport = "docker://" + +# Maximum number of image layers to be copied (pulled/pushed) simultaneously. +# Not setting this field, or setting it to zero, will fall back to containers/image defaults. +# +#image_parallel_copies = 0 + +# Default command to run the infra container +# +#infra_command = "/pause" + +# Infra (pause) container image name for pod infra containers. When running a +# pod, we start a `pause` process in a container to hold open the namespaces +# associated with the pod. This container does nothing other then sleep, +# reserving the pods resources for the lifetime of the pod. By default container +# engines run a builtin container using the pause executable. If you want override +# specify an image to pull. +# +#infra_image = "" + +# Specify the locking mechanism to use; valid values are "shm" and "file". +# Change the default only if you are sure of what you are doing, in general +# "file" is useful only on platforms where cgo is not available for using the +# faster "shm" lock type. You may need to run "podman system renumber" after +# you change the lock type. +# +#lock_type** = "shm" + +# 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. +# +#multi_image_archive = "false" + +# Default engine namespace +# If engine is joined to a namespace, it will see only containers and pods +# that were created in the same namespace, and will create new containers and +# pods in that namespace. +# The default namespace is "", which corresponds to no namespace. When no +# namespace is set, all containers and pods are visible. +# +#namespace = "" + +# Path to the slirp4netns binary +# +#network_cmd_path = "" + +# Default options to pass to the slirp4netns binary. +# Valid options values are: +# +# - allow_host_loopback=true|false: Allow the slirp4netns to reach the host loopback IP (`10.0.2.2`). +# Default is false. +# - mtu=MTU: Specify the MTU to use for this network. (Default is `65520`). +# - cidr=CIDR: Specify ip range to use for this network. (Default is `10.0.2.0/24`). +# - enable_ipv6=true|false: Enable IPv6. Default is true. (Required for `outbound_addr6`). +# - outbound_addr=INTERFACE: Specify the outbound interface slirp should bind to (ipv4 traffic only). +# - outbound_addr=IPv4: Specify the outbound ipv4 address slirp should bind to. +# - outbound_addr6=INTERFACE: Specify the outbound interface slirp should bind to (ipv6 traffic only). +# - outbound_addr6=IPv6: Specify the outbound ipv6 address slirp should bind to. +# - port_handler=rootlesskit: Use rootlesskit for port forwarding. Default. +# Note: Rootlesskit changes the source IP address of incoming packets to a IP address in the container +# network namespace, usually `10.0.2.100`. If your application requires the real source IP address, +# e.g. web server logs, use the slirp4netns port handler. The rootlesskit port handler is also used for +# rootless containers when connected to user-defined networks. +# - port_handler=slirp4netns: Use the slirp4netns port forwarding, it is slower than rootlesskit but +# preserves the correct source IP address. This port handler cannot be used for user-defined networks. +# +#network_cmd_options = [] + +# Whether to use chroot instead of pivot_root in the runtime +# +#no_pivot_root = false + +# Number of locks available for containers and pods. +# If this is changed, a lock renumber must be performed (e.g. with the +# 'podman system renumber' command). +# +#num_locks = 2048 + +# Whether to pull new image before running a container +# +#pull_policy = "missing" + +# Indicates whether the application should be running in remote mode. This flag modifies the +# --remote option on container engines. Setting the flag to true will default +# `podman --remote=true` for access to the remote Podman service. +# +#remote = false + +# Default OCI runtime +# +#runtime = "crun" + +# List of the OCI runtimes that support --format=json. When json is supported +# engine will use it for reporting nicer errors. +# +#runtime_supports_json = ["crun", "runc", "kata", "runsc", "krun"] + +# List of the OCI runtimes that supports running containers with KVM Separation. +# +#runtime_supports_kvm = ["kata", "krun"] + +# List of the OCI runtimes that supports running containers without cgroups. +# +#runtime_supports_nocgroups = ["crun", "krun"] + +# Default location for storing temporary container image content. Can be overridden with the TMPDIR environment +# variable. If you specify "storage", then the location of the +# container/storage tmp directory will be used. +# image_copy_tmp_dir="/var/tmp" + +# Number of seconds to wait without a connection +# before the `podman system service` times out and exits +# +#service_timeout = 5 + +# Directory for persistent engine files (database, etc) +# By default, this will be configured relative to where the containers/storage +# stores containers +# Uncomment to change location from this default +# +#static_dir = "/var/lib/containers/storage/libpod" + +# Number of seconds to wait for container to exit before sending kill signal. +# +#stop_timeout = 10 + +# Number of seconds to wait before exit command in API process is given to. +# This mimics Docker's exec cleanup behaviour, where the default is 5 minutes (value is in seconds). +# +#exit_command_delay = 300 + +# map of service destinations +# +#[service_destinations] +# [service_destinations.production] +# URI to access the Podman service +# Examples: +# rootless "unix://run/user/$UID/podman/podman.sock" (Default) +# rootful "unix://run/podman/podman.sock (Default) +# remote rootless ssh://engineering.lab.company.com/run/user/1000/podman/podman.sock +# remote rootful ssh://root@10.10.1.136:22/run/podman/podman.sock +# +# uri = "ssh://user@production.example.com/run/user/1001/podman/podman.sock" +# Path to file containing ssh identity key +# identity = "~/.ssh/id_rsa" + +# Directory for temporary files. Must be tmpfs (wiped after reboot) +# +#tmp_dir = "/run/libpod" + +# Directory for libpod named volumes. +# By default, this will be configured relative to where containers/storage +# stores containers. +# Uncomment to change location from this default. +# +#volume_path = "/var/lib/containers/storage/volumes" + +# Paths to look for a valid OCI runtime (crun, runc, kata, runsc, krun, etc) +[engine.runtimes] +#crun = [ +# "/usr/bin/crun", +# "/usr/sbin/crun", +# "/usr/local/bin/crun", +# "/usr/local/sbin/crun", +# "/sbin/crun", +# "/bin/crun", +# "/run/current-system/sw/bin/crun", +#] + +#kata = [ +# "/usr/bin/kata-runtime", +# "/usr/sbin/kata-runtime", +# "/usr/local/bin/kata-runtime", +# "/usr/local/sbin/kata-runtime", +# "/sbin/kata-runtime", +# "/bin/kata-runtime", +# "/usr/bin/kata-qemu", +# "/usr/bin/kata-fc", +#] + +#runc = [ +# "/usr/bin/runc", +# "/usr/sbin/runc", +# "/usr/local/bin/runc", +# "/usr/local/sbin/runc", +# "/sbin/runc", +# "/bin/runc", +# "/usr/lib/cri-o-runc/sbin/runc", +#] + +#runsc = [ +# "/usr/bin/runsc", +# "/usr/sbin/runsc", +# "/usr/local/bin/runsc", +# "/usr/local/sbin/runsc", +# "/bin/runsc", +# "/sbin/runsc", +# "/run/current-system/sw/bin/runsc", +#] + +#krun = [ +# "/usr/bin/krun", +# "/usr/local/bin/krun", +#] + +[engine.volume_plugins] +#testplugin = "/var/run/podman/plugins/test.sock" + +[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 username to use and create on the podman machine OS for rootless +# container access. +# +#user = "core" + +# Host directories to be mounted as volumes into the VM by default. +# Environment variables like $HOME as well as complete paths are supported for +# the source and destination. An optional third field `:ro` can be used to +# tell the container engines to mount the volume readonly. +# +# volumes = [ +# "$HOME:$HOME", +#] + +# 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 [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 8979a406b..d988d3b1c 100644 --- a/vendor/github.com/containers/common/pkg/config/default.go +++ b/vendor/github.com/containers/common/pkg/config/default.go @@ -193,7 +193,7 @@ func DefaultConfig() (*Config, error) { ApparmorProfile: DefaultApparmorProfile, BaseHostsFile: "", CgroupNS: cgroupNS, - Cgroups: "enabled", + Cgroups: getDefaultCgroupsMode(), DefaultCapabilities: DefaultCapabilities, DefaultSysctls: []string{}, DefaultUlimits: getDefaultProcessLimits(), @@ -323,6 +323,9 @@ func defaultConfigFromMemory() (*EngineConfig, error) { "/usr/lib/cri-o-runc/sbin/runc", "/run/current-system/sw/bin/runc", }, + "runj": { + "/usr/local/bin/runj", + }, "kata": { "/usr/bin/kata-runtime", "/usr/sbin/kata-runtime", @@ -384,7 +387,7 @@ func defaultConfigFromMemory() (*EngineConfig, error) { c.SDNotify = false // TODO - ideally we should expose a `type LockType string` along with // constants. - c.LockType = "shm" + c.LockType = getDefaultLockType() c.MachineEnabled = false c.ChownCopiedFiles = true @@ -395,7 +398,7 @@ func defaultConfigFromMemory() (*EngineConfig, error) { func defaultTmpDir() (string, error) { if !unshare.IsRootless() { - return "/run/libpod", nil + return getLibpodTmpDir(), nil } runtimeDir, err := util.GetRuntimeDir() diff --git a/vendor/github.com/containers/common/pkg/config/default_darwin.go b/vendor/github.com/containers/common/pkg/config/default_darwin.go new file mode 100644 index 000000000..c502ea55e --- /dev/null +++ b/vendor/github.com/containers/common/pkg/config/default_darwin.go @@ -0,0 +1,13 @@ +package config + +func getDefaultCgroupsMode() string { + return "enabled" +} + +func getDefaultLockType() string { + return "shm" +} + +func getLibpodTmpDir() string { + return "/run/libpod" +} diff --git a/vendor/github.com/containers/common/pkg/config/default_freebsd.go b/vendor/github.com/containers/common/pkg/config/default_freebsd.go new file mode 100644 index 000000000..8b10ac1f7 --- /dev/null +++ b/vendor/github.com/containers/common/pkg/config/default_freebsd.go @@ -0,0 +1,20 @@ +package config + +func getDefaultCgroupsMode() string { + return "disabled" +} + +// In theory, FreeBSD should be able to use shm locks but in practice, +// this causes cryptic error messages from the kernel that look like: +// +// comm podman pid 90813: handling rb error 22 +// +// These seem to be related to fork/exec code paths. Fall back to +// file-based locks. +func getDefaultLockType() string { + return "file" +} + +func getLibpodTmpDir() string { + return "/var/run/libpod" +} diff --git a/vendor/github.com/containers/common/pkg/config/default_linux.go b/vendor/github.com/containers/common/pkg/config/default_linux.go index d6ea4359c..86873beb1 100644 --- a/vendor/github.com/containers/common/pkg/config/default_linux.go +++ b/vendor/github.com/containers/common/pkg/config/default_linux.go @@ -14,6 +14,10 @@ const ( oldMaxSize = uint64(1048576) ) +func getDefaultCgroupsMode() string { + return "enabled" +} + // getDefaultMachineImage returns the default machine image stream // On Linux/Mac, this returns the FCOS stream func getDefaultMachineImage() string { @@ -58,3 +62,11 @@ func getDefaultTmpDir() string { } return "/var/tmp" } + +func getDefaultLockType() string { + return "shm" +} + +func getLibpodTmpDir() string { + return "/run/libpod" +} diff --git a/vendor/github.com/containers/common/pkg/config/default_windows.go b/vendor/github.com/containers/common/pkg/config/default_windows.go index db230dfb2..1ff88fc42 100644 --- a/vendor/github.com/containers/common/pkg/config/default_windows.go +++ b/vendor/github.com/containers/common/pkg/config/default_windows.go @@ -32,3 +32,15 @@ func getDefaultTmpDir() string { } return os.Getenv("LOCALAPPDATA") + "\\Temp" } + +func getDefaultCgroupsMode() string { + return "enabled" +} + +func getDefaultLockType() string { + return "shm" +} + +func getLibpodTmpDir() string { + return "/run/libpod" +} diff --git a/vendor/github.com/containers/common/pkg/filters/filters.go b/vendor/github.com/containers/common/pkg/filters/filters.go index e26e056ad..53650efc9 100644 --- a/vendor/github.com/containers/common/pkg/filters/filters.go +++ b/vendor/github.com/containers/common/pkg/filters/filters.go @@ -36,11 +36,13 @@ func ComputeUntilTimestamp(filterValues []string) (time.Time, error) { // // Please refer to https://github.com/containers/podman/issues/6899 for some // background. +// +// revive does not like the name because the package is already called filters +//nolint:revive func FiltersFromRequest(r *http.Request) ([]string, error) { var ( compatFilters map[string]map[string]bool filters map[string][]string - libpodFilters []string raw []byte ) @@ -54,6 +56,7 @@ func FiltersFromRequest(r *http.Request) ([]string, error) { // Backwards compat with older versions of Docker. if err := json.Unmarshal(raw, &compatFilters); err == nil { + libpodFilters := make([]string, 0, len(compatFilters)) for filterKey, filterMap := range compatFilters { for filterValue, toAdd := range filterMap { if toAdd { @@ -68,6 +71,7 @@ func FiltersFromRequest(r *http.Request) ([]string, error) { return nil, err } + libpodFilters := make([]string, 0, len(filters)) for filterKey, filterSlice := range filters { f := filterKey for _, filterValue := range filterSlice { diff --git a/vendor/github.com/containers/common/pkg/machine/machine.go b/vendor/github.com/containers/common/pkg/machine/machine.go index 465eeceaf..37e89a08e 100644 --- a/vendor/github.com/containers/common/pkg/machine/machine.go +++ b/vendor/github.com/containers/common/pkg/machine/machine.go @@ -9,6 +9,8 @@ import ( "github.com/sirupsen/logrus" ) +// TODO: change name to MachineMarker since package is already called machine +//nolint:revive type MachineMarker struct { Enabled bool Type string @@ -54,6 +56,8 @@ func IsPodmanMachine() bool { return GetMachineMarker().Enabled } +// TODO: change name to HostType since package is already called machine +//nolint:revive func MachineHostType() string { return GetMachineMarker().Type } diff --git a/vendor/github.com/containers/common/pkg/parse/parse_unix.go b/vendor/github.com/containers/common/pkg/parse/parse_unix.go index d087c4a02..6fb52a014 100644 --- a/vendor/github.com/containers/common/pkg/parse/parse_unix.go +++ b/vendor/github.com/containers/common/pkg/parse/parse_unix.go @@ -1,5 +1,5 @@ -//go:build linux || darwin -// +build linux darwin +//go:build linux || darwin || freebsd +// +build linux darwin freebsd package parse @@ -13,7 +13,6 @@ import ( ) func DeviceFromPath(device string) ([]devices.Device, error) { - var devs []devices.Device src, dst, permissions, err := Device(device) if err != nil { return nil, err @@ -27,7 +26,7 @@ func DeviceFromPath(device string) ([]devices.Device, error) { } if !srcInfo.IsDir() { - + devs := make([]devices.Device, 0, 1) dev, err := devices.DeviceFromPath(src, permissions) if err != nil { return nil, errors.Wrapf(err, "%s is not a valid device", src) @@ -42,6 +41,7 @@ func DeviceFromPath(device string) ([]devices.Device, error) { if err != nil { return nil, errors.Wrapf(err, "error getting source devices from directory %s", src) } + devs := make([]devices.Device, 0, len(srcDevices)) for _, d := range srcDevices { d.Path = filepath.Join(dst, filepath.Base(d.Path)) d.Permissions = devices.Permissions(permissions) diff --git a/vendor/github.com/containers/common/pkg/retry/retry.go b/vendor/github.com/containers/common/pkg/retry/retry.go index a9573e4e8..234fd3448 100644 --- a/vendor/github.com/containers/common/pkg/retry/retry.go +++ b/vendor/github.com/containers/common/pkg/retry/retry.go @@ -17,12 +17,17 @@ import ( ) // RetryOptions defines the option to retry +// revive does not like the name because the package is already called retry +//nolint:revive type RetryOptions struct { MaxRetry int // The number of times to possibly retry Delay time.Duration // The delay to use between retries, if set } // RetryIfNecessary retries the operation in exponential backoff with the retryOptions +// +// revive does not like the name because the package is already called retry +//nolint:revive func RetryIfNecessary(ctx context.Context, operation func() error, retryOptions *RetryOptions) error { err := operation() for attempt := 0; err != nil && isRetryable(err) && attempt < retryOptions.MaxRetry; attempt++ { diff --git a/vendor/github.com/containers/common/pkg/seccomp/conversion.go b/vendor/github.com/containers/common/pkg/seccomp/conversion.go index 4c25cb1b1..cd599f0f3 100644 --- a/vendor/github.com/containers/common/pkg/seccomp/conversion.go +++ b/vendor/github.com/containers/common/pkg/seccomp/conversion.go @@ -71,11 +71,12 @@ var ( // https://github.com/opencontainers/runtime-spec/pull/1064 // specs.ActKillProcess ActKillProcess, // specs.ActKillThread ActKillThread, - specs.ActErrno: ActErrno, - specs.ActTrap: ActTrap, - specs.ActAllow: ActAllow, - specs.ActTrace: ActTrace, - specs.ActLog: ActLog, + specs.ActErrno: ActErrno, + specs.ActTrap: ActTrap, + specs.ActAllow: ActAllow, + specs.ActTrace: ActTrace, + specs.ActLog: ActLog, + specs.ActNotify: ActNotify, } specOperatorToSeccompOperatorMap = map[specs.LinuxSeccompOperator]Operator{ specs.OpNotEqual: OpNotEqual, diff --git a/vendor/github.com/containers/common/pkg/seccomp/filter.go b/vendor/github.com/containers/common/pkg/seccomp/filter.go index 5c278574c..609036c82 100644 --- a/vendor/github.com/containers/common/pkg/seccomp/filter.go +++ b/vendor/github.com/containers/common/pkg/seccomp/filter.go @@ -130,7 +130,7 @@ func matchSyscall(filter *libseccomp.ScmpFilter, call *Syscall) error { return errors.Wrapf(err, "create seccomp syscall condition for syscall %s", call.Name) } - argCounts[cond.Index] += 1 + argCounts[cond.Index]++ conditions = append(conditions, newCond) } diff --git a/vendor/github.com/containers/common/pkg/seccomp/types.go b/vendor/github.com/containers/common/pkg/seccomp/types.go index 784b1ba8d..56fd22a38 100644 --- a/vendor/github.com/containers/common/pkg/seccomp/types.go +++ b/vendor/github.com/containers/common/pkg/seccomp/types.go @@ -75,6 +75,7 @@ const ( ActTrace Action = "SCMP_ACT_TRACE" ActAllow Action = "SCMP_ACT_ALLOW" ActLog Action = "SCMP_ACT_LOG" + ActNotify Action = "SCMP_ACT_NOTIFY" ) // Operator used to match syscall arguments in Seccomp diff --git a/vendor/github.com/containers/common/pkg/secrets/filedriver/filedriver.go b/vendor/github.com/containers/common/pkg/secrets/filedriver/filedriver.go index e0c275851..6b92714d0 100644 --- a/vendor/github.com/containers/common/pkg/secrets/filedriver/filedriver.go +++ b/vendor/github.com/containers/common/pkg/secrets/filedriver/filedriver.go @@ -55,7 +55,7 @@ func (d *Driver) List() ([]string, error) { if err != nil { return nil, err } - var allID []string + allID := make([]string, 0, len(secretData)) for k := range secretData { allID = append(allID, k) } @@ -134,9 +134,8 @@ func (d *Driver) getAllData() (map[string][]byte, error) { if os.IsNotExist(err) { // the file will be created later on a store() return make(map[string][]byte), nil - } else { - return nil, err } + return nil, err } file, err := os.Open(d.secretsDataFilePath) diff --git a/vendor/github.com/containers/common/pkg/secrets/secrets.go b/vendor/github.com/containers/common/pkg/secrets/secrets.go index 4a04e2b2f..e45995b2e 100644 --- a/vendor/github.com/containers/common/pkg/secrets/secrets.go +++ b/vendor/github.com/containers/common/pkg/secrets/secrets.go @@ -53,6 +53,9 @@ var secretsFile = "secrets.json" var secretNameRegexp = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_.-]*$`) // SecretsManager holds information on handling secrets +// +// revive does not like the name because the package is already called secrets +//nolint:revive type SecretsManager struct { // secretsPath is the path to the db file where secrets are stored secretsDBPath string @@ -82,6 +85,9 @@ type Secret struct { // The driver stores the actual bytes of secret data, as opposed to // the secret metadata. // Currently only the unencrypted filedriver is implemented. +// +// revive does not like the name because the package is already called secrets +//nolint:revive type SecretsDriver interface { // List lists all secret ids in the secrets data store List() ([]string, error) @@ -234,7 +240,7 @@ func (s *SecretsManager) List() ([]Secret, error) { if err != nil { return nil, err } - var ls []Secret + ls := make([]Secret, 0, len(secrets)) for _, v := range secrets { ls = append(ls, v) } @@ -276,9 +282,8 @@ func getDriver(name string, opts map[string]string) (SecretsDriver, error) { case "file": if path, ok := opts["path"]; ok { return filedriver.NewDriver(path) - } else { - return nil, errors.Wrap(errInvalidDriverOpt, "need path for filedriver") } + return nil, errors.Wrap(errInvalidDriverOpt, "need path for filedriver") case "pass": return passdriver.NewDriver(opts) case "shell": diff --git a/vendor/github.com/containers/common/pkg/secrets/secretsdb.go b/vendor/github.com/containers/common/pkg/secrets/secretsdb.go index 4d2ca0fca..8d21aa754 100644 --- a/vendor/github.com/containers/common/pkg/secrets/secretsdb.go +++ b/vendor/github.com/containers/common/pkg/secrets/secretsdb.go @@ -31,9 +31,8 @@ func (s *SecretsManager) loadDB() error { // the db cache will show no entries anyway. // The file will be created later on a store() return nil - } else { - return err } + return err } // We check if the file has been modified after the last time it was loaded into the cache. diff --git a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go index 4410292a7..b111ae7ff 100644 --- a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go +++ b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go @@ -212,8 +212,8 @@ func rchown(chowndir string, uid, gid int) error { // addSubscriptionsFromMountsFile copies the contents of host directory to container directory // and returns a list of mounts func addSubscriptionsFromMountsFile(filePath, mountLabel, containerRunDir string, uid, gid int) ([]rspec.Mount, error) { - var mounts []rspec.Mount defaultMountsPaths := getMounts(filePath) + mounts := make([]rspec.Mount, 0, len(defaultMountsPaths)) for _, path := range defaultMountsPaths { hostDirOrFile, ctrDirOrFile, err := getMountsMap(path) if err != nil { diff --git a/vendor/github.com/containers/common/pkg/sysinfo/nummem_linux.go b/vendor/github.com/containers/common/pkg/sysinfo/nummem_linux.go index 859791e36..018c488be 100644 --- a/vendor/github.com/containers/common/pkg/sysinfo/nummem_linux.go +++ b/vendor/github.com/containers/common/pkg/sysinfo/nummem_linux.go @@ -12,6 +12,8 @@ import ( // NUMANodeCount queries the system for the count of Memory Nodes available // for use to this process. func NUMANodeCount() int { + // this is the correct flag name (not defined in the unix package) + //nolint:revive MPOL_F_MEMS_ALLOWED := (1 << 2) var mask [1024 / 64]uintptr _, _, err := unix.RawSyscall6(unix.SYS_GET_MEMPOLICY, 0, uintptr(unsafe.Pointer(&mask[0])), uintptr(len(mask)*8), 0, uintptr(MPOL_F_MEMS_ALLOWED), 0) diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index 61fce9d22..f8a24f823 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.48.0" +const Version = "0.49.0-dev" diff --git a/vendor/github.com/containers/image/v5/copy/copy.go b/vendor/github.com/containers/image/v5/copy/copy.go index d28cc4a3f..123c23e02 100644 --- a/vendor/github.com/containers/image/v5/copy/copy.go +++ b/vendor/github.com/containers/image/v5/copy/copy.go @@ -305,7 +305,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef, unparsedInstance := image.UnparsedInstance(rawSource, &instanceDigest) if copiedManifest, _, _, err = c.copyOneImage(ctx, policyContext, options, unparsedToplevel, unparsedInstance, nil); err != nil { - return nil, err + return nil, errors.Wrap(err, "copying system image from manifest list") } } else { /* options.ImageListSelection == CopyAllImages or options.ImageListSelection == CopySpecificImages, */ // If we were asked to copy multiple images and can't, that's an error. @@ -501,7 +501,7 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur unparsedInstance := image.UnparsedInstance(c.rawSource, &instanceDigest) updatedManifest, updatedManifestType, updatedManifestDigest, err := c.copyOneImage(ctx, policyContext, options, unparsedToplevel, unparsedInstance, &instanceDigest) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "copying image %d/%d from manifest list", instancesCopied+1, imagesToCopy) } instancesCopied++ // Record the result of a possible conversion here. diff --git a/vendor/github.com/containers/image/v5/image/docker_list.go b/vendor/github.com/containers/image/v5/image/docker_list.go index 4fe84413c..af78ac1df 100644 --- a/vendor/github.com/containers/image/v5/image/docker_list.go +++ b/vendor/github.com/containers/image/v5/image/docker_list.go @@ -19,7 +19,7 @@ func manifestSchema2FromManifestList(ctx context.Context, sys *types.SystemConte } manblob, mt, err := src.GetManifest(ctx, &targetManifestDigest) if err != nil { - return nil, errors.Wrapf(err, "loading manifest for target platform") + return nil, errors.Wrapf(err, "fetching target platform image selected from manifest list") } matches, err := manifest.MatchesDigest(manblob, targetManifestDigest) diff --git a/vendor/github.com/containers/image/v5/image/oci_index.go b/vendor/github.com/containers/image/v5/image/oci_index.go index 4e6ca879a..d6e6685b1 100644 --- a/vendor/github.com/containers/image/v5/image/oci_index.go +++ b/vendor/github.com/containers/image/v5/image/oci_index.go @@ -19,7 +19,7 @@ func manifestOCI1FromImageIndex(ctx context.Context, sys *types.SystemContext, s } manblob, mt, err := src.GetManifest(ctx, &targetManifestDigest) if err != nil { - return nil, errors.Wrapf(err, "loading manifest for target platform") + return nil, errors.Wrapf(err, "fetching target platform image selected from image index") } matches, err := manifest.MatchesDigest(manblob, targetManifestDigest) diff --git a/vendor/github.com/proglottis/gpgme/gpgme.go b/vendor/github.com/proglottis/gpgme/gpgme.go index 9833057a6..82effbd9e 100644 --- a/vendor/github.com/proglottis/gpgme/gpgme.go +++ b/vendor/github.com/proglottis/gpgme/gpgme.go @@ -1,6 +1,7 @@ // Package gpgme provides a Go wrapper for the GPGME library package gpgme +// #cgo pkg-config: gpgme // #cgo LDFLAGS: -lgpgme -lassuan -lgpg-error // #cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64 // #include <stdlib.h> diff --git a/vendor/modules.txt b/vendor/modules.txt index d2d7a6df9..f4eda9756 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -109,7 +109,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.48.0 +# github.com/containers/common v0.48.1-0.20220512112240-7536bf6ff9b1 ## explicit github.com/containers/common/libimage github.com/containers/common/libimage/manifests @@ -155,7 +155,7 @@ github.com/containers/common/version # github.com/containers/conmon v2.0.20+incompatible ## explicit github.com/containers/conmon/runner/config -# github.com/containers/image/v5 v5.21.2-0.20220511203756-fe4fd4ed8be4 +# github.com/containers/image/v5 v5.21.2-0.20220519193817-1e26896b8059 ## explicit github.com/containers/image/v5/copy github.com/containers/image/v5/directory @@ -328,7 +328,7 @@ github.com/docker/distribution/registry/client/auth/challenge github.com/docker/distribution/registry/client/transport github.com/docker/distribution/registry/storage/cache github.com/docker/distribution/registry/storage/cache/memory -# github.com/docker/docker v20.10.15+incompatible +# github.com/docker/docker v20.10.16+incompatible ## explicit github.com/docker/docker/api github.com/docker/docker/api/types @@ -553,7 +553,7 @@ github.com/opencontainers/go-digest ## explicit github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 -# github.com/opencontainers/runc v1.1.1 +# github.com/opencontainers/runc v1.1.2 ## explicit github.com/opencontainers/runc/libcontainer/apparmor github.com/opencontainers/runc/libcontainer/cgroups @@ -594,7 +594,7 @@ github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 ## explicit github.com/pmezard/go-difflib/difflib -# github.com/proglottis/gpgme v0.1.1 +# github.com/proglottis/gpgme v0.1.2 github.com/proglottis/gpgme # github.com/prometheus/client_golang v1.11.1 github.com/prometheus/client_golang/prometheus |