diff options
-rw-r--r-- | .cirrus.yml | 6 | ||||
-rw-r--r-- | Makefile | 62 | ||||
-rw-r--r-- | cmd/podman/common/create.go | 2 | ||||
-rw-r--r-- | docs/source/markdown/podman-create.1.md | 13 | ||||
-rw-r--r-- | docs/source/markdown/podman-login.1.md | 4 | ||||
-rw-r--r-- | docs/source/markdown/podman-run.1.md | 14 | ||||
-rwxr-xr-x | hack/install_bats.sh | 8 | ||||
-rw-r--r-- | libpod/container_exec.go | 7 | ||||
-rw-r--r-- | libpod/kube.go | 18 | ||||
-rw-r--r-- | libpod/runtime_pod_infra_linux.go | 4 | ||||
-rw-r--r-- | nix/nixpkgs.json | 6 | ||||
-rw-r--r-- | pkg/api/handlers/compat/containers_logs.go | 21 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 13 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/images.go | 17 | ||||
-rw-r--r-- | pkg/specgen/generate/storage.go | 4 | ||||
-rw-r--r-- | test/e2e/build_test.go | 2 | ||||
-rw-r--r-- | test/e2e/exec_test.go | 28 | ||||
-rw-r--r-- | test/e2e/generate_kube_test.go | 34 | ||||
-rw-r--r-- | test/e2e/play_kube_test.go | 68 | ||||
-rw-r--r-- | test/e2e/pod_create_test.go | 24 | ||||
-rw-r--r-- | test/e2e/run_test.go | 70 |
21 files changed, 322 insertions, 103 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 9d220c69a..a11bbbe61 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -594,12 +594,14 @@ static_build_task: mv .cache /nix if [[ -z $(ls -A /nix) ]]; then podman run --rm --privileged -ti -v /:/mnt nixos/nix cp -rfT /nix /mnt/nix; fi podman run --rm --privileged -ti -v /nix:/nix -v ${PWD}:${PWD} -w ${PWD} nixos/nix nix --print-build-logs --option cores 8 --option max-jobs 8 build --file nix/ - mv /nix .cache - chown -Rf $(whoami) .cache binaries_artifacts: path: "result/bin/podman" + save_cache_script: | + mv /nix .cache + chown -Rf $(whoami) .cache + darwin_build_task: depends_on: @@ -11,7 +11,6 @@ PROJECT := github.com/containers/podman GIT_BASE_BRANCH ?= origin/master GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null) GIT_BRANCH_CLEAN ?= $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g") -LIBPOD_IMAGE ?= libpod_dev$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN)) LIBPOD_INSTANCE := libpod_dev PREFIX ?= /usr/local BINDIR ?= ${PREFIX}/bin @@ -38,7 +37,7 @@ PRE_COMMIT = $(shell command -v bin/venv/bin/pre-commit ~/.local/bin/pre-commit SOURCES = $(shell find . -path './.*' -prune -o -name "*.go") -GO_BUILD ?= $(GO) build -mod=vendor +BUILDFLAGS := -mod=vendor $(BUILDFLAGS) BUILDTAGS_CROSS ?= containers_image_openpgp exclude_graphdriver_btrfs exclude_graphdriver_devicemapper exclude_graphdriver_overlay ifneq (,$(findstring varlink,$(BUILDTAGS))) @@ -170,11 +169,11 @@ gofmt: ## Verify the source code gofmt .PHONY: test/checkseccomp/checkseccomp test/checkseccomp/checkseccomp: .gopathok $(wildcard test/checkseccomp/*.go) - $(GO_BUILD) -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ ./test/checkseccomp + $(GO) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ ./test/checkseccomp .PHONY: test/goecho/goechoe test/goecho/goecho: .gopathok $(wildcard test/goecho/*.go) - $(GO_BUILD) -ldflags '$(LDFLAGS_PODMAN)' -o $@ ./test/goecho + $(GO) build $(BUILDFLAGS) -ldflags '$(LDFLAGS_PODMAN)' -o $@ ./test/goecho .PHONY: bin/podman @@ -184,18 +183,18 @@ ifeq (,$(findstring systemd,$(BUILDTAGS))) @echo "Podman is being compiled without the systemd build tag. Install libsystemd on \ Ubuntu or systemd-devel on rpm based distro for journald support." endif - $(GO_BUILD) $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ ./cmd/podman + $(GO) build $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS)" -o $@ ./cmd/podman .PHONY: podman podman: bin/podman .PHONY: bin/podman-remote bin/podman-remote: .gopathok $(SOURCES) go.mod go.sum $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman on remote environment - $(GO_BUILD) $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "${REMOTETAGS}" -o $@ ./cmd/podman + $(GO) build $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "${REMOTETAGS}" -o $@ ./cmd/podman .PHONY: bin/podman-remote-static podman-remote-static: bin/podman-remote-static - CGO_ENABLED=0 $(GO_BUILD) $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN_STATIC)' -tags "${REMOTETAGS}" -o bin/podman-remote-static ./cmd/podman + CGO_ENABLED=0 $(GO) build $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN_STATIC)' -tags "${REMOTETAGS}" -o bin/podman-remote-static ./cmd/podman .PHONY: podman-remote podman-remote: bin/podman-remote @@ -209,7 +208,7 @@ podman.msi: podman-remote podman-remote-windows install-podman-remote-windows-do podman-remote-%: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build podman for a specific GOOS $(eval BINSFX := $(shell test "$*" != "windows" || echo ".exe")) - CGO_ENABLED=0 GOOS=$* $(GO_BUILD) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "${REMOTETAGS}" -o bin/$@$(BINSFX) ./cmd/podman + CGO_ENABLED=0 GOOS=$* $(GO) build $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "${REMOTETAGS}" -o bin/$@$(BINSFX) ./cmd/podman local-cross: $(CROSS_BUILD_TARGETS) ## Cross local compilation @@ -217,7 +216,7 @@ bin/podman.cross.%: .gopathok TARGET="$*"; \ GOOS="$${TARGET%%.*}" \ GOARCH="$${TARGET##*.}" \ - $(GO_BUILD) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags '$(BUILDTAGS_CROSS)' -o "$@" ./cmd/podman + $(GO) build $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags '$(BUILDTAGS_CROSS)' -o "$@" ./cmd/podman # Update nix/nixpkgs.json its latest stable commit .PHONY: nixpkgs @@ -264,46 +263,6 @@ clean: ## Clean artifacts docs/build make -C docs clean -.PHONY: libpodimage -libpodimage: ## Build the libpod image - ${CONTAINER_RUNTIME} build -t ${LIBPOD_IMAGE} . - -.PHONY: dbuild -dbuild: libpodimage - ${CONTAINER_RUNTIME} run --name=${LIBPOD_INSTANCE} --privileged -v ${PWD}:/go/src/${PROJECT} --rm ${LIBPOD_IMAGE} make all - -.PHONY: dbuild-podman-remote -dbuild-podman-remote: libpodimage - ${CONTAINER_RUNTIME} run --name=${LIBPOD_INSTANCE} --privileged -v ${PWD}:/go/src/${PROJECT} --rm ${LIBPOD_IMAGE} $(GOBUILD) -ldflags '$(LDFLAGS_PODMAN)' -tags "$(REMOTETAGS)" -o bin/podman-remote ./cmd/podman - -.PHONY: dbuild-podman-remote-darwin -dbuild-podman-remote-darwin: libpodimage - ${CONTAINER_RUNTIME} run --name=${LIBPOD_INSTANCE} --privileged -v ${PWD}:/go/src/${PROJECT} --rm ${LIBPOD_IMAGE} env GOOS=darwin $(GOBUILD) -ldflags '$(LDFLAGS_PODMAN)' -tags "${REMOTETAGS}" -o bin/podman-remote-darwin ./cmd/podman - -.PHONY: test -test: libpodimage ## Run tests on built image - ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e OCI_RUNTIME -e CGROUP_MANAGER=cgroupfs -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make clean all localunit install.catatonit localintegration - -.PHONY: integration -integration: libpodimage ## Execute integration tests - ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e OCI_RUNTIME -e CGROUP_MANAGER=cgroupfs -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make clean all install.catatonit localintegration - -.PHONY: integration.fedora -integration.fedora: - DIST=Fedora sh .papr_prepare.sh - -.PHONY: integration.centos -integration.centos: - DIST=CentOS sh .papr_prepare.sh - -.PHONY: shell -shell: libpodimage ## Run the built image and attach a shell - ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e CGROUP_MANAGER=cgroupfs -e TESTFLAGS -e OCI_RUNTIME -e TRAVIS -it --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} sh - -.PHONY: testunit -testunit: libpodimage ## Run unittest on the built image - ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e CGROUP_MANAGER=cgroupfs -e OCI_RUNTIME -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make localunit - .PHONY: localunit localunit: test/goecho/goecho varlink_generate hack/check_root.sh make localunit @@ -322,6 +281,9 @@ localunit: test/goecho/goecho varlink_generate $(GO) tool cover -func=${COVERAGE_PATH}/coverprofile > ${COVERAGE_PATH}/functions cat ${COVERAGE_PATH}/functions | sed -n 's/\(total:\).*\([0-9][0-9].[0-9]\)/\1 \2/p' +.PHONY: test +test: localunit localintegration remoteintegration localsystem remotesystem ## Run unit, integration, and system tests. + .PHONY: ginkgo ginkgo: $(GOBIN)/ginkgo -v $(TESTFLAGS) -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -nodes 3 -debug test/e2e/. hack/. @@ -622,7 +584,7 @@ endef .PHONY: .install.ginkgo .install.ginkgo: .gopathok if [ ! -x "$(GOBIN)/ginkgo" ]; then \ - $(GO_BUILD) -o ${GOPATH}/bin/ginkgo ./vendor/github.com/onsi/ginkgo/ginkgo ; \ + $(GO) install $(BUILDFLAGS) ./vendor/github.com/onsi/ginkgo/ginkgo ; \ fi .PHONY: .install.gitvalidation diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index cfbcf6140..7e3dc7fb4 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -509,7 +509,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { "volume", "v", containerConfig.Volumes(), "Bind mount a volume into the container", ) - createFlags.StringSliceVar( + createFlags.StringArrayVar( &cf.VolumesFrom, "volumes-from", []string{}, "Mount volumes from the specified container(s)", diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 9049ffb9f..4a8b311f0 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -1070,11 +1070,11 @@ change propagation properties of source mount. Say `/` is source mount for **--volumes-from**[=*CONTAINER*[:*OPTIONS*]] -Mount volumes from the specified container(s). -*OPTIONS* is a comma delimited list with the following available elements: +Mount volumes from the specified container(s). Used to share volumes between +containers. The *options* is a comma delimited list with the following available elements: -* [rw|ro] -* z +* **rw**|**ro** +* **z** Mounts already mounted volumes from a source container onto another container. You must supply the source's container-id or container-name. @@ -1083,9 +1083,8 @@ the target container. You can share volumes even if the source container is not running. By default, Podman mounts the volumes in the same mode (read-write or -read-only) as it is mounted in the source container. Optionally, you -can change this by suffixing the container-id with either the `ro` or -`rw` keyword. +read-only) as it is mounted in the source container. +You can change this by adding a `ro` or `rw` _option_. Labeling systems like SELinux require that proper labels are placed on volume content mounted into a container. Without a label, the security system might diff --git a/docs/source/markdown/podman-login.1.md b/docs/source/markdown/podman-login.1.md index efc7f05e2..9b4ff74ed 100644 --- a/docs/source/markdown/podman-login.1.md +++ b/docs/source/markdown/podman-login.1.md @@ -18,7 +18,7 @@ Podman will first search for the username and password in the **${XDG\_RUNTIME\_ Podman will then use any existing credentials found in **$HOME/.docker/config.json**. If those credentials are not present, Podman will create **${XDG\_RUNTIME\_DIR}/containers/auth.json** (if the file does not exist) and will then store the username and password from STDIN as a base64 encoded string in it. -For more details about format and configurations of the auth,json file, please refer to containers-auth.json(5) +For more details about format and configurations of the auth.json file, please refer to containers-auth.json(5) **podman [GLOBAL OPTIONS]** @@ -108,7 +108,7 @@ Login Succeeded! ``` ## SEE ALSO -podman(1), podman-logout(1), containers-auth.json(5) +podman(1), podman-logout(1), containers-auth.json(5), containers-registries.conf(5) ## HISTORY August 2017, Originally compiled by Urvashi Mohnani <umohnani@redhat.com> diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 1a7b36a5e..47aa8827f 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -1100,7 +1100,7 @@ will convert /foo into a shared mount point. Alternatively, one can directly change propagation properties of source mount. Say, if _/_ is source mount for _/foo_, then use **mount --make-shared /** to convert _/_ into a shared mount. -**--volumes-from**[=*container-id*[:*options*]] +**--volumes-from**[=*CONTAINER*[:*OPTIONS*]] Mount volumes from the specified container(s). Used to share volumes between containers. The *options* is a comma delimited list with the following available elements: @@ -1108,19 +1108,23 @@ containers. The *options* is a comma delimited list with the following available * **rw**|**ro** * **z** -You can share volumes even if the source container is not running. +Mounts already mounted volumes from a source container onto another +container. You must supply the source's container-id or container-name. +To share a volume, use the --volumes-from option when running +the target container. You can share volumes even if the source container +is not running. By default, Podman mounts the volumes in the same mode (read-write or read-only) as it is mounted in the source container. -You can change this by adding a **ro** or **rw** _option_. +You can change this by adding a `ro` or `rw` _option_. Labeling systems like SELinux require that proper labels are placed on volume content mounted into a container. Without a label, the security system might prevent the processes running inside the container from using the content. By default, Podman does not change the labels set by the OS. -To change a label in the container context, you can add **z** to the volume mount. -This suffix tells Podman to relabel file objects on the shared volumes. The **z** +To change a label in the container context, you can add `z` to the volume mount. +This suffix tells Podman to relabel file objects on the shared volumes. The `z` option tells Podman that two containers share the volume content. As a result, podman labels the content with a shared content label. Shared volume labels allow all containers to read/write content. diff --git a/hack/install_bats.sh b/hack/install_bats.sh index d30e3daf8..01de8b7c6 100755 --- a/hack/install_bats.sh +++ b/hack/install_bats.sh @@ -4,13 +4,19 @@ set -e die() { echo "${1:-No error message given} (from $(basename $0))"; exit 1; } +if [[ "$(type -t bats)" != "" ]]; then + # bats is already installed. + exit 0 +fi + buildDir=$(mktemp -d) git clone https://github.com/bats-core/bats-core $buildDir pushd $buildDir pwd git reset --hard ${VERSION} -./install.sh /usr/local +echo "Installing bats to /usr/local (requires root)" +sudo ./install.sh /usr/local popd rm -rf $buildDir diff --git a/libpod/container_exec.go b/libpod/container_exec.go index f5f54c7cc..fce26acb0 100644 --- a/libpod/container_exec.go +++ b/libpod/container_exec.go @@ -980,11 +980,6 @@ func prepareForExec(c *Container, session *ExecSession) (*ExecOptions, error) { capList = capabilities.AllCapabilities() } - user := c.config.User - if session.Config.User != "" { - user = session.Config.User - } - if err := c.createExecBundle(session.ID()); err != nil { return nil, err } @@ -995,7 +990,7 @@ func prepareForExec(c *Container, session *ExecSession) (*ExecOptions, error) { opts.Env = session.Config.Environment opts.Terminal = session.Config.Terminal opts.Cwd = session.Config.WorkDir - opts.User = user + opts.User = session.Config.User opts.PreserveFDs = session.Config.PreserveFDs opts.DetachKeys = session.Config.DetachKeys opts.ExitCommand = session.Config.ExitCommand diff --git a/libpod/kube.go b/libpod/kube.go index 9d5cbe68b..f83e99d82 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -77,6 +77,24 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) { } pod.Spec.HostAliases = extraHost + // vendor/k8s.io/api/core/v1/types.go: v1.Container cannot save restartPolicy + // so set it at here + for _, ctr := range allContainers { + if !ctr.IsInfra() { + switch ctr.Config().RestartPolicy { + case RestartPolicyAlways: + pod.Spec.RestartPolicy = v1.RestartPolicyAlways + case RestartPolicyOnFailure: + pod.Spec.RestartPolicy = v1.RestartPolicyOnFailure + case RestartPolicyNo: + pod.Spec.RestartPolicy = v1.RestartPolicyNever + default: // some pod create from cmdline, such as "", so set it to Never + pod.Spec.RestartPolicy = v1.RestartPolicyNever + } + break + } + } + if p.SharesPID() { // unfortunately, go doesn't have a nice way to specify a pointer to a bool b := true diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go index 164068638..570cdd38f 100644 --- a/libpod/runtime_pod_infra_linux.go +++ b/libpod/runtime_pod_infra_linux.go @@ -50,7 +50,11 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm entryPoint = config.Entrypoint entryCmd = config.Entrypoint } + } else { // so use the InfraCommand + entrypointSet = true + entryCmd = entryPoint } + if len(config.Cmd) > 0 { // We can't use the default pause command, since we're // sourcing from the image. If we didn't already set an diff --git a/nix/nixpkgs.json b/nix/nixpkgs.json index 6ef89ff82..cd885fce2 100644 --- a/nix/nixpkgs.json +++ b/nix/nixpkgs.json @@ -1,7 +1,7 @@ { "url": "https://github.com/nixos/nixpkgs", - "rev": "5f212d693fe1c82f9c7e20cd57bc69802b36a321", - "date": "2020-08-22T01:42:23+02:00", - "sha256": "1h3819ppllcpw07j884bjh07sma07vrrk1md92sf93cg43nmzncf", + "rev": "d5a689edda8219a1e20fd3871174b994cf0a94a3", + "date": "2020-09-13T01:58:20+02:00", + "sha256": "0m6nmi1fx0glfbg52kqdjgidxylk4p5xnx9v35wlsfi1j2xhkia4", "fetchSubmodules": false } diff --git a/pkg/api/handlers/compat/containers_logs.go b/pkg/api/handlers/compat/containers_logs.go index f6d4a518e..d24b7d959 100644 --- a/pkg/api/handlers/compat/containers_logs.go +++ b/pkg/api/handlers/compat/containers_logs.go @@ -105,6 +105,18 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) { var frame strings.Builder header := make([]byte, 8) + + writeHeader := true + // Docker does not write stream headers iff the container has a tty. + if !utils.IsLibpodRequest(r) { + inspectData, err := ctnr.Inspect(false) + if err != nil { + utils.InternalServerError(w, errors.Wrapf(err, "Failed to obtain logs for Container '%s'", name)) + return + } + writeHeader = !inspectData.Config.Tty + } + for line := range logChannel { if _, found := r.URL.Query()["until"]; found { if line.Time.After(until) { @@ -138,10 +150,13 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) { } frame.WriteString(line.Msg) - binary.BigEndian.PutUint32(header[4:], uint32(frame.Len())) - if _, err := w.Write(header[0:8]); err != nil { - log.Errorf("unable to write log output header: %q", err) + if writeHeader { + binary.BigEndian.PutUint32(header[4:], uint32(frame.Len())) + if _, err := w.Write(header[0:8]); err != nil { + log.Errorf("unable to write log output header: %q", err) + } } + if _, err := io.WriteString(w, frame.String()); err != nil { log.Errorf("unable to write frame string: %q", err) } diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 659cc799c..aa6aeede2 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -299,6 +299,18 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY return nil, err } + var ctrRestartPolicy string + switch podYAML.Spec.RestartPolicy { + case v1.RestartPolicyAlways: + ctrRestartPolicy = libpod.RestartPolicyAlways + case v1.RestartPolicyOnFailure: + ctrRestartPolicy = libpod.RestartPolicyOnFailure + case v1.RestartPolicyNever: + ctrRestartPolicy = libpod.RestartPolicyNo + default: // Default to Always + ctrRestartPolicy = libpod.RestartPolicyAlways + } + containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers)) for _, container := range podYAML.Spec.Containers { pullPolicy := util.PullImageMissing @@ -326,6 +338,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if err != nil { return nil, err } + conf.RestartPolicy = ctrRestartPolicy ctr, err := createconfig.CreateContainerFromCreateConfig(ctx, ic.Libpod, conf, pod) if err != nil { return nil, err diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 50b8342a3..332a7c2eb 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -306,7 +306,22 @@ func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) { } func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts entities.BuildOptions) (*entities.BuildReport, error) { - return images.Build(ir.ClientCxt, containerFiles, opts) + report, err := images.Build(ir.ClientCxt, containerFiles, opts) + if err != nil { + return nil, err + } + // For remote clients, if the option for writing to a file was + // selected, we need to write to the *client's* filesystem. + if len(opts.IIDFile) > 0 { + f, err := os.Create(opts.IIDFile) + if err != nil { + return nil, err + } + if _, err := f.WriteString(report.ID); err != nil { + return nil, err + } + } + return report, nil } func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) { diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go index 7f55317ff..b225f79ee 100644 --- a/pkg/specgen/generate/storage.go +++ b/pkg/specgen/generate/storage.go @@ -195,9 +195,9 @@ func getVolumesFrom(volumesFrom []string, runtime *libpod.Runtime) (map[string]s splitVol := strings.SplitN(volume, ":", 2) if len(splitVol) == 2 { splitOpts := strings.Split(splitVol[1], ",") + setRORW := false + setZ := false for _, opt := range splitOpts { - setRORW := false - setZ := false switch opt { case "z": if setZ { diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go index 0b6e919d0..06054bcb4 100644 --- a/test/e2e/build_test.go +++ b/test/e2e/build_test.go @@ -179,8 +179,6 @@ var _ = Describe("Podman build", func() { }) It("podman build basic alpine and print id to external file", func() { - SkipIfRemote() - // Switch to temp dir and restore it afterwards cwd, err := os.Getwd() Expect(err).To(BeNil()) diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go index 055546f88..6841aa5a2 100644 --- a/test/e2e/exec_test.go +++ b/test/e2e/exec_test.go @@ -283,6 +283,34 @@ var _ = Describe("Podman exec", func() { Expect(strings.Contains(exec.OutputToString(), fmt.Sprintf("%s(%s)", gid, groupName))).To(BeTrue()) }) + It("podman exec preserves container groups with --user and --group-add", func() { + SkipIfRemote() + dockerfile := `FROM fedora-minimal +RUN groupadd -g 4000 first +RUN groupadd -g 4001 second +RUN useradd -u 1000 auser` + imgName := "testimg" + podmanTest.BuildImage(dockerfile, imgName, "false") + + ctrName := "testctr" + ctr := podmanTest.Podman([]string{"run", "-t", "-i", "-d", "--name", ctrName, "--user", "auser:first", "--group-add", "second", imgName, "sleep", "300"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(Equal(0)) + + exec := podmanTest.Podman([]string{"exec", "-t", ctrName, "id"}) + exec.WaitWithDefaultTimeout() + Expect(exec.ExitCode()).To(Equal(0)) + output := exec.OutputToString() + Expect(strings.Contains(output, "4000(first)")).To(BeTrue()) + Expect(strings.Contains(output, "4001(second)")).To(BeTrue()) + Expect(strings.Contains(output, "1000(auser)")).To(BeTrue()) + + // Kill the container just so the test does not take 15 seconds to stop. + kill := podmanTest.Podman([]string{"kill", ctrName}) + kill.WaitWithDefaultTimeout() + Expect(kill.ExitCode()).To(Equal(0)) + }) + It("podman exec --detach", func() { ctrName := "testctr" ctr := podmanTest.Podman([]string{"run", "-t", "-i", "-d", "--name", ctrName, ALPINE, "top"}) diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index e886c6000..a3a841dc6 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -3,6 +3,7 @@ package integration import ( "os" "path/filepath" + "strconv" . "github.com/containers/podman/v2/test/utils" "github.com/ghodss/yaml" @@ -201,6 +202,39 @@ var _ = Describe("Podman generate kube", func() { // Expect(err).To(BeNil()) }) + It("podman generate kube on pod with restartPolicy", func() { + // podName, set, expect + testSli := [][]string{ + {"testPod1", "", "Never"}, // some pod create from cmdline, so set it to Never + {"testPod2", "always", "Always"}, + {"testPod3", "on-failure", "OnFailure"}, + {"testPod4", "no", "Never"}, + } + + for k, v := range testSli { + podName := v[0] + podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName}) + podSession.WaitWithDefaultTimeout() + Expect(podSession.ExitCode()).To(Equal(0)) + + ctrName := "ctr" + strconv.Itoa(k) + ctr1Session := podmanTest.Podman([]string{"create", "--name", ctrName, "--pod", podName, + "--restart", v[1], ALPINE, "top"}) + ctr1Session.WaitWithDefaultTimeout() + Expect(ctr1Session.ExitCode()).To(Equal(0)) + + kube := podmanTest.Podman([]string{"generate", "kube", podName}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + pod := new(v1.Pod) + err := yaml.Unmarshal(kube.Out.Contents(), pod) + Expect(err).To(BeNil()) + + Expect(string(pod.Spec.RestartPolicy)).To(Equal(v[2])) + } + }) + It("podman generate kube on pod with ports", func() { podName := "test" podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName, "-p", "4000:4000", "-p", "5000:5000"}) diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index f58862ab2..7a5aebcc2 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -46,6 +46,7 @@ metadata: {{ end }} spec: + restartPolicy: {{ .RestartPolicy }} hostname: {{ .Hostname }} hostAliases: {{ range .HostAliases }} @@ -165,6 +166,7 @@ spec: {{- end }} {{- end }} spec: + restartPolicy: {{ .RestartPolicy }} hostname: {{ .Hostname }} containers: {{ with .Ctrs }} @@ -274,13 +276,14 @@ func generateDeploymentKubeYaml(deployment *Deployment, fileName string) error { // Pod describes the options a kube yaml can be configured at pod level type Pod struct { - Name string - Hostname string - HostAliases []HostAlias - Ctrs []*Ctr - Volumes []*Volume - Labels map[string]string - Annotations map[string]string + Name string + RestartPolicy string + Hostname string + HostAliases []HostAlias + Ctrs []*Ctr + Volumes []*Volume + Labels map[string]string + Annotations map[string]string } type HostAlias struct { @@ -293,13 +296,14 @@ type HostAlias struct { // if no containers are added, it will add the default container func getPod(options ...podOption) *Pod { p := Pod{ - Name: defaultPodName, - Hostname: "", - HostAliases: nil, - Ctrs: make([]*Ctr, 0), - Volumes: make([]*Volume, 0), - Labels: make(map[string]string), - Annotations: make(map[string]string), + Name: defaultPodName, + RestartPolicy: "Never", + Hostname: "", + HostAliases: nil, + Ctrs: make([]*Ctr, 0), + Volumes: make([]*Volume, 0), + Labels: make(map[string]string), + Annotations: make(map[string]string), } for _, option := range options { option(&p) @@ -312,6 +316,12 @@ func getPod(options ...podOption) *Pod { type podOption func(*Pod) +func withPodName(name string) podOption { + return func(pod *Pod) { + pod.Name = name + } +} + func withHostname(h string) podOption { return func(pod *Pod) { pod.Hostname = h @@ -333,6 +343,12 @@ func withCtr(c *Ctr) podOption { } } +func withRestartPolicy(policy string) podOption { + return func(pod *Pod) { + pod.RestartPolicy = policy + } +} + func withLabel(k, v string) podOption { return func(pod *Pod) { pod.Labels[k] = v @@ -649,6 +665,30 @@ var _ = Describe("Podman generate kube", func() { Expect(inspect.OutputToString()).To(ContainSubstring(`[echo hello world]`)) }) + It("podman play kube test restartPolicy", func() { + // podName, set, expect + testSli := [][]string{ + {"testPod1", "", "always"}, // Default eqaul to always + {"testPod2", "Always", "always"}, + {"testPod3", "OnFailure", "on-failure"}, + {"testPod4", "Never", "no"}, + } + for _, v := range testSli { + pod := getPod(withPodName(v[0]), withRestartPolicy(v[1])) + err := generatePodKubeYaml(pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "{{.HostConfig.RestartPolicy.Name}}"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(Equal(v[2])) + } + }) + It("podman play kube test hostname", func() { pod := getPod() err := generatePodKubeYaml(pod, kubeYaml) diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index ed62e8a4b..168150bff 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -345,6 +345,12 @@ var _ = Describe("Podman pod create", func() { check1.WaitWithDefaultTimeout() Expect(check1.ExitCode()).To(Equal(0)) Expect(check1.OutputToString()).To(Equal("/pause")) + + // check the Path and Args + check2 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Path}}:{{.Args}}", data.Containers[0].ID}) + check2.WaitWithDefaultTimeout() + Expect(check2.ExitCode()).To(Equal(0)) + Expect(check2.OutputToString()).To(Equal("/pause:[/pause]")) }) It("podman create pod with --infra-command", func() { @@ -362,6 +368,12 @@ var _ = Describe("Podman pod create", func() { check1.WaitWithDefaultTimeout() Expect(check1.ExitCode()).To(Equal(0)) Expect(check1.OutputToString()).To(Equal("/pause1")) + + // check the Path and Args + check2 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Path}}:{{.Args}}", data.Containers[0].ID}) + check2.WaitWithDefaultTimeout() + Expect(check2.ExitCode()).To(Equal(0)) + Expect(check2.OutputToString()).To(Equal("/pause1:[/pause1]")) }) It("podman create pod with --infra-image", func() { @@ -383,6 +395,12 @@ entrypoint ["/fromimage"] check1.WaitWithDefaultTimeout() Expect(check1.ExitCode()).To(Equal(0)) Expect(check1.OutputToString()).To(Equal("/fromimage")) + + // check the Path and Args + check2 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Path}}:{{.Args}}", data.Containers[0].ID}) + check2.WaitWithDefaultTimeout() + Expect(check2.ExitCode()).To(Equal(0)) + Expect(check2.OutputToString()).To(Equal("/fromimage:[/fromimage]")) }) It("podman create pod with --infra-command --infra-image", func() { @@ -404,5 +422,11 @@ entrypoint ["/fromimage"] check1.WaitWithDefaultTimeout() Expect(check1.ExitCode()).To(Equal(0)) Expect(check1.OutputToString()).To(Equal("/fromcommand")) + + // check the Path and Args + check2 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Path}}:{{.Args}}", data.Containers[0].ID}) + check2.WaitWithDefaultTimeout() + Expect(check2.ExitCode()).To(Equal(0)) + Expect(check2.OutputToString()).To(Equal("/fromcommand:[/fromcommand]")) }) }) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index cbfb6bf59..4376bf309 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -733,23 +733,85 @@ USER mail` err := os.MkdirAll(vol, 0755) Expect(err).To(BeNil()) - volFile := filepath.Join(vol, "test.txt") + filename := "test.txt" + volFile := filepath.Join(vol, filename) data := "Testing --volumes-from!!!" err = ioutil.WriteFile(volFile, []byte(data), 0755) Expect(err).To(BeNil()) + mountpoint := "/myvol/" - session := podmanTest.Podman([]string{"create", "--volume", vol + ":/myvol", redis, "sh"}) + session := podmanTest.Podman([]string{"create", "--volume", vol + ":" + mountpoint, ALPINE, "cat", mountpoint + filename}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) ctrID := session.OutputToString() - session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID, ALPINE, "echo", "'testing read-write!' >> myvol/test.txt"}) + session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID, ALPINE, "cat", mountpoint + filename}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal(data)) - session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID + ":z", ALPINE, "ls"}) + session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID, ALPINE, "sh", "-c", "echo test >> " + mountpoint + filename}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"start", "--attach", ctrID}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal(data + "test")) + }) + + It("podman run --volumes-from flag options", func() { + vol := filepath.Join(podmanTest.TempDir, "vol-test") + err := os.MkdirAll(vol, 0755) + Expect(err).To(BeNil()) + + filename := "test.txt" + volFile := filepath.Join(vol, filename) + data := "Testing --volumes-from!!!" + err = ioutil.WriteFile(volFile, []byte(data), 0755) + Expect(err).To(BeNil()) + mountpoint := "/myvol/" + + session := podmanTest.Podman([]string{"create", "--volume", vol + ":" + mountpoint, ALPINE, "cat", mountpoint + filename}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + ctrID := session.OutputToString() + + // check that the read only option works + session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID + ":ro", ALPINE, "touch", mountpoint + "abc.txt"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + Expect(session.ErrorToString()).To(ContainSubstring("Read-only file system")) + + // check that both z and ro options work + session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID + ":ro,z", ALPINE, "cat", mountpoint + filename}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal(data)) + + // check that multiple ro/rw are not working + session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID + ":ro,rw", ALPINE, "cat", mountpoint + filename}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(125)) + Expect(session.ErrorToString()).To(ContainSubstring("cannot set ro or rw options more than once")) + + // check that multiple z options are not working + session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID + ":z,z,ro", ALPINE, "cat", mountpoint + filename}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(125)) + Expect(session.ErrorToString()).To(ContainSubstring("cannot set :z more than once in mount options")) + + // create new read only volume + session = podmanTest.Podman([]string{"create", "--volume", vol + ":" + mountpoint + ":ro", ALPINE, "cat", mountpoint + filename}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + ctrID = session.OutputToString() + + // check if the original volume was mounted as read only that --volumes-from also mount it as read only + session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID, ALPINE, "touch", mountpoint + "abc.txt"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + Expect(session.ErrorToString()).To(ContainSubstring("Read-only file system")) }) It("podman run --volumes-from flag with built-in volumes", func() { |