diff options
143 files changed, 1791 insertions, 502 deletions
diff --git a/.gitignore b/.gitignore index f87c8974f..6a5ae509c 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ release.txt /test/checkseccomp/checkseccomp /test/copyimg/copyimg /test/goecho/goecho +/test/testvol/testvol .vscode* result # Necessary to prevent hack/tree-status.sh false-positive diff --git a/Containerfile-testvol b/Containerfile-testvol new file mode 100644 index 000000000..6ff45064b --- /dev/null +++ b/Containerfile-testvol @@ -0,0 +1,10 @@ +FROM golang:1.15-alpine AS build-img +COPY ./test/testvol/ /go/src/github.com/containers/podman/cmd/testvol/ +COPY ./vendor /go/src/github.com/containers/podman/vendor/ +WORKDIR /go/src/github.com/containers/podman +RUN go build -o /testvol ./cmd/testvol + +FROM alpine +COPY --from=build-img /testvol /usr/local/bin +WORKDIR / +ENTRYPOINT ["/usr/local/bin/testvol"] @@ -180,6 +180,14 @@ gofmt: ## Verify the source code gofmt test/checkseccomp/checkseccomp: .gopathok $(wildcard test/checkseccomp/*.go) $(GO) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ ./test/checkseccomp +.PHONY: test/testvol/testvol +test/testvol/testvol: .gopathok $(wildcard test/testvol/*.go) + $(GO) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -o $@ ./test/testvol + +.PHONY: volume-plugin-test-image +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) $(GO) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -o $@ ./test/goecho @@ -198,7 +206,7 @@ endif podman: bin/podman .PHONY: bin/podman-remote -bin/podman-remote: .gopathok $(SOURCES) go.mod go.sum ## Build with podman on remote environment +bin/podman-remote: .gopathok .generate-bindings $(SOURCES) go.mod go.sum ## Build with podman on remote environment $(GO) build $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "${REMOTETAGS}" -o $@ ./cmd/podman .PHONY: bin/podman-remote-static @@ -268,6 +276,8 @@ clean: ## Clean artifacts libpod/pod_ffjson.go \ libpod/container_easyjson.go \ libpod/pod_easyjson.go \ + .install.goimports \ + .generate-bindings \ docs/build make -C docs clean @@ -407,7 +417,7 @@ release.txt: # X-RELEASE-INFO format depended upon by automated tooling echo -n "X-RELEASE-INFO:" > "$@" for field in "$(RELEASE_BASENAME)" "$(RELEASE_VERSION)" \ - "$(RELEASE_DIST)" "$(RELEASE_DIST_VER)" "$(RELEASE_ARCH)"; do \ + "$(RELEASE_DIST)" "$(RELEASE_DIST_VER)" "$(RELEASE_ARCH)"; do \ echo -n " $$field"; done >> "$@" echo "" >> "$@" @@ -449,6 +459,21 @@ podman-remote-%-release: rm -f release.txt $(MAKE) podman-remote-release-$*.zip +BINDINGS_SOURCE = $(wildcard pkg/bindings/**/types.go) +.generate-bindings: $(BINDINGS_SOURCE) +ifneq ($(shell uname -s), Darwin) + for i in $(BINDINGS_SOURCE); do \ + dirname=$$(dirname $${i}); \ + shortname=$$(basename $${dirname}); \ + pushd $${dirname}>/dev/null; \ + echo $${dirname}; \ + echo $(GO) generate; \ + $(GO) generate; \ + popd > /dev/null; \ + done; +endif + touch .generate-bindings + .PHONY: docker-docs docker-docs: docs (cd docs; ./dckrman.sh ./build/man/*.1) @@ -565,13 +590,19 @@ uninstall: GIT_CHECK_EXCLUDE="./vendor:docs/make.bat" $(GOBIN)/git-validation -run DCO,short-subject,dangling-whitespace -range $(EPOCH_TEST_COMMIT)..$(HEAD) .PHONY: install.tools -install.tools: .install.gitvalidation .install.md2man .install.ginkgo .install.golangci-lint .install.bats ## Install needed tools +install.tools: .install.goimports .install.gitvalidation .install.md2man .install.ginkgo .install.golangci-lint .install.bats ## Install needed tools define go-get env GO111MODULE=off \ $(GO) get -u ${1} endef +.install.goimports: .gopathok + if [ ! -x "$(GOBIN)/goimports" ]; then \ + $(call go-get,golang.org/x/tools/cmd/goimports); \ + fi + touch .install.goimports + .PHONY: .install.ginkgo .install.ginkgo: .gopathok if [ ! -x "$(GOBIN)/ginkgo" ]; then \ @@ -71,20 +71,6 @@ A little configuration by an administrator is required before rootless Podman ca See [Skopeo](https://github.com/containers/skopeo/) for those tasks. * Support for the Kubernetes CRI interface for container management. The [CRI-O](https://github.com/cri-o/cri-o) daemon specializes in that. -* Supporting `docker-compose`. We believe that Kubernetes is the defacto - standard for composing Pods and for orchestrating containers, making - Kubernetes YAML a defacto standard file format. Hence, Podman allows the - creation and execution of Pods from a Kubernetes YAML file (see - [podman-play-kube](https://github.com/containers/podman/blob/master/docs/source/markdown/podman-play-kube.1.md)). - Podman can also generate Kubernetes YAML based on a container or Pod (see - [podman-generate-kube](https://github.com/containers/podman/blob/master/docs/source/markdown/podman-generate-kube.1.md)), - which allows for an easy transition from a local development environment - to a production Kubernetes cluster. If Kubernetes does not fit your requirements, - there are other third-party tools that support the docker-compose format such as - [kompose](https://github.com/kubernetes/kompose/) and - [podman-compose](https://github.com/muayyad-alsadi/podman-compose) - that might be appropriate for your environment. This situation may change with - the addition of the REST API. ## OCI Projects Plans diff --git a/cmd/podman/containers/rename.go b/cmd/podman/containers/rename.go new file mode 100644 index 000000000..9c94e6272 --- /dev/null +++ b/cmd/podman/containers/rename.go @@ -0,0 +1,56 @@ +package containers + +import ( + "github.com/containers/podman/v2/cmd/podman/common" + "github.com/containers/podman/v2/cmd/podman/registry" + "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + renameDescription = "The podman rename command allows you to rename an existing container" + renameCommand = &cobra.Command{ + Use: "rename CONTAINER NAME", + Short: "Rename an existing container", + Long: renameDescription, + RunE: rename, + Args: cobra.ExactArgs(2), + ValidArgsFunction: common.AutocompletePortCommand, + Example: "podman rename containerA newName", + } + + containerRenameCommand = &cobra.Command{ + Use: renameCommand.Use, + Short: renameCommand.Short, + Long: renameCommand.Long, + RunE: renameCommand.RunE, + Args: renameCommand.Args, + ValidArgsFunction: renameCommand.ValidArgsFunction, + Example: "podman container rename containerA newName", + } +) + +func init() { + // TODO: Once bindings are done, add this to TunnelMode + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: renameCommand, + }) + + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: containerRenameCommand, + Parent: containerCmd, + }) +} + +func rename(cmd *cobra.Command, args []string) error { + if len(args) > 2 { + return errors.Errorf("must provide at least two arguments to rename") + } + renameOpts := entities.ContainerRenameOptions{ + NewName: args[1], + } + return registry.ContainerEngine().ContainerRename(registry.GetContext(), args[0], renameOpts) +} diff --git a/contrib/cirrus/required_host_ports.txt b/contrib/cirrus/required_host_ports.txt index 140e2c32f..9248e497a 100644 --- a/contrib/cirrus/required_host_ports.txt +++ b/contrib/cirrus/required_host_ports.txt @@ -2,13 +2,3 @@ github.com 22 docker.io 443 quay.io 443 registry.fedoraproject.org 443 -mirrors.fedoraproject.org 443 -dl.fedoraproject.org 443 -ewr.edge.kernel.org 443 -mirror.clarkson.edu 443 -mirror.umd.edu 443 -mirror.vcu.edu 443 -mirrors.cat.pdx.edu 443 -pubmirror1.math.uh.edu 443 -pubmirror2.math.uh.edu 443 -sjc.edge.kernel.org 443 diff --git a/docs/source/Commands.rst b/docs/source/Commands.rst index cd5d894da..563462377 100644 --- a/docs/source/Commands.rst +++ b/docs/source/Commands.rst @@ -75,6 +75,8 @@ Commands :doc:`push <markdown/podman-push.1>` Push an image to a specified destination +:doc:`rename <markdown/podman-rename.1>` Rename an existing container + :doc:`restart <markdown/podman-restart.1>` Restart one or more containers :doc:`rm <markdown/podman-rm.1>` Remove one or more containers diff --git a/docs/source/managecontainers.rst b/docs/source/managecontainers.rst index 9926f9996..9b3978f25 100644 --- a/docs/source/managecontainers.rst +++ b/docs/source/managecontainers.rst @@ -41,6 +41,8 @@ Manage Containers :doc:`ps <markdown/podman-ps.1>` List containers +:doc:`rename <markdown/podman-rename.1>` Rename an existing container + :doc:`restart <markdown/podman-restart.1>` Restart one or more containers :doc:`restore <markdown/podman-container-restore.1>` Restores one or more containers from a checkpoint diff --git a/docs/source/markdown/podman-container.1.md b/docs/source/markdown/podman-container.1.md index 9da5db601..e85d69c59 100644 --- a/docs/source/markdown/podman-container.1.md +++ b/docs/source/markdown/podman-container.1.md @@ -33,6 +33,7 @@ The container command allows you to manage containers | port | [podman-port(1)](podman-port.1.md) | List port mappings for the container. | | prune | [podman-container-prune(1)](podman-container-prune.1.md)| Remove all stopped containers from local storage. | | ps | [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. | +| rename | [podman-rename(1)](podman-rename.1.md) | Rename an existing container. | | restart | [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. | | restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. | | rm | [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. | @@ -42,7 +43,7 @@ The container command allows you to manage containers | stats | [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. | | stop | [podman-stop(1)](podman-stop.1.md) | Stop one or more running containers. | | top | [podman-top(1)](podman-top.1.md) | Display the running processes of a container. | -| unmount | [podman-unmount(1)](podman-unmount.1.md) | Unmount a working container's root filesystem.(Alias unmount) | +| unmount | [podman-unmount(1)](podman-unmount.1.md) | Unmount a working container's root filesystem.(Alias unmount) | | unpause | [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. | | wait | [podman-wait(1)](podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes. | diff --git a/docs/source/markdown/podman-rename.1.md b/docs/source/markdown/podman-rename.1.md new file mode 100644 index 000000000..fdb0dac89 --- /dev/null +++ b/docs/source/markdown/podman-rename.1.md @@ -0,0 +1,38 @@ +% podman-rename(1) + +## NAME +podman\-rename - Rename an existing container + +## SYNOPSIS +**podman rename** *container* *newname* + +**podman container rename** *container* *newname* + +## DESCRIPTION +Rename changes the name of an existing container. +The old name will be freed, and will be available for use. +This command can be run on containers in any state. +However, running containers may not fully receive the effects until they are restarted - for example, a running container may still use the old name in its logs. +At present, only containers are supported; pods and volumes cannot be renamed. + +## OPTIONS + +## EXAMPLES + +``` +# Rename a container by name +$ podman rename oldContainer aNewName +``` + +``` +# Rename a container by ID +$ podman rename 717716c00a6b testcontainer +``` + +``` +# Use the container rename alias +$ podman container rename 6e7514b47180 databaseCtr +``` + +## SEE ALSO +podman(1), podman-create(1), podman-run(1) diff --git a/docs/source/markdown/podman-volume-create.1.md b/docs/source/markdown/podman-volume-create.1.md index 118f024df..a06411000 100644 --- a/docs/source/markdown/podman-volume-create.1.md +++ b/docs/source/markdown/podman-volume-create.1.md @@ -17,7 +17,7 @@ driver options can be set using the **--opt** flag. #### **--driver**=*driver* -Specify the volume driver name (default local). +Specify the volume driver name (default **local**). Setting this to a value other than **local** Podman will attempt to create the volume using a volume plugin with the given name. Such plugins must be defined in the **volume_plugins** section of the **containers.conf**(5) configuration file. #### **--help** @@ -30,13 +30,14 @@ Set metadata for a volume (e.g., --label mykey=value). #### **--opt**=*option*, **-o** Set driver specific options. -For the default driver, `local`, this allows a volume to be configured to mount a filesystem on the host. +For the default driver, **local**, this allows a volume to be configured to mount a filesystem on the host. For the `local` driver the following options are supported: `type`, `device`, and `o`. The `type` option sets the type of the filesystem to be mounted, and is equivalent to the `-t` flag to **mount(8)**. The `device` option sets the device to be mounted, and is equivalent to the `device` argument to **mount(8)**. The `o` option sets options for the mount, and is equivalent to the `-o` flag to **mount(8)** with two exceptions. The `o` option supports `uid` and `gid` options to set the UID and GID of the created volume that are not normally supported by **mount(8)**. -Using volume options with the `local` driver requires root privileges. +Using volume options with the **local** driver requires root privileges. +When not using the **local** driver, the given options will be passed directly to the volume plugin. In this case, supported options will be dictated by the plugin in question, not Podman. ## EXAMPLES @@ -53,7 +54,8 @@ $ podman volume create --label foo=bar myvol ``` ## SEE ALSO -podman-volume(1), mount(8) +**podman-volume**(1), **mount**(8), **containers.conf**(5) ## HISTORY +January 2020, updated with information on volume plugins by Matthew Heon <mheon@redhat.com> November 2018, Originally compiled by Urvashi Mohnani <umohnani@redhat.com> diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 42054d075..67484c3ec 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -247,6 +247,7 @@ the exit codes follow the `chroot` standard, see below: | [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. | | [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. | | [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. | +| [podman-rename(1)](podman-rename.1.md) | Rename an existing container. | | [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. | | [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. | | [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. | @@ -259,7 +260,7 @@ the exit codes follow the `chroot` standard, see below: | [podman-system(1)](podman-system.1.md) | Manage podman. | | [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. | | [podman-top(1)](podman-top.1.md) | Display the running processes of a container. | -| [podman-unmount(1)](podman-unmount.1.md) | Unmount a working container's root filesystem. | +| [podman-unmount(1)](podman-unmount.1.md) | Unmount a working container's root filesystem. | | [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. | | [podman-unshare(1)](podman-unshare.1.md) | Run a command inside of a modified user namespace. | | [podman-untag(1)](podman-untag.1.md) | Removes one or more names from a locally-stored image. | @@ -17,7 +17,7 @@ require ( github.com/containers/psgo v1.5.2 github.com/containers/storage v1.24.5 github.com/coreos/go-systemd/v22 v22.1.0 - github.com/cri-o/ocicni v0.2.1-0.20201125151022-df072ea5421c + github.com/cri-o/ocicni v0.2.1-0.20201204103948-b6cbe99b9756 github.com/cyphar/filepath-securejoin v0.2.2 github.com/davecgh/go-spew v1.1.1 github.com/docker/distribution v2.7.1+incompatible @@ -62,7 +62,7 @@ require ( go.uber.org/atomic v1.7.0 // indirect golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 + golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3 google.golang.org/appengine v1.6.6 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect @@ -131,8 +131,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cri-o/ocicni v0.2.1-0.20201125151022-df072ea5421c h1:iGaCU6d3oVT0pl8tmvyDhoA/vTDL3IX08akfsKZIy9o= -github.com/cri-o/ocicni v0.2.1-0.20201125151022-df072ea5421c/go.mod h1:vingr1ztOAzP2WyTgGbpMov9dFhbjNxdLtDv0+PhAvY= +github.com/cri-o/ocicni v0.2.1-0.20201204103948-b6cbe99b9756 h1:4T3rzrCSvMgVTR+fm526d+Ed0BurAHGjOaaNFOVoK6E= +github.com/cri-o/ocicni v0.2.1-0.20201204103948-b6cbe99b9756/go.mod h1:vingr1ztOAzP2WyTgGbpMov9dFhbjNxdLtDv0+PhAvY= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= @@ -666,8 +666,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index dcb2ff751..b2ee63b08 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -304,6 +304,7 @@ func (s *BoltState) Refresh() error { // Reset mount count to 0 oldState.MountCount = 0 + oldState.MountPoint = "" newState, err := json.Marshal(oldState) if err != nil { diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go index c06fedd3e..6014fbef3 100644 --- a/libpod/boltdb_state_internal.go +++ b/libpod/boltdb_state_internal.go @@ -497,6 +497,21 @@ func (s *BoltState) getVolumeFromDB(name []byte, volume *Volume, volBkt *bolt.Bu } } + // Retrieve volume driver + if volume.UsesVolumeDriver() { + plugin, err := s.runtime.getVolumePlugin(volume.config.Driver) + if err != nil { + // We want to fail gracefully here, to ensure that we + // can still remove volumes even if their plugin is + // missing. Otherwise, we end up with volumes that + // cannot even be retrieved from the database and will + // cause things like `volume ls` to fail. + logrus.Errorf("Volume %s uses volume plugin %s, but it cannot be accessed - some functionality may not be available: %v", volume.Name(), volume.config.Driver, err) + } else { + volume.plugin = plugin + } + } + // Get the lock lock, err := s.runtime.lockManager.RetrieveLock(volume.config.LockID) if err != nil { diff --git a/libpod/container_api.go b/libpod/container_api.go index 87ff764e3..0d62a2dd7 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -210,7 +210,13 @@ func (c *Container) Kill(signal uint) error { } // TODO: Is killing a paused container OK? - if c.state.State != define.ContainerStateRunning { + switch c.state.State { + case define.ContainerStateRunning, define.ContainerStateStopping: + // Note that killing containers in "stopping" state is okay. + // In that state, the Podman is waiting for the runtime to + // stop the container and if that is taking too long, a user + // may have decided to kill the container after all. + default: return errors.Wrapf(define.ErrCtrStateInvalid, "can only kill running containers. %s is in state %s", c.ID(), c.state.State.String()) } @@ -539,7 +545,7 @@ func (c *Container) Cleanup(ctx context.Context) error { } // Check if state is good - if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateCreated, define.ContainerStateStopped, define.ContainerStateExited) { + if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateCreated, define.ContainerStateStopped, define.ContainerStateStopping, define.ContainerStateExited) { return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is running or paused, refusing to clean up", c.ID()) } diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 870d92ca9..ac7eae56b 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -212,7 +212,12 @@ func (c *Container) getInspectMounts(namedVolumes []*ContainerNamedVolume, image return nil, errors.Wrapf(err, "error looking up volume %s in container %s config", volume.Name, c.ID()) } mountStruct.Driver = volFromDB.Driver() - mountStruct.Source = volFromDB.MountPoint() + + mountPoint, err := volFromDB.MountPoint() + if err != nil { + return nil, err + } + mountStruct.Source = mountPoint parseMountOptionsForInspect(volume.Options, &mountStruct) diff --git a/libpod/container_internal.go b/libpod/container_internal.go index f4cdb749f..b9ea50783 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -764,7 +764,7 @@ func (c *Container) isStopped() (bool, error) { return true, err } - return !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused), nil + return !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopping), nil } // save container state to the database @@ -1290,10 +1290,49 @@ func (c *Container) stop(timeout uint) error { return err } + // Set the container state to "stopping" and unlock the container + // before handing it over to conmon to unblock other commands. #8501 + // demonstrates nicely that a high stop timeout will block even simple + // commands such as `podman ps` from progressing if the container lock + // is held when busy-waiting for the container to be stopped. + c.state.State = define.ContainerStateStopping + if err := c.save(); err != nil { + return errors.Wrapf(err, "error saving container %s state before stopping", c.ID()) + } + if !c.batched { + c.lock.Unlock() + } + if err := c.ociRuntime.StopContainer(c, timeout, all); err != nil { return err } + if !c.batched { + c.lock.Lock() + if err := c.syncContainer(); err != nil { + switch errors.Cause(err) { + // If the container has already been removed (e.g., via + // the cleanup process), there's nothing left to do. + case define.ErrNoSuchCtr, define.ErrCtrRemoved: + return nil + default: + return err + } + } + } + + // Since we're now subject to a race condition with other processes who + // may have altered the state (and other data), let's check if the + // state has changed. If so, we should return immediately and log a + // warning. + if c.state.State != define.ContainerStateStopping { + logrus.Warnf( + "Container %q state changed from %q to %q while waiting for it to be stopped: discontinuing stop procedure as another process interfered", + c.ID(), define.ContainerStateStopping, c.state.State, + ) + return nil + } + c.newContainerEvent(events.Stop) c.state.PID = 0 @@ -1541,8 +1580,18 @@ func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string) return nil, err } + // HACK HACK HACK - copy up into a volume driver is 100% broken + // right now. + if vol.UsesVolumeDriver() { + logrus.Infof("Not copying up into volume %s as it uses a volume driver", vol.Name()) + return vol, nil + } + // If the volume is not empty, we should not copy up. - volMount := vol.MountPoint() + volMount, err := vol.MountPoint() + if err != nil { + return nil, err + } contents, err := ioutil.ReadDir(volMount) if err != nil { return nil, errors.Wrapf(err, "error listing contents of volume %s mountpoint when copying up from container %s", vol.Name(), c.ID()) @@ -1580,7 +1629,11 @@ func (c *Container) chownVolume(volumeName string) error { return err } - if vol.state.NeedsChown { + // TODO: For now, I've disabled chowning volumes owned by non-Podman + // drivers. This may be safe, but it's really going to be a case-by-case + // thing, I think - safest to leave disabled now and reenable later if + // there is a demand. + if vol.state.NeedsChown && !vol.UsesVolumeDriver() { vol.state.NeedsChown = false uid := int(c.config.Spec.Process.User.UID) @@ -1607,7 +1660,10 @@ func (c *Container) chownVolume(volumeName string) error { return err } - mountPoint := vol.MountPoint() + mountPoint, err := vol.MountPoint() + if err != nil { + return err + } if err := os.Lchown(mountPoint, uid, gid); err != nil { return err @@ -2116,7 +2172,7 @@ func (c *Container) sortUserVolumes(ctrSpec *spec.Spec) ([]*ContainerNamedVolume // Check for an exit file, and handle one if present func (c *Container) checkExitFile() error { // If the container's not running, nothing to do. - if !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) { + if !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopping) { return nil } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index ce2b52234..0553cc59c 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -341,7 +341,10 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { if err != nil { return nil, errors.Wrapf(err, "error retrieving volume %s to add to container %s", namedVol.Name, c.ID()) } - mountPoint := volume.MountPoint() + mountPoint, err := volume.MountPoint() + if err != nil { + return nil, err + } volMount := spec.Mount{ Type: "bind", Source: mountPoint, @@ -903,7 +906,15 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error { return err } - input, err := archive.TarWithOptions(volume.MountPoint(), &archive.TarOptions{ + mp, err := volume.MountPoint() + if err != nil { + return err + } + if mp == "" { + return errors.Wrapf(define.ErrInternal, "volume %s is not mounted, cannot export", volume.Name()) + } + + input, err := archive.TarWithOptions(mp, &archive.TarOptions{ Compression: archive.Uncompressed, IncludeSourceDir: true, }) @@ -958,10 +969,10 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error { func (c *Container) checkpointRestoreSupported() error { if !criu.CheckForCriu() { - return errors.Errorf("Checkpoint/Restore requires at least CRIU %d", criu.MinCriuVersion) + return errors.Errorf("checkpoint/restore requires at least CRIU %d", criu.MinCriuVersion) } if !c.ociRuntime.SupportsCheckpoint() { - return errors.Errorf("Configured runtime does not support checkpoint/restore") + return errors.Errorf("configured runtime does not support checkpoint/restore") } return nil } @@ -993,7 +1004,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO } if c.AutoRemove() && options.TargetFile == "" { - return errors.Errorf("Cannot checkpoint containers that have been started with '--rm' unless '--export' is used") + return errors.Errorf("cannot checkpoint containers that have been started with '--rm' unless '--export' is used") } if err := c.checkpointRestoreLabelLog("dump.log"); err != nil { @@ -1079,13 +1090,13 @@ func (c *Container) importCheckpoint(input string) error { } err = archive.Untar(archiveFile, c.bundlePath(), options) if err != nil { - return errors.Wrapf(err, "Unpacking of checkpoint archive %s failed", input) + return errors.Wrapf(err, "unpacking of checkpoint archive %s failed", input) } // Make sure the newly created config.json exists on disk g := generate.Generator{Config: c.config.Spec} if err = c.saveSpec(g.Config); err != nil { - return errors.Wrap(err, "Saving imported container specification for restore failed") + return errors.Wrap(err, "saving imported container specification for restore failed") } return nil @@ -1130,7 +1141,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti // Let's try to stat() CRIU's inventory file. If it does not exist, it makes // no sense to try a restore. This is a minimal check if a checkpoint exist. if _, err := os.Stat(filepath.Join(c.CheckpointPath(), "inventory.img")); os.IsNotExist(err) { - return errors.Wrapf(err, "A complete checkpoint for this container cannot be found, cannot restore") + return errors.Wrapf(err, "a complete checkpoint for this container cannot be found, cannot restore") } if err := c.checkpointRestoreLabelLog("restore.log"); err != nil { @@ -1286,16 +1297,22 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti volumeFile, err := os.Open(volumeFilePath) if err != nil { - return errors.Wrapf(err, "Failed to open volume file %s", volumeFilePath) + return errors.Wrapf(err, "failed to open volume file %s", volumeFilePath) } defer volumeFile.Close() volume, err := c.runtime.GetVolume(v.Name) if err != nil { - return errors.Wrapf(err, "Failed to retrieve volume %s", v.Name) + return errors.Wrapf(err, "failed to retrieve volume %s", v.Name) } - mountPoint := volume.MountPoint() + mountPoint, err := volume.MountPoint() + if err != nil { + return err + } + if mountPoint == "" { + return errors.Wrapf(err, "unable to import volume %s as it is not mounted", volume.Name()) + } if err := archive.UntarUncompressed(volumeFile, mountPoint, nil); err != nil { return errors.Wrapf(err, "Failed to extract volume %s to %s", volumeFilePath, mountPoint) } diff --git a/libpod/define/containerstate.go b/libpod/define/containerstate.go index 825e77387..5d2bc9099 100644 --- a/libpod/define/containerstate.go +++ b/libpod/define/containerstate.go @@ -28,6 +28,9 @@ const ( // ContainerStateRemoving indicates the container is in the process of // being removed. ContainerStateRemoving ContainerStatus = iota + // ContainerStateStopping indicates the container is in the process of + // being stopped. + ContainerStateStopping ContainerStatus = iota ) // ContainerStatus returns a string representation for users @@ -50,6 +53,8 @@ func (t ContainerStatus) String() string { return "exited" case ContainerStateRemoving: return "removing" + case ContainerStateStopping: + return "stopping" } return "bad state" } diff --git a/libpod/define/errors.go b/libpod/define/errors.go index 568f8e88d..d37bc397e 100644 --- a/libpod/define/errors.go +++ b/libpod/define/errors.go @@ -35,6 +35,10 @@ var ( // aliases. ErrNoAliases = errors.New("no aliases for container") + // ErrMissingPlugin indicates that the requested operation requires a + // plugin that is not present on the system or in the configuration. + ErrMissingPlugin = errors.New("required plugin missing") + // ErrCtrExists indicates a container with the same name or ID already // exists ErrCtrExists = errors.New("container already exists") diff --git a/libpod/define/volume_inspect.go b/libpod/define/volume_inspect.go new file mode 100644 index 000000000..20602ea16 --- /dev/null +++ b/libpod/define/volume_inspect.go @@ -0,0 +1,51 @@ +package define + +import ( + "time" +) + +// InspectVolumeData is the output of Inspect() on a volume. It is matched to +// the format of 'docker volume inspect'. +type InspectVolumeData struct { + // Name is the name of the volume. + Name string `json:"Name"` + // Driver is the driver used to create the volume. + // If set to "local" or "", the Local driver (Podman built-in code) is + // used to service the volume; otherwise, a volume plugin with the given + // name is used to mount and manage the volume. + Driver string `json:"Driver"` + // Mountpoint is the path on the host where the volume is mounted. + Mountpoint string `json:"Mountpoint"` + // CreatedAt is the date and time the volume was created at. This is not + // stored for older Libpod volumes; if so, it will be omitted. + CreatedAt time.Time `json:"CreatedAt,omitempty"` + // Status is used to return information on the volume's current state, + // if the volume was created using a volume plugin (uses a Driver that + // is not the local driver). + // Status is provided to us by an external program, so no guarantees are + // made about its format or contents. Further, it is an optional field, + // so it may not be set even in cases where a volume plugin is in use. + Status map[string]interface{} `json:"Status,omitempty"` + // Labels includes the volume's configured labels, key:value pairs that + // can be passed during volume creation to provide information for third + // party tools. + Labels map[string]string `json:"Labels"` + // Scope is unused and provided solely for Docker compatibility. It is + // unconditionally set to "local". + Scope string `json:"Scope"` + // Options is a set of options that were used when creating the volume. + // For the Local driver, these are mount options that will be used to + // determine how a local filesystem is mounted; they are handled as + // parameters to Mount in a manner described in the volume create + // manpage. + // For non-local drivers, these are passed as-is to the volume plugin. + Options map[string]string `json:"Options"` + // UID is the UID that the volume was created with. + UID int `json:"UID,omitempty"` + // GID is the GID that the volume was created with. + GID int `json:"GID,omitempty"` + // Anonymous indicates that the volume was created as an anonymous + // volume for a specific container, and will be be removed when any + // container using it is removed. + Anonymous bool `json:"Anonymous,omitempty"` +} diff --git a/libpod/options.go b/libpod/options.go index 31c0b9ac9..c7bac7e1f 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1549,17 +1549,6 @@ func WithVolumeDriver(driver string) VolumeCreateOption { return define.ErrVolumeFinalized } - // Uncomment when volume plugins are ready for use. - // if driver != define.VolumeDriverLocal { - // if _, err := plugin.GetVolumePlugin(driver); err != nil { - // return err - // } - // } - - if driver != define.VolumeDriverLocal { - return define.ErrNotImplemented - } - volume.config.Driver = driver return nil } diff --git a/libpod/plugin/volume_api.go b/libpod/plugin/volume_api.go index 2500a4f36..c5dec651c 100644 --- a/libpod/plugin/volume_api.go +++ b/libpod/plugin/volume_api.go @@ -2,8 +2,9 @@ package plugin import ( "bytes" - "fmt" + "context" "io/ioutil" + "net" "net/http" "os" "path/filepath" @@ -43,7 +44,6 @@ var ( const ( defaultTimeout = 5 * time.Second - defaultPath = "/run/docker/plugins" volumePluginType = "VolumeDriver" ) @@ -64,6 +64,8 @@ type VolumePlugin struct { Name string // SocketPath is the unix socket at which the plugin is accessed. SocketPath string + // Client is the HTTP client we use to connect to the plugin. + Client *http.Client } // This is the response from the activate endpoint of the API. @@ -76,7 +78,7 @@ type activateResponse struct { func validatePlugin(newPlugin *VolumePlugin) error { // It's a socket. Is it a plugin? // Hit the Activate endpoint to find out if it is, and if so what kind - req, err := http.NewRequest("POST", activatePath, nil) + req, err := http.NewRequest("POST", "http://plugin"+activatePath, nil) if err != nil { return errors.Wrapf(err, "error making request to volume plugin %s activation endpoint", newPlugin.Name) } @@ -84,9 +86,7 @@ func validatePlugin(newPlugin *VolumePlugin) error { req.Header.Set("Host", newPlugin.getURI()) req.Header.Set("Content-Type", sdk.DefaultContentTypeV1_1) - client := new(http.Client) - client.Timeout = defaultTimeout - resp, err := client.Do(req) + resp, err := newPlugin.Client.Do(req) if err != nil { return errors.Wrapf(err, "error sending request to plugin %s activation endpoint", newPlugin.Name) } @@ -121,22 +121,28 @@ func validatePlugin(newPlugin *VolumePlugin) error { return errors.Wrapf(ErrNotVolumePlugin, "plugin %s does not implement volume plugin, instead provides %s", newPlugin.Name, strings.Join(respStruct.Implements, ", ")) } + if plugins == nil { + plugins = make(map[string]*VolumePlugin) + } + plugins[newPlugin.Name] = newPlugin return nil } -// GetVolumePlugin gets a single volume plugin by path. -// TODO: We should not be auto-completing based on a default path; we should -// require volumes to have been pre-specified in containers.conf (will need a -// function to pre-populate the plugins list, and we should probably do a lazy -// initialization there to not slow things down too much). -func GetVolumePlugin(name string) (*VolumePlugin, error) { +// GetVolumePlugin gets a single volume plugin, with the given name, at the +// given path. +func GetVolumePlugin(name string, path string) (*VolumePlugin, error) { pluginsLock.Lock() defer pluginsLock.Unlock() plugin, exists := plugins[name] if exists { + // This shouldn't be possible, but just in case... + if plugin.SocketPath != filepath.Clean(path) { + return nil, errors.Wrapf(define.ErrInvalidArg, "requested path %q for volume plugin %s does not match pre-existing path for plugin, %q", path, name, plugin.SocketPath) + } + return plugin, nil } @@ -144,7 +150,20 @@ func GetVolumePlugin(name string) (*VolumePlugin, error) { newPlugin := new(VolumePlugin) newPlugin.Name = name - newPlugin.SocketPath = filepath.Join(defaultPath, fmt.Sprintf("%s.sock", name)) + newPlugin.SocketPath = filepath.Clean(path) + + // Need an HTTP client to force a Unix connection. + // And since we can reuse it, might as well cache it. + client := new(http.Client) + client.Timeout = defaultTimeout + // This bit borrowed from pkg/bindings/connection.go + client.Transport = &http.Transport{ + DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { + return (&net.Dialer{}).DialContext(ctx, "unix", newPlugin.SocketPath) + }, + DisableCompression: true, + } + newPlugin.Client = client stat, err := os.Stat(newPlugin.SocketPath) if err != nil { @@ -183,6 +202,7 @@ func (p *VolumePlugin) verifyReachable() error { } // Send a request to the volume plugin for handling. +// Callers *MUST* close the response when they are done. func (p *VolumePlugin) sendRequest(toJSON interface{}, hasBody bool, endpoint string) (*http.Response, error) { var ( reqJSON []byte @@ -196,7 +216,7 @@ func (p *VolumePlugin) sendRequest(toJSON interface{}, hasBody bool, endpoint st } } - req, err := http.NewRequest("POST", endpoint, bytes.NewReader(reqJSON)) + req, err := http.NewRequest("POST", "http://plugin"+endpoint, bytes.NewReader(reqJSON)) if err != nil { return nil, errors.Wrapf(err, "error making request to volume plugin %s endpoint %s", p.Name, endpoint) } @@ -204,13 +224,12 @@ func (p *VolumePlugin) sendRequest(toJSON interface{}, hasBody bool, endpoint st req.Header.Set("Host", p.getURI()) req.Header.Set("Content-Type", sdk.DefaultContentTypeV1_1) - client := new(http.Client) - client.Timeout = defaultTimeout - resp, err := client.Do(req) + resp, err := p.Client.Do(req) if err != nil { return nil, errors.Wrapf(err, "error sending request to volume plugin %s endpoint %s", p.Name, endpoint) } - defer resp.Body.Close() + // We are *deliberately not closing* response here. It is the + // responsibility of the caller to do so after reading the response. return resp, nil } diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go index ce8a87759..9a980750f 100644 --- a/libpod/rootless_cni_linux.go +++ b/libpod/rootless_cni_linux.go @@ -110,6 +110,8 @@ func DeallocRootlessCNI(ctx context.Context, c *Container) error { logrus.Warn(err) } logrus.Debugf("rootless CNI: removing infra container %q", infra.ID()) + infra.lock.Lock() + defer infra.lock.Unlock() if err := c.runtime.removeContainer(ctx, infra, true, false, true); err != nil { return err } diff --git a/libpod/runtime.go b/libpod/runtime.go index 1004e4fa7..34c737a67 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -17,6 +17,7 @@ import ( "github.com/containers/podman/v2/libpod/events" "github.com/containers/podman/v2/libpod/image" "github.com/containers/podman/v2/libpod/lock" + "github.com/containers/podman/v2/libpod/plugin" "github.com/containers/podman/v2/libpod/shutdown" "github.com/containers/podman/v2/pkg/cgroups" "github.com/containers/podman/v2/pkg/registries" @@ -888,3 +889,18 @@ func (r *Runtime) reloadStorageConf() error { logrus.Infof("applied new storage configuration: %v", r.storageConfig) return nil } + +// getVolumePlugin gets a specific volume plugin given its name. +func (r *Runtime) getVolumePlugin(name string) (*plugin.VolumePlugin, error) { + // There is no plugin for local. + if name == define.VolumeDriverLocal || name == "" { + return nil, nil + } + + pluginPath, ok := r.config.Engine.VolumePlugins[name] + if !ok { + return nil, errors.Wrapf(define.ErrMissingPlugin, "no volume plugin with name %s available", name) + } + + return plugin.GetVolumePlugin(name, pluginPath) +} diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index f22e48746..d2bcd8db3 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -72,6 +72,140 @@ func (r *Runtime) RestoreContainer(ctx context.Context, rSpec *spec.Spec, config return r.setupContainer(ctx, ctr) } +// RenameContainer renames the given container. +// The given container object will be rendered unusable, and a new, renamed +// Container will be returned. +func (r *Runtime) RenameContainer(ctx context.Context, ctr *Container, newName string) (*Container, error) { + ctr.lock.Lock() + defer ctr.lock.Unlock() + + if err := ctr.syncContainer(); err != nil { + return nil, err + } + + if newName == "" || !define.NameRegex.MatchString(newName) { + return nil, define.RegexError + } + + // Check if the name is available. + // This is *100% NOT ATOMIC* so any failures in-flight will do + // *VERY BAD THINGS* to the state. So we have to try and catch all we + // can before starting. + if _, err := r.state.LookupContainerID(newName); err == nil { + return nil, errors.Wrapf(define.ErrCtrExists, "name %s is already in use by another container", newName) + } + if _, err := r.state.LookupPod(newName); err == nil { + return nil, errors.Wrapf(define.ErrPodExists, "name %s is already in use by another pod", newName) + } + + // TODO: Investigate if it is possible to remove this limitation. + depCtrs, err := r.state.ContainerInUse(ctr) + if err != nil { + return nil, err + } + if len(depCtrs) > 0 { + return nil, errors.Wrapf(define.ErrCtrExists, "cannot rename container %s as it is in use by other containers: %v", ctr.ID(), strings.Join(depCtrs, ",")) + } + + // We need to pull an updated config, in case another rename fired and + // the config was re-written. + newConf, err := r.state.GetContainerConfig(ctr.ID()) + if err != nil { + return nil, errors.Wrapf(err, "error retrieving container %s configuration from DB to remove", ctr.ID()) + } + ctr.config = newConf + + // TODO: This is going to fail if we have active exec sessions, too. + // Investigate fixing that at a later date. + + var pod *Pod + if ctr.config.Pod != "" { + tmpPod, err := r.state.Pod(ctr.config.Pod) + if err != nil { + return nil, errors.Wrapf(err, "error retrieving container %s pod", ctr.ID()) + } + pod = tmpPod + // Lock pod to ensure it's not removed while we're working + pod.lock.Lock() + defer pod.lock.Unlock() + } + + // Lock all volumes to ensure they are not removed while we're working + volsLocked := make(map[string]bool) + for _, namedVol := range ctr.config.NamedVolumes { + if volsLocked[namedVol.Name] { + continue + } + vol, err := r.state.Volume(namedVol.Name) + if err != nil { + return nil, errors.Wrapf(err, "error retrieving volume used by container %s", ctr.ID()) + } + + volsLocked[vol.Name()] = true + vol.lock.Lock() + defer vol.lock.Unlock() + } + + logrus.Infof("Going to rename container %s from %q to %q", ctr.ID(), ctr.Name(), newName) + + // Step 1: remove the old container. + if pod != nil { + if err := r.state.RemoveContainerFromPod(pod, ctr); err != nil { + return nil, errors.Wrapf(err, "error renaming container %s", ctr.ID()) + } + } else { + if err := r.state.RemoveContainer(ctr); err != nil { + return nil, errors.Wrapf(err, "error renaming container %s", ctr.ID()) + } + } + + // Step 2: Make a new container based on the old one. + // TODO: Should we deep-copy the container config and state, to be safe? + newCtr := new(Container) + newCtr.config = ctr.config + newCtr.state = ctr.state + newCtr.lock = ctr.lock + newCtr.ociRuntime = ctr.ociRuntime + newCtr.runtime = r + newCtr.rootlessSlirpSyncR = ctr.rootlessSlirpSyncR + newCtr.rootlessSlirpSyncW = ctr.rootlessSlirpSyncW + newCtr.rootlessPortSyncR = ctr.rootlessPortSyncR + newCtr.rootlessPortSyncW = ctr.rootlessPortSyncW + + newCtr.valid = true + newCtr.config.Name = newName + + // Step 3: Add that new container to the DB + if pod != nil { + if err := r.state.AddContainerToPod(pod, newCtr); err != nil { + return nil, errors.Wrapf(err, "error renaming container %s", newCtr.ID()) + } + } else { + if err := r.state.AddContainer(newCtr); err != nil { + return nil, errors.Wrapf(err, "error renaming container %s", newCtr.ID()) + } + } + + // Step 4: Save the new container, to force the state to be written to + // the DB. This may not be necessary, depending on DB implementation, + // but let's do it to be safe. + if err := newCtr.save(); err != nil { + return nil, err + } + + // Step 5: rename the container in c/storage. + // This can fail if the name is already in use by a non-Podman + // container. This puts us in a bad spot - we've already renamed the + // container in Podman. We can swap the order, but then we have the + // opposite problem. Atomicity is a real problem here, with no easy + // solution. + if err := r.store.SetNames(newCtr.ID(), []string{newCtr.Name()}); err != nil { + return nil, err + } + + return newCtr, nil +} + func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConfig) (*Container, error) { if rSpec == nil { return nil, errors.Wrapf(define.ErrInvalidArg, "must provide a valid runtime spec to create container") @@ -393,7 +527,7 @@ func (r *Runtime) RemoveContainer(ctx context.Context, c *Container, force bool, // removePod is used only when removing pods. It instructs Podman to ignore // infra container protections, and *not* remove from the database (as pod // remove will handle that). -func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, removeVolume bool, removePod bool) error { +func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, removeVolume, removePod bool) error { span, _ := opentracing.StartSpanFromContext(ctx, "removeContainer") span.SetTag("type", "runtime") defer span.Finish() @@ -406,6 +540,18 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, } } + // We need to refresh container config from the DB, to ensure that any + // changes (e.g. a rename) are picked up before we start removing. + // Since HasContainer above succeeded, we can safely assume the + // container exists. + // This is *very iffy* but it should be OK because the container won't + // exist once we're done. + newConf, err := r.state.GetContainerConfig(c.ID()) + if err != nil { + return errors.Wrapf(err, "error retrieving container %s configuration from DB to remove", c.ID()) + } + c.config = newConf + logrus.Debugf("Removing container %s", c.ID()) // We need to lock the pod before we lock the container. @@ -413,7 +559,6 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, // Don't need to do this in pod removal case - we're evicting the entire // pod. var pod *Pod - var err error runtime := c.runtime if c.config.Pod != "" && !removePod { pod, err = r.state.Pod(c.config.Pod) diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go index 9bf0fd108..4a29f01aa 100644 --- a/libpod/runtime_volume_linux.go +++ b/libpod/runtime_volume_linux.go @@ -11,7 +11,9 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/libpod/events" + volplugin "github.com/containers/podman/v2/libpod/plugin" "github.com/containers/storage/pkg/stringid" + pluginapi "github.com/docker/go-plugins-helpers/volume" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -53,6 +55,14 @@ func (r *Runtime) newVolume(ctx context.Context, options ...VolumeCreateOption) return nil, errors.Wrapf(define.ErrVolumeExists, "volume with name %s already exists", volume.config.Name) } + // Plugin can be nil if driver is local, but that's OK - superfluous + // assignment doesn't hurt much. + plugin, err := r.getVolumePlugin(volume.config.Driver) + if err != nil { + return nil, errors.Wrapf(err, "volume %s uses volume plugin %s but it could not be retrieved", volume.config.Name, volume.config.Driver) + } + volume.plugin = plugin + if volume.config.Driver == define.VolumeDriverLocal { logrus.Debugf("Validating options for local driver") // Validate options @@ -66,25 +76,38 @@ func (r *Runtime) newVolume(ctx context.Context, options ...VolumeCreateOption) } } - // Create the mountpoint of this volume - volPathRoot := filepath.Join(r.config.Engine.VolumePath, volume.config.Name) - if err := os.MkdirAll(volPathRoot, 0700); err != nil { - return nil, errors.Wrapf(err, "error creating volume directory %q", volPathRoot) - } - if err := os.Chown(volPathRoot, volume.config.UID, volume.config.GID); err != nil { - return nil, errors.Wrapf(err, "error chowning volume directory %q to %d:%d", volPathRoot, volume.config.UID, volume.config.GID) - } - fullVolPath := filepath.Join(volPathRoot, "_data") - if err := os.MkdirAll(fullVolPath, 0755); err != nil { - return nil, errors.Wrapf(err, "error creating volume directory %q", fullVolPath) - } - if err := os.Chown(fullVolPath, volume.config.UID, volume.config.GID); err != nil { - return nil, errors.Wrapf(err, "error chowning volume directory %q to %d:%d", fullVolPath, volume.config.UID, volume.config.GID) - } - if err := LabelVolumePath(fullVolPath); err != nil { - return nil, err + // Now we get conditional: we either need to make the volume in the + // volume plugin, or on disk if not using a plugin. + if volume.plugin != nil { + // We can't chown, or relabel, or similar the path the volume is + // using, because it's not managed by us. + // TODO: reevaluate this once we actually have volume plugins in + // use in production - it may be safe, but I can't tell without + // knowing what the actual plugin does... + if err := makeVolumeInPluginIfNotExist(volume.config.Name, volume.config.Options, volume.plugin); err != nil { + return nil, err + } + } else { + // Create the mountpoint of this volume + volPathRoot := filepath.Join(r.config.Engine.VolumePath, volume.config.Name) + if err := os.MkdirAll(volPathRoot, 0700); err != nil { + return nil, errors.Wrapf(err, "error creating volume directory %q", volPathRoot) + } + if err := os.Chown(volPathRoot, volume.config.UID, volume.config.GID); err != nil { + return nil, errors.Wrapf(err, "error chowning volume directory %q to %d:%d", volPathRoot, volume.config.UID, volume.config.GID) + } + fullVolPath := filepath.Join(volPathRoot, "_data") + if err := os.MkdirAll(fullVolPath, 0755); err != nil { + return nil, errors.Wrapf(err, "error creating volume directory %q", fullVolPath) + } + if err := os.Chown(fullVolPath, volume.config.UID, volume.config.GID); err != nil { + return nil, errors.Wrapf(err, "error chowning volume directory %q to %d:%d", fullVolPath, volume.config.UID, volume.config.GID) + } + if err := LabelVolumePath(fullVolPath); err != nil { + return nil, err + } + volume.config.MountPoint = fullVolPath } - volume.config.MountPoint = fullVolPath lock, err := r.lockManager.AllocateLock() if err != nil { @@ -111,6 +134,39 @@ func (r *Runtime) newVolume(ctx context.Context, options ...VolumeCreateOption) return volume, nil } +// makeVolumeInPluginIfNotExist makes a volume in the given volume plugin if it +// does not already exist. +func makeVolumeInPluginIfNotExist(name string, options map[string]string, plugin *volplugin.VolumePlugin) error { + // Ping the volume plugin to see if it exists first. + // If it does, use the existing volume in the plugin. + // Options may not match exactly, but not much we can do about + // that. Not complaining avoids a lot of the sync issues we see + // with c/storage and libpod DB. + needsCreate := true + getReq := new(pluginapi.GetRequest) + getReq.Name = name + if resp, err := plugin.GetVolume(getReq); err == nil { + // TODO: What do we do if we get a 200 response, but the + // Volume is nil? The docs on the Plugin API are very + // nonspecific, so I don't know if this is valid or + // not... + if resp != nil { + needsCreate = false + logrus.Infof("Volume %q already exists in plugin %q, using existing volume", name, plugin.Name) + } + } + if needsCreate { + createReq := new(pluginapi.CreateRequest) + createReq.Name = name + createReq.Options = options + if err := plugin.CreateVolume(createReq); err != nil { + return errors.Wrapf(err, "error creating volume %q in plugin %s", name, plugin.Name) + } + } + + return nil +} + // removeVolume removes the specified volume from state as well tears down its mountpoint and storage func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error { if !v.valid { @@ -185,9 +241,43 @@ func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error var removalErr error + // If we use a volume plugin, we need to remove from the plugin. + if v.UsesVolumeDriver() { + canRemove := true + + // Do we have a volume driver? + if v.plugin == nil { + canRemove = false + removalErr = errors.Wrapf(define.ErrMissingPlugin, "cannot remove volume %s from plugin %s, but it has been removed from Podman", v.Name(), v.Driver()) + } else { + // Ping the plugin first to verify the volume still + // exists. + // We're trying to be very tolerant of missing volumes + // in the backend, to avoid the problems we see with + // sync between c/storage and the Libpod DB. + getReq := new(pluginapi.GetRequest) + getReq.Name = v.Name() + if _, err := v.plugin.GetVolume(getReq); err != nil { + canRemove = false + removalErr = errors.Wrapf(err, "volume %s could not be retrieved from plugin %s, but it has been removed from Podman", v.Name(), v.Driver()) + } + } + if canRemove { + req := new(pluginapi.RemoveRequest) + req.Name = v.Name() + if err := v.plugin.RemoveVolume(req); err != nil { + removalErr = errors.Wrapf(err, "volume %s could not be removed from plugin %s, but it has been removed from Podman", v.Name(), v.Driver()) + } + } + } + // Free the volume's lock if err := v.lock.Free(); err != nil { - removalErr = errors.Wrapf(err, "error freeing lock for volume %s", v.Name()) + if removalErr == nil { + removalErr = errors.Wrapf(err, "error freeing lock for volume %s", v.Name()) + } else { + logrus.Errorf("Error freeing lock for volume %q: %v", v.Name(), err) + } } // Delete the mountpoint path of the volume, that is delete the volume @@ -196,7 +286,7 @@ func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error if removalErr == nil { removalErr = errors.Wrapf(err, "error cleaning up volume storage for %q", v.Name()) } else { - logrus.Errorf("error cleaning up volume storage for volume %q: %v", v.Name(), err) + logrus.Errorf("Error cleaning up volume storage for volume %q: %v", v.Name(), err) } } diff --git a/libpod/volume.go b/libpod/volume.go index ed08d375f..4c137cb8e 100644 --- a/libpod/volume.go +++ b/libpod/volume.go @@ -7,6 +7,7 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/libpod/lock" + "github.com/containers/podman/v2/libpod/plugin" ) // Volume is a libpod named volume. @@ -18,6 +19,7 @@ type Volume struct { state *VolumeState valid bool + plugin *plugin.VolumePlugin runtime *Runtime lock lock.Locker } @@ -31,7 +33,7 @@ type VolumeConfig struct { // Labels for the volume. Labels map[string]string `json:"labels"` // The volume driver. Empty string or local does not activate a volume - // driver, all other volumes will. + // driver, all other values will. Driver string `json:"volumeDriver"` // The location the volume is mounted at. MountPoint string `json:"mountPoint"` @@ -53,6 +55,10 @@ type VolumeConfig struct { // Volumes are not guaranteed to have a state. Only volumes using the Local // driver that have mount options set will create a state. type VolumeState struct { + // Mountpoint is the location where the volume was mounted. + // This is only used for volumes using a volume plugin, which will mount + // at non-standard locations. + MountPoint string `json:"mountPoint,omitempty"` // MountCount is the number of times this volume has been requested to // be mounted. // It is incremented on mount() and decremented on unmount(). @@ -115,8 +121,20 @@ func (v *Volume) Labels() map[string]string { } // MountPoint returns the volume's mountpoint on the host -func (v *Volume) MountPoint() string { - return v.config.MountPoint +func (v *Volume) MountPoint() (string, error) { + // For the sake of performance, avoid locking unless we have to. + if v.UsesVolumeDriver() { + v.lock.Lock() + defer v.lock.Unlock() + + if err := v.update(); err != nil { + return "", err + } + + return v.state.MountPoint, nil + } + + return v.config.MountPoint, nil } // Options return the volume's options @@ -139,14 +157,19 @@ func (v *Volume) UID() (int, error) { v.lock.Lock() defer v.lock.Unlock() - if !v.valid { - return -1, define.ErrVolumeRemoved + if err := v.update(); err != nil { + return -1, err } + return v.uid(), nil +} + +// Internal, unlocked accessor for UID. +func (v *Volume) uid() int { if v.state.UIDChowned > 0 { - return v.state.UIDChowned, nil + return v.state.UIDChowned } - return v.config.UID, nil + return v.config.UID } // GID returns the GID the volume will be created as. @@ -154,14 +177,19 @@ func (v *Volume) GID() (int, error) { v.lock.Lock() defer v.lock.Unlock() - if !v.valid { - return -1, define.ErrVolumeRemoved + if err := v.update(); err != nil { + return -1, err } + return v.gid(), nil +} + +// Internal, unlocked accessor for GID. +func (v *Volume) gid() int { if v.state.GIDChowned > 0 { - return v.state.GIDChowned, nil + return v.state.GIDChowned } - return v.config.GID, nil + return v.config.GID } // CreatedTime returns the time the volume was created at. It was not tracked @@ -198,3 +226,10 @@ func (v *Volume) IsDangling() (bool, error) { } return len(ctrs) == 0, nil } + +// UsesVolumeDriver determines whether the volume uses a volume driver. Volume +// drivers are pluggable backends for volumes that will manage the storage and +// mounting. +func (v *Volume) UsesVolumeDriver() bool { + return !(v.config.Driver == define.VolumeDriverLocal || v.config.Driver == "") +} diff --git a/libpod/volume_inspect.go b/libpod/volume_inspect.go index c8b20b8f1..2448d1bb5 100644 --- a/libpod/volume_inspect.go +++ b/libpod/volume_inspect.go @@ -1,60 +1,52 @@ package libpod import ( - "time" - "github.com/containers/podman/v2/libpod/define" + pluginapi "github.com/docker/go-plugins-helpers/volume" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) -// InspectVolumeData is the output of Inspect() on a volume. It is matched to -// the format of 'docker volume inspect'. -type InspectVolumeData struct { - // Name is the name of the volume. - Name string `json:"Name"` - // Driver is the driver used to create the volume. - // This will be properly implemented in a future version. - Driver string `json:"Driver"` - // Mountpoint is the path on the host where the volume is mounted. - Mountpoint string `json:"Mountpoint"` - // CreatedAt is the date and time the volume was created at. This is not - // stored for older Libpod volumes; if so, it will be omitted. - CreatedAt time.Time `json:"CreatedAt,omitempty"` - // Status is presently unused and provided only for Docker compatibility. - // In the future it will be used to return information on the volume's - // current state. - Status map[string]string `json:"Status,omitempty"` - // Labels includes the volume's configured labels, key:value pairs that - // can be passed during volume creation to provide information for third - // party tools. - Labels map[string]string `json:"Labels"` - // Scope is unused and provided solely for Docker compatibility. It is - // unconditionally set to "local". - Scope string `json:"Scope"` - // Options is a set of options that were used when creating the volume. - // It is presently not used. - Options map[string]string `json:"Options"` - // UID is the UID that the volume was created with. - UID int `json:"UID,omitempty"` - // GID is the GID that the volume was created with. - GID int `json:"GID,omitempty"` - // Anonymous indicates that the volume was created as an anonymous - // volume for a specific container, and will be be removed when any - // container using it is removed. - Anonymous bool `json:"Anonymous,omitempty"` -} - // Inspect provides detailed information about the configuration of the given // volume. -func (v *Volume) Inspect() (*InspectVolumeData, error) { +func (v *Volume) Inspect() (*define.InspectVolumeData, error) { if !v.valid { return nil, define.ErrVolumeRemoved } - data := new(InspectVolumeData) + v.lock.Lock() + defer v.lock.Unlock() + + if err := v.update(); err != nil { + return nil, err + } + + data := new(define.InspectVolumeData) + + data.Mountpoint = v.config.MountPoint + if v.UsesVolumeDriver() { + logrus.Debugf("Querying volume plugin %s for status", v.config.Driver) + data.Mountpoint = v.state.MountPoint + + if v.plugin == nil { + return nil, errors.Wrapf(define.ErrMissingPlugin, "volume %s uses volume plugin %s but it is not available, cannot inspect", v.Name(), v.config.Driver) + } + + // Retrieve status for the volume. + // Need to query the volume driver. + req := new(pluginapi.GetRequest) + req.Name = v.Name() + resp, err := v.plugin.GetVolume(req) + if err != nil { + return nil, errors.Wrapf(err, "error retrieving volume %s information from plugin %s", v.Name(), v.Driver()) + } + if resp != nil { + data.Status = resp.Status + } + } data.Name = v.config.Name data.Driver = v.config.Driver - data.Mountpoint = v.config.MountPoint data.CreatedAt = v.config.CreatedTime data.Labels = make(map[string]string) for k, v := range v.config.Labels { @@ -65,15 +57,8 @@ func (v *Volume) Inspect() (*InspectVolumeData, error) { for k, v := range v.config.Options { data.Options[k] = v } - var err error - data.UID, err = v.UID() - if err != nil { - return nil, err - } - data.GID, err = v.GID() - if err != nil { - return nil, err - } + data.UID = v.uid() + data.GID = v.gid() data.Anonymous = v.config.IsAnon return data, nil diff --git a/libpod/volume_internal.go b/libpod/volume_internal.go index 95cb752e0..88d940370 100644 --- a/libpod/volume_internal.go +++ b/libpod/volume_internal.go @@ -22,13 +22,24 @@ func newVolume(runtime *Runtime) *Volume { // teardownStorage deletes the volume from volumePath func (v *Volume) teardownStorage() error { + if v.UsesVolumeDriver() { + return nil + } + + // TODO: Should this be converted to use v.config.MountPoint? return os.RemoveAll(filepath.Join(v.runtime.config.Engine.VolumePath, v.Name())) } // Volumes with options set, or a filesystem type, or a device to mount need to // be mounted and unmounted. func (v *Volume) needsMount() bool { - return len(v.config.Options) > 0 && v.config.Driver == define.VolumeDriverLocal + // Non-local driver always needs mount + if v.UsesVolumeDriver() { + return true + } + + // Local driver with options needs mount + return len(v.config.Options) > 0 } // update() updates the volume state from the DB. diff --git a/libpod/volume_internal_linux.go b/libpod/volume_internal_linux.go index bbf47f124..e184505e7 100644 --- a/libpod/volume_internal_linux.go +++ b/libpod/volume_internal_linux.go @@ -8,11 +8,17 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/rootless" + pluginapi "github.com/docker/go-plugins-helpers/volume" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) +// This is a pseudo-container ID to use when requesting a mount or unmount from +// the volume plugins. +// This is the shas256 of the string "placeholder\n". +const pseudoCtrID = "2f73349cfc4630255319c6c8dfc1b46a8996ace9d14d8e07563b165915918ec2" + // mount mounts the volume if necessary. // A mount is necessary if a volume has any options set. // If a mount is necessary, v.state.MountCount will be incremented. @@ -20,7 +26,7 @@ import ( // host. Otherwise, we assume it is already mounted. // Must be done while the volume is locked. // Is a no-op on volumes that do not require a mount (as defined by -// volumeNeedsMount()) +// volumeNeedsMount()). func (v *Volume) mount() error { if !v.needsMount() { return nil @@ -44,6 +50,28 @@ func (v *Volume) mount() error { return v.save() } + // Volume plugins implement their own mount counter, based on the ID of + // the mounting container. But we already have one, and honestly I trust + // ours more. So hardcode container ID to something reasonable, and use + // the same one for everything. + if v.UsesVolumeDriver() { + if v.plugin == nil { + return errors.Wrapf(define.ErrMissingPlugin, "volume plugin %s (needed by volume %s) missing", v.Driver(), v.Name()) + } + + req := new(pluginapi.MountRequest) + req.Name = v.Name() + req.ID = pseudoCtrID + mountPoint, err := v.plugin.MountVolume(req) + if err != nil { + return err + } + + v.state.MountCount += 1 + v.state.MountPoint = mountPoint + return v.save() + } + volDevice := v.config.Options["device"] volType := v.config.Options["type"] volOptions := v.config.Options["o"] @@ -132,6 +160,22 @@ func (v *Volume) unmount(force bool) error { logrus.Debugf("Volume %s mount count now at %d", v.Name(), v.state.MountCount) if v.state.MountCount == 0 { + if v.UsesVolumeDriver() { + if v.plugin == nil { + return errors.Wrapf(define.ErrMissingPlugin, "volume plugin %s (needed by volume %s) missing", v.Driver(), v.Name()) + } + + req := new(pluginapi.UnmountRequest) + req.Name = v.Name() + req.ID = pseudoCtrID + if err := v.plugin.UnmountVolume(req); err != nil { + return err + } + + v.state.MountPoint = "" + return v.save() + } + // Unmount the volume if err := unix.Unmount(v.config.MountPoint, unix.MNT_DETACH); err != nil { if err == unix.EINVAL { diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 0f89c859e..6e1945db1 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -465,3 +465,34 @@ func formatCapabilities(slice []string) { slice[i] = strings.TrimPrefix(slice[i], "CAP_") } } + +func RenameContainer(w http.ResponseWriter, r *http.Request) { + runtime := r.Context().Value("runtime").(*libpod.Runtime) + decoder := r.Context().Value("decoder").(*schema.Decoder) + + name := utils.GetName(r) + query := struct { + Name string `schema:"name"` + }{} + if err := decoder.Decode(&query, r.URL.Query()); err != nil { + utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + return + } + + ctr, err := runtime.LookupContainer(name) + if err != nil { + utils.ContainerNotFound(w, name, err) + return + } + + if _, err := runtime.RenameContainer(r.Context(), ctr, query.Name); err != nil { + if errors.Cause(err) == define.ErrPodExists || errors.Cause(err) == define.ErrCtrExists { + utils.Error(w, "Something went wrong.", http.StatusConflict, err) + return + } + utils.InternalServerError(w, err) + return + } + + utils.WriteResponse(w, http.StatusNoContent, nil) +} diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go index 4903bbad4..82e70eb90 100644 --- a/pkg/api/handlers/compat/volumes.go +++ b/pkg/api/handlers/compat/volumes.go @@ -58,10 +58,15 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) { } volumeConfigs := make([]*docker_api_types.Volume, 0, len(vols)) for _, v := range vols { + mp, err := v.MountPoint() + if err != nil { + utils.InternalServerError(w, err) + return + } config := docker_api_types.Volume{ Name: v.Name(), Driver: v.Driver(), - Mountpoint: v.MountPoint(), + Mountpoint: mp, CreatedAt: v.CreatedTime().Format(time.RFC3339), Labels: v.Labels(), Scope: v.Scope(), @@ -106,11 +111,16 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { // if using the compat layer and the volume already exists, we // must return a 201 with the same information as create if existingVolume != nil && !utils.IsLibpodRequest(r) { + mp, err := existingVolume.MountPoint() + if err != nil { + utils.InternalServerError(w, err) + return + } response := docker_api_types.Volume{ CreatedAt: existingVolume.CreatedTime().Format(time.RFC3339), Driver: existingVolume.Driver(), Labels: existingVolume.Labels(), - Mountpoint: existingVolume.MountPoint(), + Mountpoint: mp, Name: existingVolume.Name(), Options: existingVolume.Options(), Scope: existingVolume.Scope(), @@ -146,10 +156,15 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } + mp, err := vol.MountPoint() + if err != nil { + utils.InternalServerError(w, err) + return + } volResponse := docker_api_types.Volume{ Name: config.Name, Driver: config.Driver, - Mountpoint: config.MountPoint, + Mountpoint: mp, CreatedAt: config.CreatedTime.Format(time.RFC3339), Labels: config.Labels, Options: config.Options, @@ -173,10 +188,15 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) { utils.VolumeNotFound(w, name, err) return } + mp, err := vol.MountPoint() + if err != nil { + utils.InternalServerError(w, err) + return + } volResponse := docker_api_types.Volume{ Name: vol.Name(), Driver: vol.Driver(), - Mountpoint: vol.MountPoint(), + Mountpoint: mp, CreatedAt: vol.CreatedTime().Format(time.RFC3339), Labels: vol.Labels(), Options: vol.Options(), diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go index 6f9537515..38fdf1b4d 100644 --- a/pkg/api/handlers/libpod/volumes.go +++ b/pkg/api/handlers/libpod/volumes.go @@ -60,20 +60,13 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - config, err := vol.Config() + inspectOut, err := vol.Inspect() if err != nil { utils.InternalServerError(w, err) return } volResponse := entities.VolumeConfigResponse{ - Name: config.Name, - Driver: config.Driver, - Mountpoint: config.MountPoint, - CreatedAt: config.CreatedTime, - Labels: config.Labels, - Options: config.Options, - UID: config.UID, - GID: config.GID, + InspectVolumeData: *inspectOut, } utils.WriteResponse(w, http.StatusCreated, volResponse) } @@ -88,27 +81,13 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) { utils.VolumeNotFound(w, name, err) return } - var uid, gid int - uid, err = vol.UID() + inspectOut, err := vol.Inspect() if err != nil { - utils.Error(w, "Error fetching volume UID", http.StatusInternalServerError, err) - return - } - gid, err = vol.GID() - if err != nil { - utils.Error(w, "Error fetching volume GID", http.StatusInternalServerError, err) + utils.InternalServerError(w, err) return } volResponse := entities.VolumeConfigResponse{ - Name: vol.Name(), - Driver: vol.Driver(), - Mountpoint: vol.MountPoint(), - CreatedAt: vol.CreatedTime(), - Labels: vol.Labels(), - Scope: vol.Scope(), - Options: vol.Options(), - UID: uid, - GID: gid, + InspectVolumeData: *inspectOut, } utils.WriteResponse(w, http.StatusOK, volResponse) } @@ -143,27 +122,13 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) { } volumeConfigs := make([]*entities.VolumeListReport, 0, len(vols)) for _, v := range vols { - var uid, gid int - uid, err = v.UID() + inspectOut, err := v.Inspect() if err != nil { - utils.Error(w, "Error fetching volume UID", http.StatusInternalServerError, err) - return - } - gid, err = v.GID() - if err != nil { - utils.Error(w, "Error fetching volume GID", http.StatusInternalServerError, err) + utils.InternalServerError(w, err) return } config := entities.VolumeConfigResponse{ - Name: v.Name(), - Driver: v.Driver(), - Mountpoint: v.MountPoint(), - CreatedAt: v.CreatedTime(), - Labels: v.Labels(), - Scope: v.Scope(), - Options: v.Options(), - UID: uid, - GID: gid, + InspectVolumeData: *inspectOut, } volumeConfigs = append(volumeConfigs, &entities.VolumeListReport{VolumeConfigResponse: config}) } diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index b80dea545..74a04b2e6 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -291,9 +291,6 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { 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) - r.HandleFunc(VersionedPath("/containers/{name}/rename"), s.APIHandler(compat.UnsupportedHandler)).Methods(http.MethodPost) - // Added non version path to URI to support docker non versioned paths - r.HandleFunc("/containers/{name}/rename", s.APIHandler(compat.UnsupportedHandler)).Methods(http.MethodPost) // swagger:operation POST /containers/{name}/restart compat restartContainer // --- // tags: @@ -610,6 +607,36 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // $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 renameContainer + // --- + // tags: + // - containers (compat) + // summary: Rename an existing container + // description: Change the name of an existing container. + // parameters: + // - in: path + // name: name + // type: string + // required: true + // description: Full or partial ID or full name of the container to rename + // - in: query + // name: name + // type: string + // required: true + // description: New name for the container + // produces: + // - application/json + // responses: + // 204: + // description: no error + // 404: + // $ref: "#/responses/NoSuchContainer" + // 409: + // $ref: "#/responses/ConflictError" + // 500: + // $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) /* libpod endpoints @@ -1463,5 +1490,34 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $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 libpodRenameContainer + // --- + // tags: + // - containers + // summary: Rename an existing container + // description: Change the name of an existing container. + // parameters: + // - in: path + // name: name + // type: string + // required: true + // description: Full or partial ID or full name of the container to rename + // - in: query + // name: name + // type: string + // required: true + // description: New name for the container + // produces: + // - application/json + // responses: + // 204: + // description: no error + // 404: + // $ref: "#/responses/NoSuchContainer" + // 409: + // $ref: "#/responses/ConflictError" + // 500: + // $ref: "#/responses/InternalError" + r.HandleFunc(VersionedPath("/libpod/containers/{name}/rename"), s.APIHandler(compat.RenameContainer)).Methods(http.MethodPost) return nil } diff --git a/pkg/bindings/containers/types_attach_options.go b/pkg/bindings/containers/types_attach_options.go index 4ffb8ab17..6d8c1cb01 100644 --- a/pkg/bindings/containers/types_attach_options.go +++ b/pkg/bindings/containers/types_attach_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:18.566804404 -0600 CST m=+0.000258831 */ // Changed @@ -39,6 +38,7 @@ func (o *AttachOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_checkpoint_options.go b/pkg/bindings/containers/types_checkpoint_options.go index d03dc8231..ec766de4a 100644 --- a/pkg/bindings/containers/types_checkpoint_options.go +++ b/pkg/bindings/containers/types_checkpoint_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:18.714853285 -0600 CST m=+0.000319103 */ // Changed @@ -39,6 +38,7 @@ func (o *CheckpointOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_commit_options.go b/pkg/bindings/containers/types_commit_options.go index a8b215141..b745bebe2 100644 --- a/pkg/bindings/containers/types_commit_options.go +++ b/pkg/bindings/containers/types_commit_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:18.420656951 -0600 CST m=+0.000259662 */ // Changed @@ -39,6 +38,7 @@ func (o *CommitOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_create_options.go b/pkg/bindings/containers/types_create_options.go index 4dbce0203..4b9574cf1 100644 --- a/pkg/bindings/containers/types_create_options.go +++ b/pkg/bindings/containers/types_create_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:19.011789618 -0600 CST m=+0.000259413 */ // Changed @@ -39,6 +38,7 @@ func (o *CreateOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_diff_options.go b/pkg/bindings/containers/types_diff_options.go index be3bbf554..55fa6930d 100644 --- a/pkg/bindings/containers/types_diff_options.go +++ b/pkg/bindings/containers/types_diff_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:19.159128927 -0600 CST m=+0.000255635 */ // Changed @@ -39,6 +38,7 @@ func (o *DiffOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_execinspect_options.go b/pkg/bindings/containers/types_execinspect_options.go index 3c4c870be..c5d1f931a 100644 --- a/pkg/bindings/containers/types_execinspect_options.go +++ b/pkg/bindings/containers/types_execinspect_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:19.303239014 -0600 CST m=+0.000256861 */ // Changed @@ -39,6 +38,7 @@ func (o *ExecInspectOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_execstart_options.go b/pkg/bindings/containers/types_execstart_options.go index 66fdc82cb..9ecb70a3e 100644 --- a/pkg/bindings/containers/types_execstart_options.go +++ b/pkg/bindings/containers/types_execstart_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:19.447714428 -0600 CST m=+0.000257278 */ // Changed @@ -39,6 +38,7 @@ func (o *ExecStartOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_execstartandattach_options.go b/pkg/bindings/containers/types_execstartandattach_options.go index 43900d29d..a5a691e35 100644 --- a/pkg/bindings/containers/types_execstartandattach_options.go +++ b/pkg/bindings/containers/types_execstartandattach_options.go @@ -6,6 +6,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -13,8 +14,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:22.827903078 -0600 CST m=+0.000269906 */ // Changed @@ -41,6 +40,7 @@ func (o *ExecStartAndAttachOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_export_options.go b/pkg/bindings/containers/types_export_options.go index e325bd2cd..55e413c72 100644 --- a/pkg/bindings/containers/types_export_options.go +++ b/pkg/bindings/containers/types_export_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:22.101679998 -0600 CST m=+0.000261669 */ // Changed @@ -39,6 +38,7 @@ func (o *ExportOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_healthcheck_options.go b/pkg/bindings/containers/types_healthcheck_options.go index 8c4300366..9d8b25bf4 100644 --- a/pkg/bindings/containers/types_healthcheck_options.go +++ b/pkg/bindings/containers/types_healthcheck_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:19.593883686 -0600 CST m=+0.000289845 */ // Changed @@ -39,6 +38,7 @@ func (o *HealthCheckOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_init_options.go b/pkg/bindings/containers/types_init_options.go index 655362f62..6fb5795c0 100644 --- a/pkg/bindings/containers/types_init_options.go +++ b/pkg/bindings/containers/types_init_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:22.245077233 -0600 CST m=+0.000255461 */ // Changed @@ -39,6 +38,7 @@ func (o *InitOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_inspect_options.go b/pkg/bindings/containers/types_inspect_options.go index 884f5524d..722372414 100644 --- a/pkg/bindings/containers/types_inspect_options.go +++ b/pkg/bindings/containers/types_inspect_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:20.635987603 -0600 CST m=+0.000260270 */ // Changed @@ -39,6 +38,7 @@ func (o *InspectOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_kill_options.go b/pkg/bindings/containers/types_kill_options.go index 3d6fa6224..dd84f0d9f 100644 --- a/pkg/bindings/containers/types_kill_options.go +++ b/pkg/bindings/containers/types_kill_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:20.781581076 -0600 CST m=+0.000259040 */ // Changed @@ -39,6 +38,7 @@ func (o *KillOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_list_options.go b/pkg/bindings/containers/types_list_options.go index dd74d37b7..43326fa59 100644 --- a/pkg/bindings/containers/types_list_options.go +++ b/pkg/bindings/containers/types_list_options.go @@ -12,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:20.199081744 -0600 CST m=+0.000270626 */ // Changed diff --git a/pkg/bindings/containers/types_log_options.go b/pkg/bindings/containers/types_log_options.go index a6958242f..364f29de4 100644 --- a/pkg/bindings/containers/types_log_options.go +++ b/pkg/bindings/containers/types_log_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:18.273264471 -0600 CST m=+0.000274536 */ // Changed @@ -39,6 +38,7 @@ func (o *LogOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_mount_options.go b/pkg/bindings/containers/types_mount_options.go index c0e253094..6f4349b73 100644 --- a/pkg/bindings/containers/types_mount_options.go +++ b/pkg/bindings/containers/types_mount_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:19.740822464 -0600 CST m=+0.000250074 */ // Changed @@ -39,6 +38,7 @@ func (o *MountOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_mountedcontainerpaths_options.go b/pkg/bindings/containers/types_mountedcontainerpaths_options.go index e368ff131..0d8b69654 100644 --- a/pkg/bindings/containers/types_mountedcontainerpaths_options.go +++ b/pkg/bindings/containers/types_mountedcontainerpaths_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:20.048233253 -0600 CST m=+0.000307223 */ // Changed @@ -39,6 +38,7 @@ func (o *MountedContainerPathsOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_pause_options.go b/pkg/bindings/containers/types_pause_options.go index 26ad86793..0cc65f64e 100644 --- a/pkg/bindings/containers/types_pause_options.go +++ b/pkg/bindings/containers/types_pause_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:20.929891294 -0600 CST m=+0.000261081 */ // Changed @@ -39,6 +38,7 @@ func (o *PauseOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_prune_options.go b/pkg/bindings/containers/types_prune_options.go index e3c0f4de7..10adf0a2a 100644 --- a/pkg/bindings/containers/types_prune_options.go +++ b/pkg/bindings/containers/types_prune_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:20.344278799 -0600 CST m=+0.000263499 */ // Changed @@ -39,6 +38,7 @@ func (o *PruneOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_remove_options.go b/pkg/bindings/containers/types_remove_options.go index 6f59f0ed5..e21fb41f7 100644 --- a/pkg/bindings/containers/types_remove_options.go +++ b/pkg/bindings/containers/types_remove_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:20.489968735 -0600 CST m=+0.000264450 */ // Changed @@ -39,6 +38,7 @@ func (o *RemoveOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_resizeexectty_options.go b/pkg/bindings/containers/types_resizeexectty_options.go index 33bb4e78b..0212adeb2 100644 --- a/pkg/bindings/containers/types_resizeexectty_options.go +++ b/pkg/bindings/containers/types_resizeexectty_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:22.680735758 -0600 CST m=+0.000267081 */ // Changed @@ -39,6 +38,7 @@ func (o *ResizeExecTTYOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_resizetty_options.go b/pkg/bindings/containers/types_resizetty_options.go index 29ec54988..cee607902 100644 --- a/pkg/bindings/containers/types_resizetty_options.go +++ b/pkg/bindings/containers/types_resizetty_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:22.535788375 -0600 CST m=+0.000266528 */ // Changed @@ -39,6 +38,7 @@ func (o *ResizeTTYOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_restart_options.go b/pkg/bindings/containers/types_restart_options.go index 13ac099b1..8dcc6b5b7 100644 --- a/pkg/bindings/containers/types_restart_options.go +++ b/pkg/bindings/containers/types_restart_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:21.076709643 -0600 CST m=+0.000303354 */ // Changed @@ -39,6 +38,7 @@ func (o *RestartOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_restore_options.go b/pkg/bindings/containers/types_restore_options.go index be6e94736..491d678a5 100644 --- a/pkg/bindings/containers/types_restore_options.go +++ b/pkg/bindings/containers/types_restore_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:18.861536405 -0600 CST m=+0.000300026 */ // Changed @@ -39,6 +38,7 @@ func (o *RestoreOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_shouldrestart_options.go b/pkg/bindings/containers/types_shouldrestart_options.go index c833d0d8b..30ab618c7 100644 --- a/pkg/bindings/containers/types_shouldrestart_options.go +++ b/pkg/bindings/containers/types_shouldrestart_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:22.388596051 -0600 CST m=+0.000253693 */ // Changed @@ -39,6 +38,7 @@ func (o *ShouldRestartOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_start_options.go b/pkg/bindings/containers/types_start_options.go index 5918af89b..4050a8993 100644 --- a/pkg/bindings/containers/types_start_options.go +++ b/pkg/bindings/containers/types_start_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:21.221364502 -0600 CST m=+0.000276575 */ // Changed @@ -39,6 +38,7 @@ func (o *StartOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_stats_options.go b/pkg/bindings/containers/types_stats_options.go index f821ea1cd..74f419913 100644 --- a/pkg/bindings/containers/types_stats_options.go +++ b/pkg/bindings/containers/types_stats_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:21.370213399 -0600 CST m=+0.000264334 */ // Changed @@ -39,6 +38,7 @@ func (o *StatsOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_stop_options.go b/pkg/bindings/containers/types_stop_options.go index 14d7633a0..db692dbf0 100644 --- a/pkg/bindings/containers/types_stop_options.go +++ b/pkg/bindings/containers/types_stop_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:21.95469621 -0600 CST m=+0.000261399 */ // Changed @@ -39,6 +38,7 @@ func (o *StopOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_top_options.go b/pkg/bindings/containers/types_top_options.go index 95a1ee686..5f2717c28 100644 --- a/pkg/bindings/containers/types_top_options.go +++ b/pkg/bindings/containers/types_top_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:21.515867629 -0600 CST m=+0.000257106 */ // Changed @@ -39,6 +38,7 @@ func (o *TopOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_unmount_options.go b/pkg/bindings/containers/types_unmount_options.go index a29bd8216..060327c4a 100644 --- a/pkg/bindings/containers/types_unmount_options.go +++ b/pkg/bindings/containers/types_unmount_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:19.891657824 -0600 CST m=+0.000326668 */ // Changed @@ -39,6 +38,7 @@ func (o *UnmountOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_unpause_options.go b/pkg/bindings/containers/types_unpause_options.go index 44c077df2..e02bf2c95 100644 --- a/pkg/bindings/containers/types_unpause_options.go +++ b/pkg/bindings/containers/types_unpause_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:21.661356277 -0600 CST m=+0.000262608 */ // Changed @@ -39,6 +38,7 @@ func (o *UnpauseOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/containers/types_wait_options.go b/pkg/bindings/containers/types_wait_options.go index 18d36c377..470d67611 100644 --- a/pkg/bindings/containers/types_wait_options.go +++ b/pkg/bindings/containers/types_wait_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" "github.com/containers/podman/v2/libpod/define" jsoniter "github.com/json-iterator/go" @@ -12,8 +13,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 13:33:21.809397978 -0600 CST m=+0.000267049 */ // Changed @@ -40,6 +39,7 @@ func (o *WaitOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/generate/types_kube_options.go b/pkg/bindings/generate/types_kube_options.go index 68488aaee..5fb965c9f 100644 --- a/pkg/bindings/generate/types_kube_options.go +++ b/pkg/bindings/generate/types_kube_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:20.522950566 -0600 CST m=+0.000154384 */ // Changed @@ -39,6 +38,7 @@ func (o *KubeOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/generate/types_systemd_options.go b/pkg/bindings/generate/types_systemd_options.go index 0e8a46aa0..ce7286b3a 100644 --- a/pkg/bindings/generate/types_systemd_options.go +++ b/pkg/bindings/generate/types_systemd_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:20.661450253 -0600 CST m=+0.000135779 */ // Changed @@ -39,6 +38,7 @@ func (o *SystemdOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/generator/generator.go b/pkg/bindings/generator/generator.go index 8c79aebae..6a7f600a8 100644 --- a/pkg/bindings/generator/generator.go +++ b/pkg/bindings/generator/generator.go @@ -19,13 +19,10 @@ var bodyTmpl = `package {{.PackageName}} import ( {{range $import := .Imports}} {{$import}} {{end}} - ) /* This file is generated automatically by go generate. Do not edit. - -Created {{.Date}} */ // Changed @@ -52,6 +49,7 @@ func (o *{{.StructName}}) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() @@ -239,7 +237,7 @@ func main() { closed = true // go fmt file - gofmt := exec.Command("gofmt", "-w", "-s", out.Name()) + gofmt := exec.Command("go", "fmt", out.Name()) gofmt.Stderr = os.Stdout if err := gofmt.Run(); err != nil { fmt.Println(err) diff --git a/pkg/bindings/images/types_diff_options.go b/pkg/bindings/images/types_diff_options.go index d27c8945e..34a5bf2df 100644 --- a/pkg/bindings/images/types_diff_options.go +++ b/pkg/bindings/images/types_diff_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:26.320022698 -0600 CST m=+0.000277796 */ // Changed @@ -39,6 +38,7 @@ func (o *DiffOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_export_options.go b/pkg/bindings/images/types_export_options.go index 078b27fc0..172cb2b5c 100644 --- a/pkg/bindings/images/types_export_options.go +++ b/pkg/bindings/images/types_export_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:27.173810543 -0600 CST m=+0.000239871 */ // Changed @@ -39,6 +38,7 @@ func (o *ExportOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_get_options.go b/pkg/bindings/images/types_get_options.go index 1161657f7..c91ddb170 100644 --- a/pkg/bindings/images/types_get_options.go +++ b/pkg/bindings/images/types_get_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:26.609005517 -0600 CST m=+0.000241828 */ // Changed @@ -39,6 +38,7 @@ func (o *GetOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_history_options.go b/pkg/bindings/images/types_history_options.go index 6f9854e03..bd4224cd8 100644 --- a/pkg/bindings/images/types_history_options.go +++ b/pkg/bindings/images/types_history_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:26.890854681 -0600 CST m=+0.000243668 */ // Changed @@ -39,6 +38,7 @@ func (o *HistoryOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_import_options.go b/pkg/bindings/images/types_import_options.go index f5e6c8f7e..81eda946e 100644 --- a/pkg/bindings/images/types_import_options.go +++ b/pkg/bindings/images/types_import_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:27.740585278 -0600 CST m=+0.000340441 */ // Changed @@ -39,6 +38,7 @@ func (o *ImportOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_list_options.go b/pkg/bindings/images/types_list_options.go index 209d72e34..5dc4242fc 100644 --- a/pkg/bindings/images/types_list_options.go +++ b/pkg/bindings/images/types_list_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:26.462967928 -0600 CST m=+0.000289760 */ // Changed @@ -39,6 +38,7 @@ func (o *ListOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_load_options.go b/pkg/bindings/images/types_load_options.go index 6bba573d4..7bbd56c09 100644 --- a/pkg/bindings/images/types_load_options.go +++ b/pkg/bindings/images/types_load_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:27.031848205 -0600 CST m=+0.000279409 */ // Changed @@ -39,6 +38,7 @@ func (o *LoadOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_prune_options.go b/pkg/bindings/images/types_prune_options.go index c29fdae12..c290bb379 100644 --- a/pkg/bindings/images/types_prune_options.go +++ b/pkg/bindings/images/types_prune_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:27.316938584 -0600 CST m=+0.000239843 */ // Changed @@ -39,6 +38,7 @@ func (o *PruneOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_pull_options.go b/pkg/bindings/images/types_pull_options.go index 07f3e079d..5163a6341 100644 --- a/pkg/bindings/images/types_pull_options.go +++ b/pkg/bindings/images/types_pull_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" "github.com/containers/common/pkg/config" jsoniter "github.com/json-iterator/go" @@ -12,8 +13,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:28.164648348 -0600 CST m=+0.000243264 */ // Changed @@ -40,6 +39,7 @@ func (o *PullOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_push_options.go b/pkg/bindings/images/types_push_options.go index f9ce1b835..15210f30b 100644 --- a/pkg/bindings/images/types_push_options.go +++ b/pkg/bindings/images/types_push_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:27.881232044 -0600 CST m=+0.000242458 */ // Changed @@ -39,6 +38,7 @@ func (o *PushOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_remove_options.go b/pkg/bindings/images/types_remove_options.go index c9692c2b7..66a6bea7d 100644 --- a/pkg/bindings/images/types_remove_options.go +++ b/pkg/bindings/images/types_remove_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:26.180391541 -0600 CST m=+0.000290244 */ // Changed @@ -39,6 +38,7 @@ func (o *RemoveOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_search_options.go b/pkg/bindings/images/types_search_options.go index e6168ac33..299d27505 100644 --- a/pkg/bindings/images/types_search_options.go +++ b/pkg/bindings/images/types_search_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:28.023569573 -0600 CST m=+0.000245548 */ // Changed @@ -39,6 +38,7 @@ func (o *SearchOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_tag_options.go b/pkg/bindings/images/types_tag_options.go index f6396e590..40cd4a35b 100644 --- a/pkg/bindings/images/types_tag_options.go +++ b/pkg/bindings/images/types_tag_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:27.457906682 -0600 CST m=+0.000245071 */ // Changed @@ -39,6 +38,7 @@ func (o *TagOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_tree_options.go b/pkg/bindings/images/types_tree_options.go index fb2493f85..a671fa4e0 100644 --- a/pkg/bindings/images/types_tree_options.go +++ b/pkg/bindings/images/types_tree_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:26.749625305 -0600 CST m=+0.000267624 */ // Changed @@ -39,6 +38,7 @@ func (o *TreeOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/images/types_untag_options.go b/pkg/bindings/images/types_untag_options.go index 8faf5c14e..e38c5f18e 100644 --- a/pkg/bindings/images/types_untag_options.go +++ b/pkg/bindings/images/types_untag_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:27.600379913 -0600 CST m=+0.000251449 */ // Changed @@ -39,6 +38,7 @@ func (o *UntagOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/manifests/types_add_options.go b/pkg/bindings/manifests/types_add_options.go index d45effedc..1e588c668 100644 --- a/pkg/bindings/manifests/types_add_options.go +++ b/pkg/bindings/manifests/types_add_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:57:55.92237379 -0600 CST m=+0.000150701 */ // Changed @@ -39,6 +38,7 @@ func (o *AddOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/manifests/types_create_options.go b/pkg/bindings/manifests/types_create_options.go index da07f1abf..3a564a92b 100644 --- a/pkg/bindings/manifests/types_create_options.go +++ b/pkg/bindings/manifests/types_create_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:57:55.784206871 -0600 CST m=+0.000157049 */ // Changed @@ -39,6 +38,7 @@ func (o *CreateOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/manifests/types_inspect_options.go b/pkg/bindings/manifests/types_inspect_options.go index 0d32d5bb9..2af4190d4 100644 --- a/pkg/bindings/manifests/types_inspect_options.go +++ b/pkg/bindings/manifests/types_inspect_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:57:55.631746481 -0600 CST m=+0.000143104 */ // Changed @@ -39,6 +38,7 @@ func (o *InspectOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/manifests/types_push_options.go b/pkg/bindings/manifests/types_push_options.go index 4226733c9..1d689f699 100644 --- a/pkg/bindings/manifests/types_push_options.go +++ b/pkg/bindings/manifests/types_push_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:57:56.197438009 -0600 CST m=+0.000149060 */ // Changed @@ -39,6 +38,7 @@ func (o *PushOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/manifests/types_remove_options.go b/pkg/bindings/manifests/types_remove_options.go index f99220f6c..3b35c38b8 100644 --- a/pkg/bindings/manifests/types_remove_options.go +++ b/pkg/bindings/manifests/types_remove_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:57:56.059954408 -0600 CST m=+0.000146015 */ // Changed @@ -39,6 +38,7 @@ func (o *RemoveOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/network/types_connect_options.go b/pkg/bindings/network/types_connect_options.go index 6fcc4536e..b6081ba57 100644 --- a/pkg/bindings/network/types_connect_options.go +++ b/pkg/bindings/network/types_connect_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:34.075822786 -0600 CST m=+0.000167237 */ // Changed @@ -39,6 +38,7 @@ func (o *ConnectOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/network/types_create_options.go b/pkg/bindings/network/types_create_options.go index daec6a254..5b0abe870 100644 --- a/pkg/bindings/network/types_create_options.go +++ b/pkg/bindings/network/types_create_options.go @@ -5,6 +5,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -12,8 +13,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:33.37307678 -0600 CST m=+0.000176739 */ // Changed @@ -40,6 +39,7 @@ func (o *CreateOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() @@ -193,9 +193,9 @@ func (o *CreateOptions) WithIPRange(value net.IPNet) *CreateOptions { // GetIPRange func (o *CreateOptions) GetIPRange() net.IPNet { - var ipRange net.IPNet + var iPRange net.IPNet if o.IPRange == nil { - return ipRange + return iPRange } return *o.IPRange } diff --git a/pkg/bindings/network/types_disconnect_options.go b/pkg/bindings/network/types_disconnect_options.go index 821279976..8b2a9cb71 100644 --- a/pkg/bindings/network/types_disconnect_options.go +++ b/pkg/bindings/network/types_disconnect_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:33.936088242 -0600 CST m=+0.000168680 */ // Changed @@ -39,6 +38,7 @@ func (o *DisconnectOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/network/types_inspect_options.go b/pkg/bindings/network/types_inspect_options.go index 7704904ce..cec5ef7b2 100644 --- a/pkg/bindings/network/types_inspect_options.go +++ b/pkg/bindings/network/types_inspect_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:33.520438264 -0600 CST m=+0.000172934 */ // Changed @@ -39,6 +38,7 @@ func (o *InspectOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/network/types_list_options.go b/pkg/bindings/network/types_list_options.go index bbd2a71db..6a33fb7b6 100644 --- a/pkg/bindings/network/types_list_options.go +++ b/pkg/bindings/network/types_list_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:33.796794129 -0600 CST m=+0.000180368 */ // Changed @@ -39,6 +38,7 @@ func (o *ListOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/network/types_remove_options.go b/pkg/bindings/network/types_remove_options.go index b24835ae4..861fe1f2c 100644 --- a/pkg/bindings/network/types_remove_options.go +++ b/pkg/bindings/network/types_remove_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:33.658228151 -0600 CST m=+0.000172527 */ // Changed @@ -39,6 +38,7 @@ func (o *RemoveOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/play/types_kube_options.go b/pkg/bindings/play/types_kube_options.go index 91cdd30aa..5aec4b479 100644 --- a/pkg/bindings/play/types_kube_options.go +++ b/pkg/bindings/play/types_kube_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:02.386833736 -0600 CST m=+0.000171080 */ // Changed @@ -39,6 +38,7 @@ func (o *KubeOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_create_options.go b/pkg/bindings/pods/types_create_options.go index b6cf0fc53..b501d1151 100644 --- a/pkg/bindings/pods/types_create_options.go +++ b/pkg/bindings/pods/types_create_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:40.05490508 -0600 CST m=+0.000156396 */ // Changed @@ -39,6 +38,7 @@ func (o *CreateOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_inspect_options.go b/pkg/bindings/pods/types_inspect_options.go index 1c881ce9c..a2eb25fef 100644 --- a/pkg/bindings/pods/types_inspect_options.go +++ b/pkg/bindings/pods/types_inspect_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:40.258801519 -0600 CST m=+0.000175055 */ // Changed @@ -39,6 +38,7 @@ func (o *InspectOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_kill_options.go b/pkg/bindings/pods/types_kill_options.go index cb5bdfd01..f9cad3579 100644 --- a/pkg/bindings/pods/types_kill_options.go +++ b/pkg/bindings/pods/types_kill_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:40.398857339 -0600 CST m=+0.000160135 */ // Changed @@ -39,6 +38,7 @@ func (o *KillOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_list_options.go b/pkg/bindings/pods/types_list_options.go index d095bf3db..02e7adf2d 100644 --- a/pkg/bindings/pods/types_list_options.go +++ b/pkg/bindings/pods/types_list_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:40.818123838 -0600 CST m=+0.000164328 */ // Changed @@ -39,6 +38,7 @@ func (o *ListOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_pause_options.go b/pkg/bindings/pods/types_pause_options.go index 06ee6f81d..2e4fdb4a6 100644 --- a/pkg/bindings/pods/types_pause_options.go +++ b/pkg/bindings/pods/types_pause_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:40.538407099 -0600 CST m=+0.000193274 */ // Changed @@ -39,6 +38,7 @@ func (o *PauseOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_prune_options.go b/pkg/bindings/pods/types_prune_options.go index 6610aa7cc..616ad6dc9 100644 --- a/pkg/bindings/pods/types_prune_options.go +++ b/pkg/bindings/pods/types_prune_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:40.678507342 -0600 CST m=+0.000183891 */ // Changed @@ -39,6 +38,7 @@ func (o *PruneOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_remove_options.go b/pkg/bindings/pods/types_remove_options.go index 8f18e43c9..6960d8839 100644 --- a/pkg/bindings/pods/types_remove_options.go +++ b/pkg/bindings/pods/types_remove_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:41.80320679 -0600 CST m=+0.000158149 */ // Changed @@ -39,6 +38,7 @@ func (o *RemoveOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_restart_options.go b/pkg/bindings/pods/types_restart_options.go index 9030de1e7..427833044 100644 --- a/pkg/bindings/pods/types_restart_options.go +++ b/pkg/bindings/pods/types_restart_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:40.958315383 -0600 CST m=+0.000168360 */ // Changed @@ -39,6 +38,7 @@ func (o *RestartOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_start_options.go b/pkg/bindings/pods/types_start_options.go index 0fce21099..e98798459 100644 --- a/pkg/bindings/pods/types_start_options.go +++ b/pkg/bindings/pods/types_start_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:41.099102916 -0600 CST m=+0.000159629 */ // Changed @@ -39,6 +38,7 @@ func (o *StartOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_stats_options.go b/pkg/bindings/pods/types_stats_options.go index d38a9a115..845a534a3 100644 --- a/pkg/bindings/pods/types_stats_options.go +++ b/pkg/bindings/pods/types_stats_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:41.658228243 -0600 CST m=+0.000160769 */ // Changed @@ -39,6 +38,7 @@ func (o *StatsOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_stop_options.go b/pkg/bindings/pods/types_stop_options.go index ac698b8c5..86000eb57 100644 --- a/pkg/bindings/pods/types_stop_options.go +++ b/pkg/bindings/pods/types_stop_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:41.237892781 -0600 CST m=+0.000155040 */ // Changed @@ -39,6 +38,7 @@ func (o *StopOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_top_options.go b/pkg/bindings/pods/types_top_options.go index 895f62957..ada0b1e25 100644 --- a/pkg/bindings/pods/types_top_options.go +++ b/pkg/bindings/pods/types_top_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:41.375876994 -0600 CST m=+0.000154839 */ // Changed @@ -39,6 +38,7 @@ func (o *TopOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/pods/types_unpause_options.go b/pkg/bindings/pods/types_unpause_options.go index 3d647cf25..6a9ee8fcd 100644 --- a/pkg/bindings/pods/types_unpause_options.go +++ b/pkg/bindings/pods/types_unpause_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:41.515225789 -0600 CST m=+0.000158667 */ // Changed @@ -39,6 +38,7 @@ func (o *UnpauseOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/system/types_disk_options.go b/pkg/bindings/system/types_disk_options.go index f7d2cca06..c5eb2f94c 100644 --- a/pkg/bindings/system/types_disk_options.go +++ b/pkg/bindings/system/types_disk_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:08.087362343 -0600 CST m=+0.000150636 */ // Changed @@ -39,6 +38,7 @@ func (o *DiskOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/system/types_events_options.go b/pkg/bindings/system/types_events_options.go index 6dd64b055..2e95339e6 100644 --- a/pkg/bindings/system/types_events_options.go +++ b/pkg/bindings/system/types_events_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:07.675150173 -0600 CST m=+0.000140977 */ // Changed @@ -39,6 +38,7 @@ func (o *EventsOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/system/types_info_options.go b/pkg/bindings/system/types_info_options.go index 3a8960e1b..263513b0f 100644 --- a/pkg/bindings/system/types_info_options.go +++ b/pkg/bindings/system/types_info_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:08.233760126 -0600 CST m=+0.000142369 */ // Changed @@ -39,6 +38,7 @@ func (o *InfoOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/system/types_prune_options.go b/pkg/bindings/system/types_prune_options.go index 2cd3c8000..a9a6a6cda 100644 --- a/pkg/bindings/system/types_prune_options.go +++ b/pkg/bindings/system/types_prune_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:07.812719858 -0600 CST m=+0.000143214 */ // Changed @@ -39,6 +38,7 @@ func (o *PruneOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/system/types_version_options.go b/pkg/bindings/system/types_version_options.go index 4974e8d8f..be07581fa 100644 --- a/pkg/bindings/system/types_version_options.go +++ b/pkg/bindings/system/types_version_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:07.950759332 -0600 CST m=+0.000140376 */ // Changed @@ -39,6 +38,7 @@ func (o *VersionOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/volumes/types_create_options.go b/pkg/bindings/volumes/types_create_options.go index 80bdac2d2..171090afe 100644 --- a/pkg/bindings/volumes/types_create_options.go +++ b/pkg/bindings/volumes/types_create_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:14.043860791 -0600 CST m=+0.000188944 */ // Changed @@ -39,6 +38,7 @@ func (o *CreateOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/volumes/types_inspect_options.go b/pkg/bindings/volumes/types_inspect_options.go index ba8c70b63..3a1d396a7 100644 --- a/pkg/bindings/volumes/types_inspect_options.go +++ b/pkg/bindings/volumes/types_inspect_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:14.189902005 -0600 CST m=+0.000151439 */ // Changed @@ -39,6 +38,7 @@ func (o *InspectOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/volumes/types_list_options.go b/pkg/bindings/volumes/types_list_options.go index 99dec132c..56033a575 100644 --- a/pkg/bindings/volumes/types_list_options.go +++ b/pkg/bindings/volumes/types_list_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:14.326721724 -0600 CST m=+0.000172471 */ // Changed @@ -39,6 +38,7 @@ func (o *ListOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/volumes/types_prune_options.go b/pkg/bindings/volumes/types_prune_options.go index cdbc03fc9..c043d69d0 100644 --- a/pkg/bindings/volumes/types_prune_options.go +++ b/pkg/bindings/volumes/types_prune_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:14.463307398 -0600 CST m=+0.000180868 */ // Changed @@ -39,6 +38,7 @@ func (o *PruneOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/bindings/volumes/types_remove_options.go b/pkg/bindings/volumes/types_remove_options.go index 923d1353c..1f8ba4e22 100644 --- a/pkg/bindings/volumes/types_remove_options.go +++ b/pkg/bindings/volumes/types_remove_options.go @@ -4,6 +4,7 @@ import ( "net/url" "reflect" "strconv" + "strings" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -11,8 +12,6 @@ import ( /* This file is generated automatically by go generate. Do not edit. - -Created 2020-12-18 15:58:14.60278922 -0600 CST m=+0.000134408 */ // Changed @@ -39,6 +38,7 @@ func (o *RemoveOptions) ToParams() (url.Values, error) { if !o.Changed(fieldName) { continue } + fieldName = strings.ToLower(fieldName) f := s.Field(i) if reflect.Ptr == f.Kind() { f = f.Elem() diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 96687b1de..d8576c101 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -434,3 +434,9 @@ type ContainerStatsReport struct { // Results, set when there is no error. Stats []define.ContainerStats } + +// ContainerRenameOptions describes input options for renaming a container. +type ContainerRenameOptions struct { + // NewName is the new name that will be given to the container. + NewName string +} diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 7d38a97f2..d2552770c 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -37,6 +37,7 @@ type ContainerEngine interface { ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) ContainerPort(ctx context.Context, nameOrID string, options ContainerPortOptions) ([]*ContainerPortReport, error) ContainerPrune(ctx context.Context, options ContainerPruneOptions) ([]*reports.PruneReport, error) + ContainerRename(ctr context.Context, nameOrID string, options ContainerRenameOptions) error ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error) ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error) ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error) diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go index 06438f5e9..c826ee389 100644 --- a/pkg/domain/entities/volumes.go +++ b/pkg/domain/entities/volumes.go @@ -2,8 +2,8 @@ package entities import ( "net/url" - "time" + "github.com/containers/podman/v2/libpod/define" docker_api_types "github.com/docker/docker/api/types" docker_api_types_volume "github.com/docker/docker/api/types/volume" ) @@ -26,38 +26,7 @@ type IDOrNameResponse struct { } type VolumeConfigResponse struct { - // Name is the name of the volume. - Name string `json:"Name"` - // Driver is the driver used to create the volume. - // This will be properly implemented in a future version. - Driver string `json:"Driver"` - // Mountpoint is the path on the host where the volume is mounted. - Mountpoint string `json:"Mountpoint"` - // CreatedAt is the date and time the volume was created at. This is not - // stored for older Libpod volumes; if so, it will be omitted. - CreatedAt time.Time `json:"CreatedAt,omitempty"` - // Status is presently unused and provided only for Docker compatibility. - // In the future it will be used to return information on the volume's - // current state. - Status map[string]string `json:"Status,omitempty"` - // Labels includes the volume's configured labels, key:value pairs that - // can be passed during volume creation to provide information for third - // party tools. - Labels map[string]string `json:"Labels"` - // Scope is unused and provided solely for Docker compatibility. It is - // unconditionally set to "local". - Scope string `json:"Scope"` - // Options is a set of options that were used when creating the volume. - // It is presently not used. - Options map[string]string `json:"Options"` - // UID is the UID that the volume was created with. - UID int `json:"UID"` - // GID is the GID that the volume was created with. - GID int `json:"GID"` - // Anonymous indicates that the volume was created as an anonymous - // volume for a specific container, and will be be removed when any - // container using it is removed. - Anonymous bool `json:"Anonymous"` + define.InspectVolumeData } // VolumeInfo Volume list response diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index b5f5a0e91..a8f4d44a8 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -902,7 +902,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil { if errors.Cause(err) == define.ErrNoSuchCtr || errors.Cause(err) == define.ErrCtrRemoved { - logrus.Warnf("Container %s does not exist: %v", ctr.ID(), err) + logrus.Infof("Container %s was already removed, skipping --rm", ctr.ID()) } else { logrus.Errorf("Error removing container %s: %v", ctr.ID(), err) } @@ -1312,3 +1312,17 @@ func (ic *ContainerEngine) ShouldRestart(ctx context.Context, nameOrID string) ( return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil } + +// ContainerRename renames the given container. +func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string, opts entities.ContainerRenameOptions) error { + ctr, err := ic.Libpod.LookupContainer(nameOrID) + if err != nil { + return err + } + + if _, err := ic.Libpod.RenameContainer(ctx, ctr, opts.NewName); err != nil { + return err + } + + return nil +} diff --git a/pkg/domain/infra/abi/containers_stat.go b/pkg/domain/infra/abi/containers_stat.go index 5b43ee2f4..931e77026 100644 --- a/pkg/domain/infra/abi/containers_stat.go +++ b/pkg/domain/infra/abi/containers_stat.go @@ -144,16 +144,29 @@ func resolveContainerPaths(container *libpod.Container, mountPoint string, conta } if volume != nil { logrus.Debugf("Container path %q resolved to volume %q on path %q", containerPath, volume.Name(), searchPath) + + // TODO: We really need to force the volume to mount + // before doing this, but that API is not exposed + // externally right now and doing so is beyond the scope + // of this commit. + mountPoint, err := volume.MountPoint() + if err != nil { + return "", "", err + } + if mountPoint == "" { + return "", "", errors.Errorf("volume %s is not mounted, cannot copy into it", volume.Name()) + } + // We found a matching volume for searchPath. We now // need to first find the relative path of our input // path to the searchPath, and then join it with the // volume's mount point. pathRelativeToVolume := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath) - absolutePathOnTheVolumeMount, err := securejoin.SecureJoin(volume.MountPoint(), pathRelativeToVolume) + absolutePathOnTheVolumeMount, err := securejoin.SecureJoin(mountPoint, pathRelativeToVolume) if err != nil { return "", "", err } - return volume.MountPoint(), absolutePathOnTheVolumeMount, nil + return mountPoint, absolutePathOnTheVolumeMount, nil } if mount := findBindMount(container, searchPath); mount != nil { diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 97fa9d374..f29b98696 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -312,7 +312,17 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System var reclaimableSize int64 for _, v := range vols { var consInUse int - volSize, err := sizeOfPath(v.MountPoint()) + mountPoint, err := v.MountPoint() + if err != nil { + return nil, err + } + if mountPoint == "" { + // We can't get any info on this volume, as it's not + // mounted. + // TODO: fix this. + continue + } + volSize, err := sizeOfPath(mountPoint) if err != nil { return nil, err } diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go index 3c9dd9fc0..823605052 100644 --- a/pkg/domain/infra/abi/volumes.go +++ b/pkg/domain/infra/abi/volumes.go @@ -103,25 +103,12 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin } reports := make([]*entities.VolumeInspectReport, 0, len(vols)) for _, v := range vols { - var uid, gid int - uid, err = v.UID() - if err != nil { - return nil, nil, err - } - gid, err = v.GID() + inspectOut, err := v.Inspect() if err != nil { return nil, nil, err } config := entities.VolumeConfigResponse{ - Name: v.Name(), - Driver: v.Driver(), - Mountpoint: v.MountPoint(), - CreatedAt: v.CreatedTime(), - Labels: v.Labels(), - Scope: v.Scope(), - Options: v.Options(), - UID: uid, - GID: gid, + InspectVolumeData: *inspectOut, } reports = append(reports, &entities.VolumeInspectReport{VolumeConfigResponse: &config}) } @@ -155,25 +142,12 @@ func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeL } reports := make([]*entities.VolumeListReport, 0, len(vols)) for _, v := range vols { - var uid, gid int - uid, err = v.UID() - if err != nil { - return nil, err - } - gid, err = v.GID() + inspectOut, err := v.Inspect() if err != nil { return nil, err } config := entities.VolumeConfigResponse{ - Name: v.Name(), - Driver: v.Driver(), - Mountpoint: v.MountPoint(), - CreatedAt: v.CreatedTime(), - Labels: v.Labels(), - Scope: v.Scope(), - Options: v.Options(), - UID: uid, - GID: gid, + InspectVolumeData: *inspectOut, } reports = append(reports, &entities.VolumeListReport{VolumeConfigResponse: config}) } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 49bcdec98..8aab4a9cd 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -820,3 +820,8 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) { return containers.ShouldRestart(ic.ClientCtx, id, nil) } + +// ContainerRename renames the given container. +func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string, opts entities.ContainerRenameOptions) error { + return errors.Errorf("NOT YET IMPLEMENTED") +} diff --git a/test/apiv2/30-volumes.at b/test/apiv2/30-volumes.at index 33f4ea37f..b38810039 100644 --- a/test/apiv2/30-volumes.at +++ b/test/apiv2/30-volumes.at @@ -12,7 +12,7 @@ t POST libpod/volumes/create name=foo1 201 \ .Mountpoint=$volumepath/foo1/_data \ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \ .Labels={} \ - .Options=null + .Options={} t POST libpod/volumes/create '' 201 t POST libpod/volumes/create \ '"Name":"foo2","Label":{"testlabel":"testonly"},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \ diff --git a/test/apiv2/45-system.at b/test/apiv2/45-system.at index 44cd05a13..985d86e56 100644 --- a/test/apiv2/45-system.at +++ b/test/apiv2/45-system.at @@ -19,7 +19,7 @@ t POST libpod/volumes/create name=foo1 201 \ .Mountpoint=$volumepath/foo1/_data \ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \ .Labels={} \ - .Options=null + .Options={} t GET system/df 200 '.Volumes[0].Name=foo1' diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index abc37792a..3270ce685 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -623,7 +623,7 @@ var _ = Describe("Podman checkpoint", func() { result := podmanTest.Podman([]string{"container", "checkpoint", "-l"}) result.WaitWithDefaultTimeout() Expect(result).To(ExitWithError()) - Expect(result.ErrorToString()).To(ContainSubstring("Cannot checkpoint containers that have been started with '--rm'")) + Expect(result.ErrorToString()).To(ContainSubstring("cannot checkpoint containers that have been started with '--rm'")) // Checkpointing with --export should still work fileName := "/tmp/checkpoint-" + cid + ".tar.gz" diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 18679dd53..2668b1e7b 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -122,7 +122,7 @@ var _ = SynchronizedBeforeSuite(func() []byte { } // Pull cirros but don't put it into the cache - pullImages := []string{cirros, fedoraToolbox} + pullImages := []string{cirros, fedoraToolbox, volumeTest} pullImages = append(pullImages, CACHE_IMAGES...) for _, image := range pullImages { podman.createArtifact(image) @@ -483,13 +483,7 @@ func (p *PodmanTestIntegration) CleanupVolume() { session := p.Podman([]string{"volume", "rm", "-fa"}) session.Wait(90) - // Stop remove service on volume cleanup - p.StopRemoteService() - - // Nuke tempdir - if err := os.RemoveAll(p.TempDir); err != nil { - fmt.Printf("%q\n", err) - } + p.Cleanup() } // InspectContainerToJSON takes the session output of an inspect diff --git a/test/e2e/config.go b/test/e2e/config.go index e66cd6846..2552595ad 100644 --- a/test/e2e/config.go +++ b/test/e2e/config.go @@ -15,6 +15,7 @@ var ( healthcheck = "quay.io/libpod/alpine_healthcheck:latest" ImageCacheDir = "/tmp/podman/imagecachedir" fedoraToolbox = "registry.fedoraproject.org/f32/fedora-toolbox:latest" + volumeTest = "quay.io/libpod/volume-plugin-test-img:latest" // This image has seccomp profiles that blocks all syscalls. // The intention behind blocking all syscalls is to prevent diff --git a/test/e2e/config/containers.conf b/test/e2e/config/containers.conf index 35153ba05..5a5e4b7a5 100644 --- a/test/e2e/config/containers.conf +++ b/test/e2e/config/containers.conf @@ -56,3 +56,17 @@ umask = "0002" [engine] network_cmd_options=["allow_host_loopback=true"] + +# We need to ensure each test runs on a separate plugin instance... +# For now, let's just make a bunch of plugin paths and have each test use one. +[engine.volume_plugins] +testvol0 = "/run/docker/plugins/testvol0.sock" +testvol1 = "/run/docker/plugins/testvol1.sock" +testvol2 = "/run/docker/plugins/testvol2.sock" +testvol3 = "/run/docker/plugins/testvol3.sock" +testvol4 = "/run/docker/plugins/testvol4.sock" +testvol5 = "/run/docker/plugins/testvol5.sock" +testvol6 = "/run/docker/plugins/testvol6.sock" +testvol7 = "/run/docker/plugins/testvol7.sock" +testvol8 = "/run/docker/plugins/testvol8.sock" +testvol9 = "/run/docker/plugins/testvol9.sock" diff --git a/test/e2e/rename_test.go b/test/e2e/rename_test.go new file mode 100644 index 000000000..324e6a54a --- /dev/null +++ b/test/e2e/rename_test.go @@ -0,0 +1,93 @@ +package integration + +import ( + "fmt" + "os" + + . "github.com/containers/podman/v2/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("podman rename", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + SkipIfRemote("Rename not yet implemented by podman-remote") + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + podmanTest.SeedImages() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + + }) + + It("podman rename on non-existent container", func() { + session := podmanTest.Podman([]string{"rename", "doesNotExist", "aNewName"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) + + It("Podman rename on existing container with bad name", func() { + ctrName := "testCtr" + ctr := podmanTest.Podman([]string{"create", "--name", ctrName, ALPINE, "top"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(Equal(0)) + + newName := "invalid<>:char" + rename := podmanTest.Podman([]string{"rename", ctrName, newName}) + rename.WaitWithDefaultTimeout() + Expect(rename.ExitCode()).To(Not(Equal(0))) + + ps := podmanTest.Podman([]string{"ps", "-aq", "--filter", fmt.Sprintf("name=%s", ctrName), "--format", "{{ .Names }}"}) + ps.WaitWithDefaultTimeout() + Expect(ps.ExitCode()).To(Equal(0)) + Expect(ps.OutputToString()).To(ContainSubstring(ctrName)) + }) + + It("Successfully rename a created container", func() { + ctrName := "testCtr" + ctr := podmanTest.Podman([]string{"create", "--name", ctrName, ALPINE, "top"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(Equal(0)) + + newName := "aNewName" + rename := podmanTest.Podman([]string{"rename", ctrName, newName}) + rename.WaitWithDefaultTimeout() + Expect(rename.ExitCode()).To(Equal(0)) + + ps := podmanTest.Podman([]string{"ps", "-aq", "--filter", fmt.Sprintf("name=%s", newName), "--format", "{{ .Names }}"}) + ps.WaitWithDefaultTimeout() + Expect(ps.ExitCode()).To(Equal(0)) + Expect(ps.OutputToString()).To(ContainSubstring(newName)) + }) + + It("Successfully rename a running container", func() { + ctrName := "testCtr" + ctr := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, ALPINE, "top"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(Equal(0)) + + newName := "aNewName" + rename := podmanTest.Podman([]string{"rename", ctrName, newName}) + rename.WaitWithDefaultTimeout() + Expect(rename.ExitCode()).To(Equal(0)) + + ps := podmanTest.Podman([]string{"ps", "-aq", "--filter", fmt.Sprintf("name=%s", newName), "--format", "{{ .Names }}"}) + ps.WaitWithDefaultTimeout() + Expect(ps.ExitCode()).To(Equal(0)) + Expect(ps.OutputToString()).To(ContainSubstring(newName)) + }) +}) diff --git a/test/e2e/volume_plugin_test.go b/test/e2e/volume_plugin_test.go new file mode 100644 index 000000000..16edab27c --- /dev/null +++ b/test/e2e/volume_plugin_test.go @@ -0,0 +1,184 @@ +package integration + +import ( + "fmt" + "os" + "path/filepath" + + . "github.com/containers/podman/v2/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman volume plugins", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + podmanTest.SeedImages() + os.Setenv("CONTAINERS_CONF", "config/containers.conf") + SkipIfRemote("Volume plugins only supported as local") + SkipIfRootless("Root is required for volume plugin testing") + os.MkdirAll("/run/docker/plugins", 0755) + }) + + AfterEach(func() { + podmanTest.CleanupVolume() + f := CurrentGinkgoTestDescription() + processTestResult(f) + os.Unsetenv("CONTAINERS_CONF") + }) + + It("volume create with nonexistent plugin errors", func() { + session := podmanTest.Podman([]string{"volume", "create", "--driver", "notexist", "test_volume_name"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) + + It("volume create with not-running plugin does not error", func() { + session := podmanTest.Podman([]string{"volume", "create", "--driver", "testvol0", "test_volume_name"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) + + It("volume create and remove with running plugin succeeds", func() { + podmanTest.AddImageToRWStore(volumeTest) + + pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes") + os.Mkdir(pluginStatePath, 0755) + + // Keep this distinct within tests to avoid multiple tests using the same plugin. + pluginName := "testvol1" + plugin := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath}) + plugin.WaitWithDefaultTimeout() + Expect(plugin.ExitCode()).To(Equal(0)) + + volName := "testVolume1" + create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName}) + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(Equal(0)) + + ls1 := podmanTest.Podman([]string{"volume", "ls", "-q"}) + ls1.WaitWithDefaultTimeout() + Expect(ls1.ExitCode()).To(Equal(0)) + arrOutput := ls1.OutputToStringArray() + Expect(len(arrOutput)).To(Equal(1)) + Expect(arrOutput[0]).To(ContainSubstring(volName)) + + remove := podmanTest.Podman([]string{"volume", "rm", volName}) + remove.WaitWithDefaultTimeout() + Expect(remove.ExitCode()).To(Equal(0)) + + ls2 := podmanTest.Podman([]string{"volume", "ls", "-q"}) + ls2.WaitWithDefaultTimeout() + Expect(ls2.ExitCode()).To(Equal(0)) + Expect(len(ls2.OutputToStringArray())).To(Equal(0)) + }) + + It("volume inspect with running plugin succeeds", func() { + podmanTest.AddImageToRWStore(volumeTest) + + pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes") + os.Mkdir(pluginStatePath, 0755) + + // Keep this distinct within tests to avoid multiple tests using the same plugin. + pluginName := "testvol2" + plugin := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath}) + plugin.WaitWithDefaultTimeout() + Expect(plugin.ExitCode()).To(Equal(0)) + + volName := "testVolume1" + create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName}) + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(Equal(0)) + + volInspect := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .Driver }}", volName}) + volInspect.WaitWithDefaultTimeout() + Expect(volInspect.ExitCode()).To(Equal(0)) + Expect(volInspect.OutputToString()).To(ContainSubstring(pluginName)) + }) + + It("remove plugin with stopped plugin succeeds", func() { + podmanTest.AddImageToRWStore(volumeTest) + + pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes") + os.Mkdir(pluginStatePath, 0755) + + // Keep this distinct within tests to avoid multiple tests using the same plugin. + pluginName := "testvol3" + ctrName := "pluginCtr" + plugin := podmanTest.Podman([]string{"run", "--name", ctrName, "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath}) + plugin.WaitWithDefaultTimeout() + Expect(plugin.ExitCode()).To(Equal(0)) + + volName := "testVolume1" + create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName}) + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(Equal(0)) + + ls1 := podmanTest.Podman([]string{"volume", "ls", "-q"}) + ls1.WaitWithDefaultTimeout() + Expect(ls1.ExitCode()).To(Equal(0)) + arrOutput := ls1.OutputToStringArray() + Expect(len(arrOutput)).To(Equal(1)) + Expect(arrOutput[0]).To(ContainSubstring(volName)) + + stop := podmanTest.Podman([]string{"stop", "--timeout", "0", ctrName}) + stop.WaitWithDefaultTimeout() + Expect(stop.ExitCode()).To(Equal(0)) + + // Remove should exit non-zero because missing plugin + remove := podmanTest.Podman([]string{"volume", "rm", volName}) + remove.WaitWithDefaultTimeout() + Expect(remove.ExitCode()).To(Not(Equal(0))) + + // But the volume should still be gone + ls2 := podmanTest.Podman([]string{"volume", "ls", "-q"}) + ls2.WaitWithDefaultTimeout() + Expect(ls2.ExitCode()).To(Equal(0)) + Expect(len(ls2.OutputToStringArray())).To(Equal(0)) + }) + + It("use plugin in containers", func() { + podmanTest.AddImageToRWStore(volumeTest) + + pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes") + os.Mkdir(pluginStatePath, 0755) + + // Keep this distinct within tests to avoid multiple tests using the same plugin. + pluginName := "testvol4" + plugin := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath}) + plugin.WaitWithDefaultTimeout() + Expect(plugin.ExitCode()).To(Equal(0)) + + volName := "testVolume1" + create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName}) + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(Equal(0)) + + ctr1 := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", fmt.Sprintf("%v:/test", volName), ALPINE, "sh", "-c", "touch /test/testfile && echo helloworld > /test/testfile"}) + ctr1.WaitWithDefaultTimeout() + Expect(ctr1.ExitCode()).To(Equal(0)) + + ctr2 := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", fmt.Sprintf("%v:/test", volName), ALPINE, "cat", "/test/testfile"}) + ctr2.WaitWithDefaultTimeout() + Expect(ctr2.ExitCode()).To(Equal(0)) + Expect(ctr2.OutputToString()).To(ContainSubstring("helloworld")) + + // HACK: `volume rm -f` is timing out trying to remove containers using the volume. + // Solution: remove them manually... + // TODO: fix this when I get back + rmAll := podmanTest.Podman([]string{"rm", "-af"}) + rmAll.WaitWithDefaultTimeout() + Expect(rmAll.ExitCode()).To(Equal(0)) + }) +}) diff --git a/test/python/docker/test_containers.py b/test/python/docker/test_containers.py index 5a9f761a6..01e049ed4 100644 --- a/test/python/docker/test_containers.py +++ b/test/python/docker/test_containers.py @@ -179,11 +179,3 @@ class TestContainers(unittest.TestCase): filters = {"name": "top"} ctnrs = self.client.containers.list(all=True, filters=filters) self.assertEqual(len(ctnrs), 1) - - def test_rename_container(self): - top = self.client.containers.get(TestContainers.topContainerId) - - # rename bogus container - with self.assertRaises(errors.APIError) as error: - top.rename(name="newname") - self.assertEqual(error.exception.response.status_code, 404) diff --git a/test/system/050-stop.bats b/test/system/050-stop.bats index f604ea2e2..548fd56ee 100644 --- a/test/system/050-stop.bats +++ b/test/system/050-stop.bats @@ -67,4 +67,32 @@ load helpers done } +# Regression test for #8501 +@test "podman stop - unlock while waiting for timeout" { + # Test that the container state transitions to "stopping" and that other + # commands can get the container's lock. To do that, run a container that + # ingores SIGTERM such that the Podman would wait 20 seconds for the stop + # to finish. This gives us enough time to try some commands and inspect + # the container's status. + + run_podman run --name stopme -d $IMAGE sh -c \ + "trap 'echo Received SIGTERM, ignoring' SIGTERM; echo READY; while :; do sleep 1; done" + + # Stop the container in the background + $PODMAN stop -t 20 stopme & + + # Other commands can acquire the lock + run_podman ps -a + + # The container state transitioned to "stopping" + run_podman inspect --format '{{.State.Status}}' stopme + is "$output" "stopping" "Status of container should be 'stopping'" + + run_podman kill stopme + + # Exit code should be 137 as it was killed + run_podman inspect --format '{{.State.ExitCode}}' stopme + is "$output" "137" "Exit code of killed container" +} + # vim: filetype=sh diff --git a/test/testvol/main.go b/test/testvol/main.go new file mode 100644 index 000000000..14f253aa7 --- /dev/null +++ b/test/testvol/main.go @@ -0,0 +1,309 @@ +package main + +import ( + "io/ioutil" + "os" + "path/filepath" + "sync" + "time" + + "github.com/docker/go-plugins-helpers/volume" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "testvol", + Short: "testvol - volume plugin for Podman", + Long: `Creates simple directory volumes using the Volume Plugin API for testing volume plugin functionality`, + RunE: func(cmd *cobra.Command, args []string) error { + return startServer(config.sockName) + }, + PersistentPreRunE: before, +} + +// Configuration for the volume plugin +type cliConfig struct { + logLevel string + sockName string + path string +} + +// Default configuration is stored here. Will be overwritten by flags. +var config cliConfig = cliConfig{ + logLevel: "error", + sockName: "test-volume-plugin", +} + +func init() { + rootCmd.Flags().StringVar(&config.sockName, "sock-name", config.sockName, "Name of unix socket for plugin") + rootCmd.Flags().StringVar(&config.path, "path", "", "Path to initialize state and mount points") + rootCmd.PersistentFlags().StringVar(&config.logLevel, "log-level", config.logLevel, "Log messages including and over the specified level: debug, info, warn, error, fatal, panic") +} + +func before(cmd *cobra.Command, args []string) error { + if config.logLevel == "" { + config.logLevel = "error" + } + + level, err := logrus.ParseLevel(config.logLevel) + if err != nil { + return err + } + + logrus.SetLevel(level) + + return nil +} + +func main() { + if err := rootCmd.Execute(); err != nil { + logrus.Errorf("Error running volume plugin: %v", err) + os.Exit(1) + } + + os.Exit(0) +} + +// startServer runs the HTTP server and responds to requests +func startServer(socketPath string) error { + logrus.Debugf("Starting server...") + + if config.path == "" { + path, err := ioutil.TempDir("", "test_volume_plugin") + if err != nil { + return errors.Wrapf(err, "error getting directory for plugin") + } + config.path = path + } else { + pathStat, err := os.Stat(config.path) + if err != nil { + return errors.Wrapf(err, "unable to access requested plugin state directory") + } + if !pathStat.IsDir() { + return errors.Errorf("cannot use %v as plugin state dir as it is not a directory", config.path) + } + } + + handle, err := makeDirDriver(config.path) + if err != nil { + return errors.Wrapf(err, "error making volume driver") + } + logrus.Infof("Using %s for volume path", config.path) + + server := volume.NewHandler(handle) + if err := server.ServeUnix(socketPath, 0); err != nil { + return errors.Wrapf(err, "error starting server") + } + return nil +} + +// DirDriver is a trivial volume driver implementation. +// the volumes field maps name to volume +type DirDriver struct { + lock sync.Mutex + volumesPath string + volumes map[string]*dirVol +} + +type dirVol struct { + name string + path string + options map[string]string + mounts map[string]bool + createTime time.Time +} + +// Make a new DirDriver. +func makeDirDriver(path string) (volume.Driver, error) { + drv := new(DirDriver) + drv.volumesPath = path + drv.volumes = make(map[string]*dirVol) + + return drv, nil +} + +// Capabilities returns the capabilities of the driver. +func (d *DirDriver) Capabilities() *volume.CapabilitiesResponse { + logrus.Infof("Hit Capabilities() endpoint") + + return &volume.CapabilitiesResponse{ + volume.Capability{ + "local", + }, + } +} + +// Create creates a volume. +func (d *DirDriver) Create(opts *volume.CreateRequest) error { + d.lock.Lock() + defer d.lock.Unlock() + + logrus.Infof("Hit Create() endpoint") + + if _, exists := d.volumes[opts.Name]; exists { + return errors.Errorf("volume with name %s already exists", opts.Name) + } + + newVol := new(dirVol) + newVol.name = opts.Name + newVol.mounts = make(map[string]bool) + newVol.options = make(map[string]string) + newVol.createTime = time.Now() + for k, v := range opts.Options { + newVol.options[k] = v + } + + volPath := filepath.Join(d.volumesPath, opts.Name) + if err := os.Mkdir(volPath, 0755); err != nil { + return errors.Wrapf(err, "error making volume directory") + } + newVol.path = volPath + + d.volumes[opts.Name] = newVol + + logrus.Debugf("Made volume with name %s and path %s", newVol.name, newVol.path) + + return nil +} + +// List lists all volumes available. +func (d *DirDriver) List() (*volume.ListResponse, error) { + d.lock.Lock() + defer d.lock.Unlock() + + logrus.Infof("Hit List() endpoint") + + vols := new(volume.ListResponse) + vols.Volumes = []*volume.Volume{} + + for _, vol := range d.volumes { + newVol := new(volume.Volume) + newVol.Name = vol.name + newVol.Mountpoint = vol.path + newVol.CreatedAt = vol.createTime.String() + vols.Volumes = append(vols.Volumes, newVol) + logrus.Debugf("Adding volume %s to list response", newVol.Name) + } + + return vols, nil +} + +// Get retrieves a single volume. +func (d *DirDriver) Get(req *volume.GetRequest) (*volume.GetResponse, error) { + d.lock.Lock() + defer d.lock.Unlock() + + logrus.Infof("Hit Get() endpoint") + + vol, exists := d.volumes[req.Name] + if !exists { + logrus.Debugf("Did not find volume %s", req.Name) + return nil, errors.Errorf("no volume with name %s found", req.Name) + } + + logrus.Debugf("Found volume %s", req.Name) + + resp := new(volume.GetResponse) + resp.Volume = new(volume.Volume) + resp.Volume.Name = vol.name + resp.Volume.Mountpoint = vol.path + resp.Volume.CreatedAt = vol.createTime.String() + + return resp, nil +} + +// Remove removes a single volume. +func (d *DirDriver) Remove(req *volume.RemoveRequest) error { + d.lock.Lock() + defer d.lock.Unlock() + + logrus.Infof("Hit Remove() endpoint") + + vol, exists := d.volumes[req.Name] + if !exists { + logrus.Debugf("Did not find volume %s", req.Name) + return errors.Errorf("no volume with name %s found") + } + logrus.Debugf("Found volume %s", req.Name) + + if len(vol.mounts) > 0 { + logrus.Debugf("Cannot remove %s, is mounted", req.Name) + return errors.Errorf("volume %s is mounted and cannot be removed") + } + + delete(d.volumes, req.Name) + + if err := os.RemoveAll(vol.path); err != nil { + return errors.Wrapf(err, "error removing mountpoint of volume %s", req.Name) + } + + logrus.Debugf("Removed volume %s", req.Name) + + return nil +} + +// Path returns the path a single volume is mounted at. +func (d *DirDriver) Path(req *volume.PathRequest) (*volume.PathResponse, error) { + d.lock.Lock() + defer d.lock.Unlock() + + logrus.Infof("Hit Path() endpoint") + + // TODO: Should we return error if not mounted? + + vol, exists := d.volumes[req.Name] + if !exists { + logrus.Debugf("Cannot locate volume %s", req.Name) + return nil, errors.Errorf("no volume with name %s found", req.Name) + } + + return &volume.PathResponse{ + vol.path, + }, nil +} + +// Mount mounts the volume. +func (d *DirDriver) Mount(req *volume.MountRequest) (*volume.MountResponse, error) { + d.lock.Lock() + defer d.lock.Unlock() + + logrus.Infof("Hit Mount() endpoint") + + vol, exists := d.volumes[req.Name] + if !exists { + logrus.Debugf("Cannot locate volume %s", req.Name) + return nil, errors.Errorf("no volume with name %s found", req.Name) + } + + vol.mounts[req.ID] = true + + return &volume.MountResponse{ + vol.path, + }, nil +} + +// Unmount unmounts the volume. +func (d *DirDriver) Unmount(req *volume.UnmountRequest) error { + d.lock.Lock() + defer d.lock.Unlock() + + logrus.Infof("Hit Unmount() endpoint") + + vol, exists := d.volumes[req.Name] + if !exists { + logrus.Debugf("Cannot locate volume %s", req.Name) + return errors.Errorf("no volume with name %s found", req.Name) + } + + mount := vol.mounts[req.ID] + if !mount { + logrus.Debugf("Volume %s is not mounted by %s", req.Name, req.ID) + return errors.Errorf("volume %s is not mounted by %s", req.Name, req.ID) + } + + delete(vol.mounts, req.ID) + + return nil +} diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go index 7a9f97d1c..d9c1d37db 100644 --- a/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go +++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go @@ -102,7 +102,7 @@ func (plugin *cniNetworkPlugin) podUnlock(podNetwork PodNetwork) { fullPodName := buildFullPodName(podNetwork) lock, ok := plugin.pods[fullPodName] if !ok { - logrus.Warningf("Unbalanced pod lock unref for %s", fullPodName) + logrus.Errorf("Cannot find reference in refcount map for %s. Refcount cannot be determined.", fullPodName) return } else if lock.refcount == 0 { // This should never ever happen, but handle it anyway @@ -121,12 +121,12 @@ func newWatcher(confDir string) (*fsnotify.Watcher, error) { // Ensure plugin directory exists, because the following monitoring logic // relies on that. if err := os.MkdirAll(confDir, 0755); err != nil { - return nil, fmt.Errorf("failed to create %q: %v", confDir, err) + return nil, fmt.Errorf("failed to create directory %q: %v", confDir, err) } watcher, err := fsnotify.NewWatcher() if err != nil { - return nil, fmt.Errorf("could not create new watcher %v", err) + return nil, fmt.Errorf("failed to create new watcher %v", err) } defer func() { // Close watcher on error @@ -275,13 +275,13 @@ func loadNetworks(confDir string, cni *libcni.CNIConfig) (map[string]*cniNetwork if strings.HasSuffix(confFile, ".conflist") { confList, err = libcni.ConfListFromFile(confFile) if err != nil { - logrus.Warningf("Error loading CNI config list file %s: %v", confFile, err) + logrus.Errorf("Error loading CNI config list file %s: %v", confFile, err) continue } } else { conf, err := libcni.ConfFromFile(confFile) if err != nil { - logrus.Warningf("Error loading CNI config file %s: %v", confFile, err) + logrus.Errorf("Error loading CNI config file %s: %v", confFile, err) continue } if conf.Network.Type == "" { @@ -290,7 +290,7 @@ func loadNetworks(confDir string, cni *libcni.CNIConfig) (map[string]*cniNetwork } confList, err = libcni.ConfListFromConf(conf) if err != nil { - logrus.Warningf("Error converting CNI config file %s to list: %v", confFile, err) + logrus.Errorf("Error converting CNI config file %s to list: %v", confFile, err) continue } } @@ -321,7 +321,7 @@ func loadNetworks(confDir string, cni *libcni.CNIConfig) (map[string]*cniNetwork if _, ok := networks[confList.Name]; !ok { networks[confList.Name] = cniNet } else { - logrus.Infof("Ignore CNI network %s (type=%v) at %s because already exists", confList.Name, confList.Plugins[0].Network.Type, confFile) + logrus.Infof("Ignored CNI network %s (type=%v) at %s because already exists", confList.Name, confList.Plugins[0].Network.Type, confFile) } if defaultNetName == "" { @@ -348,7 +348,7 @@ func (plugin *cniNetworkPlugin) syncNetworkConfig() error { // Update defaultNetName if it is changeable if plugin.defaultNetName.changeable { plugin.defaultNetName.name = defaultNetName - logrus.Infof("Update default CNI network name to %s", defaultNetName) + logrus.Infof("Updated default CNI network name to %s", defaultNetName) } else { logrus.Debugf("Default CNI network name %s is unchangeable", plugin.defaultNetName.name) } @@ -479,8 +479,8 @@ func (plugin *cniNetworkPlugin) forEachNetwork(podNetwork *PodNetwork, fromCache var newRt *libcni.RuntimeConf cniNet, newRt, err = plugin.loadNetworkFromCache(network.Name, rt) if err != nil { - logrus.Debugf("error loading cached network config: %v", err) - logrus.Debugf("falling back to loading from existing plugins on disk") + logrus.Errorf("error loading cached network config: %v", err) + logrus.Warningf("falling back to loading from existing plugins on disk") } else { // Use the updated RuntimeConf rt = newRt @@ -570,7 +570,7 @@ func (plugin *cniNetworkPlugin) getCachedNetworkInfo(containerID string) ([]NetA cacheFile := filepath.Join(dirPath, fname) bytes, err := ioutil.ReadFile(cacheFile) if err != nil { - logrus.Warningf("failed to read CNI cache file %s: %v", cacheFile, err) + logrus.Errorf("failed to read CNI cache file %s: %v", cacheFile, err) continue } @@ -582,7 +582,7 @@ func (plugin *cniNetworkPlugin) getCachedNetworkInfo(containerID string) ([]NetA }{} if err := json.Unmarshal(bytes, &cachedInfo); err != nil { - logrus.Warningf("failed to unmarshal CNI cache file %s: %v", cacheFile, err) + logrus.Errorf("failed to unmarshal CNI cache file %s: %v", cacheFile, err) continue } if cachedInfo.Kind != libcni.CNICacheV1 { @@ -632,13 +632,12 @@ func (plugin *cniNetworkPlugin) TearDownPodWithContext(ctx context.Context, podN if err := tearDownLoopback(podNetwork.NetNS); err != nil { // ignore error - logrus.Errorf("Ignoring error tearing down loopback interface: %v", err) + logrus.Warningf("Ignoring error tearing down loopback interface: %v", err) } return plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error { if err := network.deleteFromNetwork(ctx, rt, plugin.cniConfig); err != nil { - logrus.Errorf("Error while removing pod from CNI network %q: %s", network.name, err) - return err + return fmt.Errorf("Error while removing pod from CNI network %q: %s", network.name, err) } return nil }) @@ -718,7 +717,7 @@ func (network *cniNetwork) checkNetwork(ctx context.Context, rt *libcni.RuntimeC result, err = cni.GetNetworkListCachedResult(network.config, rt) if err != nil { - logrus.Errorf("Error GetNetworkListCachedResult: %v", err) + logrus.Errorf("Error getting network list cached result: %v", err) return nil, err } else if result != nil { return result, nil @@ -771,7 +770,6 @@ func (network *cniNetwork) checkNetwork(ctx context.Context, rt *libcni.RuntimeC func (network *cniNetwork) deleteFromNetwork(ctx context.Context, rt *libcni.RuntimeConf, cni *libcni.CNIConfig) error { logrus.Infof("About to del CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type) if err := cni.DelNetworkList(ctx, network.config, rt); err != nil { - logrus.Errorf("Error deleting network: %v", err) return err } return nil diff --git a/vendor/modules.txt b/vendor/modules.txt index b7b8795dd..88ee67917 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -224,7 +224,7 @@ github.com/coreos/go-systemd/v22/dbus github.com/coreos/go-systemd/v22/internal/dlopen github.com/coreos/go-systemd/v22/journal github.com/coreos/go-systemd/v22/sdjournal -# github.com/cri-o/ocicni v0.2.1-0.20201125151022-df072ea5421c +# github.com/cri-o/ocicni v0.2.1-0.20201204103948-b6cbe99b9756 github.com/cri-o/ocicni/pkg/ocicni # github.com/cyphar/filepath-securejoin v0.2.2 github.com/cyphar/filepath-securejoin @@ -628,7 +628,7 @@ golang.org/x/net/proxy # golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/oauth2 golang.org/x/oauth2/internal -# golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 +# golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 golang.org/x/sync/errgroup golang.org/x/sync/semaphore # golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3 |