From 2fb1511690dba70adf25c36c28ec4bad2af79106 Mon Sep 17 00:00:00 2001
From: Matthew Heon <mheon@redhat.com>
Date: Mon, 15 Feb 2021 11:58:24 -0500
Subject: Fix an issue where copyup could fail with ENOENT

This one is rather bizarre because it triggers only on some
systems. I've included a CI test, for example, but I'm 99% sure
we use images in CI that have volumes over empty directories, and
the earlier patch to change copy-up implementation passed CI
without complaint.

I can reproduce this on a stock F33 VM, but that's the only place
I have been able to see it.

Regardless, the issue: under certain as-yet-unidentified
environmental conditions, the copier.Get method will return an
ENOENT attempting to stream a directory that is empty. Work
around this by avoiding the copy altogether in this case.

Signed-off-by: Matthew Heon <mheon@redhat.com>
---
 test/e2e/run_volume_test.go | 12 ++++++++++++
 1 file changed, 12 insertions(+)

(limited to 'test')

diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 19d82c974..91d8f15f4 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -322,6 +322,18 @@ RUN sh -c "cd /etc/apk && ln -s ../../testfile"`
 		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
 	})
 
+	It("podman named volume copyup empty directory", func() {
+		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/srv"})
+		baselineSession.WaitWithDefaultTimeout()
+		Expect(baselineSession.ExitCode()).To(Equal(0))
+		baselineOutput := baselineSession.OutputToString()
+
+		outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/srv", ALPINE, "ls", "/srv"})
+		outputSession.WaitWithDefaultTimeout()
+		Expect(outputSession.ExitCode()).To(Equal(0))
+		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
+	})
+
 	It("podman read-only tmpfs conflict with volume", func() {
 		session := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "-v", "tmp_volume:" + dest, ALPINE, "touch", dest + "/a"})
 		session.WaitWithDefaultTimeout()
-- 
cgit v1.2.3-54-g00ecf


From 59d2eac78a2a8e619d9c1c53b065f34f0e19795c Mon Sep 17 00:00:00 2001
From: Matthew Heon <matthew.heon@pm.me>
Date: Wed, 17 Feb 2021 14:09:28 -0500
Subject: Change source path resolution for volume copy-up

Instead of using the container's mountpoint as the base of the
chroot and indexing from there by the volume directory, instead
use the full path of what we want to copy as the base of the
chroot and copy everything in it. This resolves the bug, ends up
being a bit simpler code-wise (no string concatenation, as we
already have the full path calculated for other checks), and
seems more understandable than trying to resolve things on the
destination side of the copy-up.

Fixes #9354

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
---
 libpod/container_internal.go |  2 +-
 test/e2e/run_volume_test.go  | 12 ++++++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

(limited to 'test')

diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index ac7c1b2dc..7aaa002b2 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1642,7 +1642,7 @@ func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string)
 			getOptions := copier.GetOptions{
 				KeepDirectoryNames: false,
 			}
-			errChan <- copier.Get(mountpoint, "", getOptions, []string{v.Dest + "/."}, writer)
+			errChan <- copier.Get(srcDir, "", getOptions, []string{"/."}, writer)
 		}()
 
 		// Copy, volume side: stream what we've written to the pipe, into
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 91d8f15f4..d81fb769d 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -334,6 +334,18 @@ RUN sh -c "cd /etc/apk && ln -s ../../testfile"`
 		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
 	})
 
+	It("podman named volume copyup of /var", func() {
+		baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", fedoraMinimal, "ls", "/var"})
+		baselineSession.WaitWithDefaultTimeout()
+		Expect(baselineSession.ExitCode()).To(Equal(0))
+		baselineOutput := baselineSession.OutputToString()
+
+		outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/var", fedoraMinimal, "ls", "/var"})
+		outputSession.WaitWithDefaultTimeout()
+		Expect(outputSession.ExitCode()).To(Equal(0))
+		Expect(outputSession.OutputToString()).To(Equal(baselineOutput))
+	})
+
 	It("podman read-only tmpfs conflict with volume", func() {
 		session := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "-v", "tmp_volume:" + dest, ALPINE, "touch", dest + "/a"})
 		session.WaitWithDefaultTimeout()
-- 
cgit v1.2.3-54-g00ecf


From af62cb3ca9ab516627c5fb991d541555f8af13f4 Mon Sep 17 00:00:00 2001
From: Daniel J Walsh <dwalsh@redhat.com>
Date: Wed, 17 Feb 2021 07:52:42 -0500
Subject: podman ps --format '{{ .Size }}' requires --size option

Podman -s crashes when the user specifies the '{{ .Size }}` format
on the podman ps command, without specifying the --size option.

This PR will stop the crash and print out a logrus.Error stating that
the caller should add the --size option.

Fixes: https://github.com/containers/podman/issues/9408

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
---
 cmd/podman/containers/ps.go |  6 ++++++
 test/e2e/ps_test.go         | 15 +++++++++++++++
 2 files changed, 21 insertions(+)

(limited to 'test')

diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 23baca70f..09921b93d 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -22,6 +22,7 @@ import (
 	"github.com/cri-o/ocicni/pkg/ocicni"
 	"github.com/docker/go-units"
 	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 )
 
@@ -392,6 +393,11 @@ func (l psReporter) Command() string {
 // Size returns the rootfs and virtual sizes in human duration in
 // and output form (string) suitable for ps
 func (l psReporter) Size() string {
+	if l.ListContainer.Size == nil {
+		logrus.Errorf("Size format requires --size option")
+		return ""
+	}
+
 	virt := units.HumanSizeWithPrecision(float64(l.ListContainer.Size.RootFsSize), 3)
 	s := units.HumanSizeWithPrecision(float64(l.ListContainer.Size.RwSize), 3)
 	return fmt.Sprintf("%s (virtual %s)", s, virt)
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 225bd538e..016b4c8cd 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -350,6 +350,21 @@ var _ = Describe("Podman ps", func() {
 		Expect(session).To(ExitWithError())
 	})
 
+	It("podman --format by size", func() {
+		session := podmanTest.Podman([]string{"create", "busybox", "ls"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+
+		session = podmanTest.Podman([]string{"create", "-t", ALPINE, "top"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+
+		session = podmanTest.Podman([]string{"ps", "-a", "--format", "{{.Size}}"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+		Expect(session.ErrorToString()).To(ContainSubstring("Size format requires --size option"))
+	})
+
 	It("podman --sort by size", func() {
 		session := podmanTest.Podman([]string{"create", "busybox", "ls"})
 		session.WaitWithDefaultTimeout()
-- 
cgit v1.2.3-54-g00ecf


From 865769d911254a0f2f650322825391f5b31413a2 Mon Sep 17 00:00:00 2001
From: Daniel J Walsh <dwalsh@redhat.com>
Date: Tue, 16 Feb 2021 17:03:32 -0500
Subject: Ignore entrypoint=[\"\"]

We recieved an issue with an image that was built with
entrypoint=[""]
This blows up on Podman, but works on Docker.

When we setup the OCI Runtime, we should drop
entrypoint if it is == [""]

https://github.com/containers/podman/issues/9377

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
---
 pkg/specgen/generate/oci.go     |  5 ++++-
 test/e2e/run_entrypoint_test.go | 12 ++++++++++++
 2 files changed, 16 insertions(+), 1 deletion(-)

(limited to 'test')

diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index e62131244..d1d2f552e 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -105,7 +105,10 @@ func makeCommand(ctx context.Context, s *specgen.SpecGenerator, img *image.Image
 		entrypoint = newEntry
 	}
 
-	finalCommand = append(finalCommand, entrypoint...)
+	// Don't append the entrypoint if it is [""]
+	if len(entrypoint) != 1 || entrypoint[0] != "" {
+		finalCommand = append(finalCommand, entrypoint...)
+	}
 
 	// Only use image command if the user did not manually set an
 	// entrypoint.
diff --git a/test/e2e/run_entrypoint_test.go b/test/e2e/run_entrypoint_test.go
index cac3d759d..389f142b1 100644
--- a/test/e2e/run_entrypoint_test.go
+++ b/test/e2e/run_entrypoint_test.go
@@ -43,6 +43,18 @@ CMD []
 		Expect(session.ExitCode()).To(Equal(125))
 	})
 
+	It("podman run entrypoint == [\"\"]", func() {
+		dockerfile := `FROM quay.io/libpod/alpine:latest
+ENTRYPOINT [""]
+CMD []
+`
+		podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false")
+		session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest", "echo", "hello"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+		Expect(session.OutputToString()).To(Equal("hello"))
+	})
+
 	It("podman run entrypoint", func() {
 		dockerfile := `FROM quay.io/libpod/alpine:latest
 ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
-- 
cgit v1.2.3-54-g00ecf


From 32350c758ddfef52a53e7d74d4a68785bc54aaef Mon Sep 17 00:00:00 2001
From: Valentin Rothberg <rothberg@redhat.com>
Date: Tue, 16 Feb 2021 14:15:21 +0100
Subject: do not set empty $HOME

Make sure to not set an empty $HOME for containers and let it default to
"/".

https://github.com/containers/crun/pull/599 is required to fully
address #9378.

Partially-Fixes: #9378
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>

<MH: Fixed cherry-pick conflicts>

Signed-off-by: Matthew Heon <mheon@redhat.com>
---
 libpod/container_internal_linux.go | 2 +-
 test/system/030-run.bats           | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)

(limited to 'test')

diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 952cc42d1..8a55f01b1 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -457,7 +457,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
 			break
 		}
 	}
-	if !hasHomeSet {
+	if !hasHomeSet && execUser.Home != "" {
 		c.config.Spec.Process.Env = append(c.config.Spec.Process.Env, fmt.Sprintf("HOME=%s", execUser.Home))
 	}
 
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 98e34238e..49fa92f57 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -623,4 +623,10 @@ json-file | f
     fi
 }
 
+@test "podman run - do not set empty HOME" {
+    # Regression test for #9378.
+    run_podman run --rm --user 100 $IMAGE printenv
+    is "$output" ".*HOME=/.*"
+}
+
 # vim: filetype=sh
-- 
cgit v1.2.3-54-g00ecf


From e9328d13f4d6360fe772bc18475e0e71ae8280b9 Mon Sep 17 00:00:00 2001
From: baude <bbaude@redhat.com>
Date: Mon, 15 Feb 2021 09:32:49 -0600
Subject: Fix panic in pod creation

when creating a pod with --infra-image and using a untagged image for
the infra-image (none/none), the lookup for the image's name was
creating a panic.

Fixes: #9374

Signed-off-by: baude <bbaude@redhat.com>
---
 libpod/runtime_pod_infra_linux.go |  5 ++++-
 test/e2e/common_test.go           | 11 +++++++++--
 test/e2e/pod_create_test.go       | 14 ++++++++++++++
 3 files changed, 27 insertions(+), 3 deletions(-)

(limited to 'test')

diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index 564851f4e..40632bdd0 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -226,7 +226,10 @@ func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container,
 	if err != nil {
 		return nil, err
 	}
-	imageName := newImage.Names()[0]
+	imageName := "none"
+	if len(newImage.Names()) > 0 {
+		imageName = newImage.Names()[0]
+	}
 	imageID := data.ID
 
 	return r.makeInfraContainer(ctx, p, imageName, r.config.Engine.InfraImage, imageID, data.Config)
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 8a452f340..88cd7dd9c 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -432,13 +432,20 @@ func (p *PodmanTestIntegration) RunLsContainerInPod(name, pod string) (*PodmanSe
 
 // BuildImage uses podman build and buildah to build an image
 // called imageName based on a string dockerfile
-func (p *PodmanTestIntegration) BuildImage(dockerfile, imageName string, layers string) {
+func (p *PodmanTestIntegration) BuildImage(dockerfile, imageName string, layers string) string {
 	dockerfilePath := filepath.Join(p.TempDir, "Dockerfile")
 	err := ioutil.WriteFile(dockerfilePath, []byte(dockerfile), 0755)
 	Expect(err).To(BeNil())
-	session := p.Podman([]string{"build", "--layers=" + layers, "-t", imageName, "--file", dockerfilePath, p.TempDir})
+	cmd := []string{"build", "--layers=" + layers, "--file", dockerfilePath}
+	if len(imageName) > 0 {
+		cmd = append(cmd, []string{"-t", imageName}...)
+	}
+	cmd = append(cmd, p.TempDir)
+	session := p.Podman(cmd)
 	session.Wait(240)
 	Expect(session).Should(Exit(0), fmt.Sprintf("BuildImage session output: %q", session.OutputToString()))
+	output := session.OutputToStringArray()
+	return output[len(output)-1]
 }
 
 // PodmanPID execs podman and returns its PID
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index e57712f62..0a7a5101e 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -501,4 +501,18 @@ entrypoint ["/fromimage"]
 		Expect(session.OutputToString()).To(ContainSubstring("inet 127.0.0.1/8 scope host lo"))
 		Expect(len(session.OutputToStringArray())).To(Equal(1))
 	})
+
+	It("podman pod create --infra-image w/untagged image", func() {
+		podmanTest.AddImageToRWStore(ALPINE)
+		dockerfile := `FROM quay.io/libpod/alpine:latest
+ENTRYPOINT ["sleep","99999"]
+		`
+		// This builds a none/none image
+		iid := podmanTest.BuildImage(dockerfile, "", "true")
+
+		create := podmanTest.Podman([]string{"pod", "create", "--infra-image", iid})
+		create.WaitWithDefaultTimeout()
+		Expect(create.ExitCode()).To(BeZero())
+	})
+
 })
-- 
cgit v1.2.3-54-g00ecf


From 8d11461a7a659830619cfcdfa2999f8a65beb79a Mon Sep 17 00:00:00 2001
From: Valentin Rothberg <rothberg@redhat.com>
Date: Tue, 16 Feb 2021 13:32:31 +0100
Subject: images/create: always pull image

The `images/create` endpoint should always attempt to pull a newer
image.  Previously, the local images was used which is not compatible
with Docker and caused issues in the Gitlab CI.

Fixes: #9232
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
---
 pkg/api/handlers/compat/images.go | 14 ++------------
 test/apiv2/10-images.at           |  7 +++++++
 2 files changed, 9 insertions(+), 12 deletions(-)

(limited to 'test')

diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 0ae0f3bcf..05d4e2f65 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -10,7 +10,6 @@ import (
 	"strings"
 
 	"github.com/containers/buildah"
-	"github.com/containers/common/pkg/config"
 	"github.com/containers/image/v5/manifest"
 	"github.com/containers/podman/v2/libpod"
 	image2 "github.com/containers/podman/v2/libpod/image"
@@ -18,6 +17,7 @@ import (
 	"github.com/containers/podman/v2/pkg/api/handlers/utils"
 	"github.com/containers/podman/v2/pkg/auth"
 	"github.com/containers/podman/v2/pkg/domain/entities"
+	"github.com/containers/podman/v2/pkg/util"
 	"github.com/gorilla/schema"
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
@@ -237,16 +237,6 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
 	if sys := runtime.SystemContext(); sys != nil {
 		registryOpts.DockerCertPath = sys.DockerCertPath
 	}
-	rtc, err := runtime.GetConfig()
-	if err != nil {
-		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
-		return
-	}
-	pullPolicy, err := config.ValidatePullPolicy(rtc.Engine.PullPolicy)
-	if err != nil {
-		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
-		return
-	}
 	img, err := runtime.ImageRuntime().New(r.Context(),
 		fromImage,
 		"", // signature policy
@@ -255,7 +245,7 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
 		&registryOpts,
 		image2.SigningOptions{},
 		nil, // label
-		pullPolicy,
+		util.PullImageAlways,
 	)
 	if err != nil {
 		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index 7b500bf57..30090d806 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -45,6 +45,13 @@ t POST "images/create?fromImage=alpine" '' 200
 
 t POST "images/create?fromImage=alpine&tag=latest" '' 200
 
+# Make sure that new images are pulled
+old_iid=$(podman image inspect --format "{{.ID}}" docker.io/library/alpine:latest)
+podman rmi -f docker.io/library/alpine:latest
+podman tag $IMAGE docker.io/library/alpine:latest
+t POST "images/create?fromImage=alpine" '' 200 .error=null .status~".*$old_iid.*"
+podman untag $IMAGE docker.io/library/alpine:latest
+
 t POST "images/create?fromImage=quay.io/libpod/alpine&tag=sha256:fa93b01658e3a5a1686dc3ae55f170d8de487006fb53a28efcd12ab0710a2e5f" '' 200
 
 # Display the image history
-- 
cgit v1.2.3-54-g00ecf


From 2f3ae7ce5bbe03db13acfa529b5a396e65de1655 Mon Sep 17 00:00:00 2001
From: Valentin Rothberg <rothberg@redhat.com>
Date: Mon, 15 Feb 2021 11:35:34 +0100
Subject: podman build: pass runtime to buildah

Make sure that Podman's default OCI runtime is passed to Buildah in
`podman build`.  In theory, Podman and Buildah should use the same
defaults but the projects move at different speeds and it turns out
we caused a regression in v3.0.

Fixes: #9365
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
---
 libpod/runtime_img.go      |  5 +++++
 test/system/070-build.bats | 25 +++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

(limited to 'test')

diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index 2c5442bd2..e6caf2626 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -166,6 +166,11 @@ func (r *Runtime) newImageBuildCompleteEvent(idOrName string) {
 
 // Build adds the runtime to the imagebuildah call
 func (r *Runtime) Build(ctx context.Context, options imagebuildah.BuildOptions, dockerfiles ...string) (string, reference.Canonical, error) {
+	if options.Runtime == "" {
+		// Make sure that build containers use the same runtime as Podman (see #9365).
+		conf := util.DefaultContainerConfig()
+		options.Runtime = conf.Engine.OCIRuntime
+	}
 	id, ref, err := imagebuildah.BuildDockerfiles(ctx, r.store, options, dockerfiles...)
 	// Write event for build completion
 	r.newImageBuildCompleteEvent(id)
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
index bf9fa789c..000998f3a 100644
--- a/test/system/070-build.bats
+++ b/test/system/070-build.bats
@@ -46,6 +46,31 @@ EOF
     is "$output" ".*invalidflag" "failed when passing undefined flags to the runtime"
 }
 
+@test "podman build - set runtime" {
+    skip_if_remote "--runtime flag not supported for remote"
+    # Test on the CLI and via containers.conf
+
+    tmpdir=$PODMAN_TMPDIR/build-test
+    run mkdir -p $tmpdir
+    containerfile=$tmpdir/Containerfile
+    cat >$containerfile <<EOF
+FROM $IMAGE
+RUN echo $rand_content
+EOF
+
+    run_podman 125 --runtime=idonotexist build -t build_test $tmpdir
+    is "$output" ".*\"idonotexist\" not found.*" "failed when passing invalid OCI runtime via CLI"
+
+    containersconf=$tmpdir/containers.conf
+    cat >$containersconf <<EOF
+[engine]
+runtime="idonotexist"
+EOF
+
+    CONTAINERS_CONF="$containersconf" run_podman 125 build -t build_test $tmpdir
+    is "$output" ".*\"idonotexist\" not found.*" "failed when passing invalid OCI runtime via containers.conf"
+}
+
 # Regression from v1.5.0. This test passes fine in v1.5.0, fails in 1.6
 @test "podman build - cache (#3920)" {
     # Make an empty test directory, with a subdirectory used for tar
-- 
cgit v1.2.3-54-g00ecf


From 8dc2fb2c78a8404341e9e037ee4418d876c26366 Mon Sep 17 00:00:00 2001
From: Matej Vasek <mvasek@redhat.com>
Date: Mon, 15 Feb 2021 15:08:11 +0100
Subject: fix create container: handle empty host port

Signed-off-by: Matej Vasek <mvasek@redhat.com>
---
 cmd/podman/common/create_opts.go      | 6 +++++-
 test/python/docker/test_containers.py | 7 +++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

(limited to 'test')

diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index d86a6d364..ee6165b1b 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -222,7 +222,11 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
 	// publish
 	for port, pbs := range cc.HostConfig.PortBindings {
 		for _, pb := range pbs {
-			hostport, err := strconv.Atoi(pb.HostPort)
+			var hostport int
+			var err error
+			if pb.HostPort != "" {
+				hostport, err = strconv.Atoi(pb.HostPort)
+			}
 			if err != nil {
 				return nil, nil, err
 			}
diff --git a/test/python/docker/test_containers.py b/test/python/docker/test_containers.py
index 5c2a5fef2..337cacd5c 100644
--- a/test/python/docker/test_containers.py
+++ b/test/python/docker/test_containers.py
@@ -86,6 +86,13 @@ class TestContainers(unittest.TestCase):
         containers = self.client.containers.list(all=True)
         self.assertEqual(len(containers), 2)
 
+    def test_start_container_with_random_port_bind(self):
+        container = self.client.containers.create(image=constant.ALPINE,
+                                                  name="containerWithRandomBind",
+                                                  ports={'1234/tcp': None})
+        containers = self.client.containers.list(all=True)
+        self.assertTrue(container in containers)
+
     def test_stop_container(self):
         top = self.client.containers.get(TestContainers.topContainerId)
         self.assertEqual(top.status, "running")
-- 
cgit v1.2.3-54-g00ecf


From 538ced1258b6fcf698e9fee18f98bd4f534c674d Mon Sep 17 00:00:00 2001
From: Daniel J Walsh <dwalsh@redhat.com>
Date: Mon, 15 Feb 2021 16:22:44 -0500
Subject: Don't chown workdir if it already exists

Currently podman is always chowning the WORKDIR to root:root
This PR will return if the WORKDIR already exists.

Fixes: https://github.com/containers/podman/issues/9387

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
---
 libpod/container_internal_linux.go | 26 +++++++++++++++++---------
 test/e2e/run_working_dir_test.go   |  6 +++++-
 2 files changed, 22 insertions(+), 10 deletions(-)

(limited to 'test')

diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 8a55f01b1..a45eae45f 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -21,6 +21,7 @@ import (
 
 	cnitypes "github.com/containernetworking/cni/pkg/types/current"
 	"github.com/containernetworking/plugins/pkg/ns"
+	"github.com/containers/buildah/pkg/chrootuser"
 	"github.com/containers/buildah/pkg/overlay"
 	"github.com/containers/common/pkg/apparmor"
 	"github.com/containers/common/pkg/config"
@@ -202,10 +203,17 @@ func (c *Container) resolveWorkDir() error {
 	}
 	logrus.Debugf("Workdir %q resolved to host path %q", workdir, resolvedWorkdir)
 
-	// No need to create it (e.g., `--workdir=/foo`), so let's make sure
-	// the path exists on the container.
+	st, err := os.Stat(resolvedWorkdir)
+	if err == nil {
+		if !st.IsDir() {
+			return errors.Errorf("workdir %q exists on container %s, but is not a directory", workdir, c.ID())
+		}
+		return nil
+	}
 	if !c.config.CreateWorkingDir {
-		if _, err := os.Stat(resolvedWorkdir); err != nil {
+		// No need to create it (e.g., `--workdir=/foo`), so let's make sure
+		// the path exists on the container.
+		if err != nil {
 			if os.IsNotExist(err) {
 				return errors.Errorf("workdir %q does not exist on container %s", workdir, c.ID())
 			}
@@ -215,11 +223,6 @@ func (c *Container) resolveWorkDir() error {
 		}
 		return nil
 	}
-
-	// Ensure container entrypoint is created (if required).
-	rootUID := c.RootUID()
-	rootGID := c.RootGID()
-
 	if err := os.MkdirAll(resolvedWorkdir, 0755); err != nil {
 		if os.IsExist(err) {
 			return nil
@@ -227,7 +230,12 @@ func (c *Container) resolveWorkDir() error {
 		return errors.Wrapf(err, "error creating container %s workdir", c.ID())
 	}
 
-	if err := os.Chown(resolvedWorkdir, rootUID, rootGID); err != nil {
+	// Ensure container entrypoint is created (if required).
+	uid, gid, _, err := chrootuser.GetUser(c.state.Mountpoint, c.User())
+	if err != nil {
+		return errors.Wrapf(err, "error looking up %s inside of the container %s", c.User(), c.ID())
+	}
+	if err := os.Chown(resolvedWorkdir, int(uid), int(gid)); err != nil {
 		return errors.Wrapf(err, "error chowning container %s workdir to container root", c.ID())
 	}
 
diff --git a/test/e2e/run_working_dir_test.go b/test/e2e/run_working_dir_test.go
index 59538448e..948ed05e7 100644
--- a/test/e2e/run_working_dir_test.go
+++ b/test/e2e/run_working_dir_test.go
@@ -47,7 +47,7 @@ var _ = Describe("Podman run", func() {
 
 	It("podman run a container on an image with a workdir", func() {
 		dockerfile := `FROM alpine
-RUN  mkdir -p /home/foobar
+RUN  mkdir -p /home/foobar /etc/foobar; chown bin:bin /etc/foobar
 WORKDIR  /etc/foobar`
 		podmanTest.BuildImage(dockerfile, "test", "false")
 
@@ -56,6 +56,10 @@ WORKDIR  /etc/foobar`
 		Expect(session.ExitCode()).To(Equal(0))
 		Expect(session.OutputToString()).To(Equal("/etc/foobar"))
 
+		session = podmanTest.Podman([]string{"run", "test", "ls", "-ld", "."})
+		session.WaitWithDefaultTimeout()
+		Expect(session.LineInOutputContains("bin")).To(BeTrue())
+
 		session = podmanTest.Podman([]string{"run", "--workdir", "/home/foobar", "test", "pwd"})
 		session.WaitWithDefaultTimeout()
 		Expect(session.ExitCode()).To(Equal(0))
-- 
cgit v1.2.3-54-g00ecf


From 33ac798406ae8e3939d0550f93cf341f33bf56cd Mon Sep 17 00:00:00 2001
From: Valentin Rothberg <rothberg@redhat.com>
Date: Mon, 15 Feb 2021 13:02:14 +0100
Subject: fix failing image e2e test

The timestamps of some images must have changed changing the number of
expected filtered images.  The test conditions seem fragile but for now
it's more important to get CI back.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
---
 test/e2e/images_test.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'test')

diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index 2dab4858e..b79115c71 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -194,7 +194,7 @@ WORKDIR /test
 		result := podmanTest.Podman([]string{"images", "-q", "-f", "since=quay.io/libpod/alpine:latest"})
 		result.WaitWithDefaultTimeout()
 		Expect(result).Should(Exit(0))
-		Expect(len(result.OutputToStringArray())).To(Equal(7))
+		Expect(len(result.OutputToStringArray())).To(Equal(8))
 	})
 
 	It("podman image list filter after image", func() {
@@ -204,7 +204,7 @@ WORKDIR /test
 		result := podmanTest.Podman([]string{"image", "list", "-q", "-f", "after=quay.io/libpod/alpine:latest"})
 		result.WaitWithDefaultTimeout()
 		Expect(result).Should(Exit(0))
-		Expect(result.OutputToStringArray()).Should(HaveLen(7), "list filter output: %q", result.OutputToString())
+		Expect(result.OutputToStringArray()).Should(HaveLen(8), "list filter output: %q", result.OutputToString())
 	})
 
 	It("podman images filter dangling", func() {
-- 
cgit v1.2.3-54-g00ecf


From cf42bdcb41f34b5cdfc15e865089ec1e88681e25 Mon Sep 17 00:00:00 2001
From: Valentin Rothberg <rothberg@redhat.com>
Date: Mon, 15 Feb 2021 15:07:25 +0100
Subject: e2e: fix network alias test

The logic in the e2e test for multiple network aliases is indicating the
test should wait for the containerized nginx to be ready.  As this may
take some time, the test does an exponential backoff starting at 2050ms.

Fix the logic by removing the `Expect(...)` call during the exponential
backoff.  Otherwise, the test errors immediately.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
---
 test/e2e/network_test.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'test')

diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
index df8ff0684..d191cb6bb 100644
--- a/test/e2e/network_test.go
+++ b/test/e2e/network_test.go
@@ -407,6 +407,7 @@ var _ = Describe("Podman network", func() {
 		Expect(lines[0]).To(Equal(netName1))
 		Expect(lines[1]).To(Equal(netName2))
 	})
+
 	It("podman network with multiple aliases", func() {
 		var worked bool
 		netName := "aliasTest" + stringid.GenerateNonCryptoID()
@@ -424,7 +425,7 @@ var _ = Describe("Podman network", func() {
 			// Test curl against the container's name
 			c1 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web"})
 			c1.WaitWithDefaultTimeout()
-			worked = Expect(c1.ExitCode()).To(BeZero())
+			worked = c1.ExitCode() == 0
 			if worked {
 				break
 			}
-- 
cgit v1.2.3-54-g00ecf


From 94ff3b583e6774f115e811d10ca75245e9957f4e Mon Sep 17 00:00:00 2001
From: baude <bbaude@redhat.com>
Date: Mon, 15 Feb 2021 12:31:09 -0600
Subject: fix dns resolution on ubuntu

ubuntu's dns seems a little odd and requires a fq name in its tests.

Signed-off-by: baude <bbaude@redhat.com>
---
 test/e2e/network_test.go | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

(limited to 'test')

diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
index d191cb6bb..b1cabdbf8 100644
--- a/test/e2e/network_test.go
+++ b/test/e2e/network_test.go
@@ -416,14 +416,26 @@ var _ = Describe("Podman network", func() {
 		defer podmanTest.removeCNINetwork(netName)
 		Expect(session.ExitCode()).To(BeZero())
 
+		interval := time.Duration(250 * time.Millisecond)
+		for i := 0; i < 6; i++ {
+			n := podmanTest.Podman([]string{"network", "exists", netName})
+			n.WaitWithDefaultTimeout()
+			worked = n.ExitCode() == 0
+			if worked {
+				break
+			}
+			time.Sleep(interval)
+			interval *= 2
+		}
+
 		top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx})
 		top.WaitWithDefaultTimeout()
 		Expect(top.ExitCode()).To(BeZero())
-		interval := time.Duration(250 * time.Millisecond)
+		interval = time.Duration(250 * time.Millisecond)
 		// Wait for the nginx service to be running
 		for i := 0; i < 6; i++ {
 			// Test curl against the container's name
-			c1 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web"})
+			c1 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, nginx, "curl", "web"})
 			c1.WaitWithDefaultTimeout()
 			worked = c1.ExitCode() == 0
 			if worked {
@@ -436,12 +448,12 @@ var _ = Describe("Podman network", func() {
 
 		// Nginx is now running so no need to do a loop
 		// Test against the first alias
-		c2 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web1"})
+		c2 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, nginx, "curl", "web1"})
 		c2.WaitWithDefaultTimeout()
 		Expect(c2.ExitCode()).To(BeZero())
 
 		// Test against the second alias
-		c3 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web2"})
+		c3 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, nginx, "curl", "web2"})
 		c3.WaitWithDefaultTimeout()
 		Expect(c3.ExitCode()).To(BeZero())
 	})
-- 
cgit v1.2.3-54-g00ecf


From b4678177828bf1a5fddffa06a8ebce8fec077f47 Mon Sep 17 00:00:00 2001
From: Igor Korolev <missterr@gmail.com>
Date: Wed, 10 Feb 2021 23:15:48 +0400
Subject: apiv2: handle docker-java clients pulling

When docker-java calls images/create?fromImage=x, it expects two things
for a successful response: that both "error" and "errorDetail" are not
set, and that the "progress" message contains one of five hard-coded
strings ("Download complete" being one of them).

Signed-off-by: Igor Korolev <missterr@gmail.com>
---
 pkg/api/handlers/compat/images.go | 4 ++--
 test/apiv2/10-images.at           | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

(limited to 'test')

diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 05d4e2f65..ab2b1f471 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -255,12 +255,12 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
 	// Success
 	utils.WriteResponse(w, http.StatusOK, struct {
 		Status         string            `json:"status"`
-		Error          string            `json:"error"`
+		Error          string            `json:"error,omitempty"`
 		Progress       string            `json:"progress"`
 		ProgressDetail map[string]string `json:"progressDetail"`
 		Id             string            `json:"id"` // nolint
 	}{
-		Status:         fmt.Sprintf("pulling image (%s) from %s", img.Tag, strings.Join(img.Names(), ", ")),
+		Status:         fmt.Sprintf("pulling image (%s) from %s (Download complete)", img.Tag, strings.Join(img.Names(), ", ")),
 		ProgressDetail: map[string]string{},
 		Id:             img.ID(),
 	})
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index 30090d806..a650cf958 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -41,7 +41,7 @@ t GET images/$iid/json 200 \
   .Id=sha256:$iid \
   .RepoTags[0]=$IMAGE
 
-t POST "images/create?fromImage=alpine" '' 200
+t POST "images/create?fromImage=alpine" '' 200 .error=null .status~".*Download complete.*"
 
 t POST "images/create?fromImage=alpine&tag=latest" '' 200
 
-- 
cgit v1.2.3-54-g00ecf


From 873014e4eee81ab090b2c97ba0ce99be7c798b75 Mon Sep 17 00:00:00 2001
From: Daniel J Walsh <dwalsh@redhat.com>
Date: Fri, 5 Feb 2021 06:04:30 -0500
Subject: Do not reset storage when running inside of a container

Currently if the host shares container storage with a container
running podman, the podman inside of the container resets the
storage on the host. This can cause issues on the host, as
well as causes the podman command running the container, to
fail to unmount /dev/shm.

podman run -ti --rm --privileged -v /var/lib/containers:/var/lib/containers quay.io/podman/stable podman run alpine echo hello
	* unlinkat /var/lib/containers/storage/overlay-containers/a7f3c9deb0656f8de1d107e7ddff2d3c3c279c11c1635f233a0bffb16051fb2c/userdata/shm: device or resource busy
	* unlinkat /var/lib/containers/storage/overlay-containers/a7f3c9deb0656f8de1d107e7ddff2d3c3c279c11c1635f233a0bffb16051fb2c/userdata/shm: device or resource busy

Since podman is volume mounting in the graphroot, it will add a flag to
/run/.containerenv to tell podman inside of container whether to reset storage or not.

Since the inner podman is running inside of the container, no reason to assume this is a fresh reboot, so if "container" environment variable is set then skip
reset of storage.

Also added tests to make sure /run/.containerenv is runnig correctly.

Fixes: https://github.com/containers/podman/issues/9191

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>

<MH: Fixed cherry-pick conflicts>

Signed-off-by: Matthew Heon <mheon@redhat.com>
---
 libpod/container_internal_linux.go |  4 ++--
 libpod/runtime.go                  | 37 ++++++++++++++++++++++++++++++++++---
 test/e2e/run_test.go               | 23 +++++++++++++++++++++++
 3 files changed, 59 insertions(+), 5 deletions(-)

(limited to 'test')

diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 2f1bd52c4..1da8e6c38 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -1626,7 +1626,7 @@ func (c *Container) makeBindMounts() error {
 
 	// Make .containerenv if it does not exist
 	if _, ok := c.state.BindMounts["/run/.containerenv"]; !ok {
-		var containerenv string
+		containerenv := c.runtime.graphRootMountedFlag(c.config.Spec.Mounts)
 		isRootless := 0
 		if rootless.IsRootless() {
 			isRootless = 1
@@ -1641,7 +1641,7 @@ id=%q
 image=%q
 imageid=%q
 rootless=%d
-`, version.Version.String(), c.Name(), c.ID(), imageName, imageID, isRootless)
+%s`, version.Version.String(), c.Name(), c.ID(), imageName, imageID, isRootless, containerenv)
 		}
 		containerenvPath, err := c.writeStringToRundir(".containerenv", containerenv)
 		if err != nil {
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 9ab98a27e..7726a1f8e 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -1,6 +1,7 @@
 package libpod
 
 import (
+	"bufio"
 	"context"
 	"fmt"
 	"os"
@@ -26,6 +27,7 @@ import (
 	"github.com/containers/storage"
 	"github.com/cri-o/ocicni/pkg/ocicni"
 	"github.com/docker/docker/pkg/namesgenerator"
+	spec "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
@@ -622,9 +624,12 @@ func (r *Runtime) Shutdown(force bool) error {
 func (r *Runtime) refresh(alivePath string) error {
 	logrus.Debugf("Podman detected system restart - performing state refresh")
 
-	// First clear the state in the database
-	if err := r.state.Refresh(); err != nil {
-		return err
+	// Clear state of database if not running in container
+	if !graphRootMounted() {
+		// First clear the state in the database
+		if err := r.state.Refresh(); err != nil {
+			return err
+		}
 	}
 
 	// Next refresh the state of all containers to recreate dirs and
@@ -899,3 +904,29 @@ func (r *Runtime) getVolumePlugin(name string) (*plugin.VolumePlugin, error) {
 
 	return plugin.GetVolumePlugin(name, pluginPath)
 }
+
+func graphRootMounted() bool {
+	f, err := os.OpenFile("/run/.containerenv", os.O_RDONLY, os.ModePerm)
+	if err != nil {
+		return false
+	}
+	defer f.Close()
+
+	scanner := bufio.NewScanner(f)
+	for scanner.Scan() {
+		if scanner.Text() == "graphRootMounted=1" {
+			return true
+		}
+	}
+	return false
+}
+
+func (r *Runtime) graphRootMountedFlag(mounts []spec.Mount) string {
+	root := r.store.GraphRoot()
+	for _, val := range mounts {
+		if strings.HasPrefix(root, val.Source) {
+			return "graphRootMounted=1"
+		}
+	}
+	return ""
+}
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 7d367cccf..bff3995df 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -47,6 +47,29 @@ var _ = Describe("Podman run", func() {
 		Expect(session.ExitCode()).To(Equal(0))
 	})
 
+	It("podman run check /run/.containerenv", func() {
+		session := podmanTest.Podman([]string{"run", ALPINE, "cat", "/run/.containerenv"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+		Expect(session.OutputToString()).To(Equal(""))
+
+		session = podmanTest.Podman([]string{"run", "--privileged", "--name=test1", ALPINE, "cat", "/run/.containerenv"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+		Expect(session.OutputToString()).To(ContainSubstring("name=\"test1\""))
+		Expect(session.OutputToString()).To(ContainSubstring("image=\"" + ALPINE + "\""))
+
+		session = podmanTest.Podman([]string{"run", "-v", "/:/host", ALPINE, "cat", "/run/.containerenv"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+		Expect(session.OutputToString()).To(ContainSubstring("graphRootMounted=1"))
+
+		session = podmanTest.Podman([]string{"run", "-v", "/:/host", "--privileged", ALPINE, "cat", "/run/.containerenv"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+		Expect(session.OutputToString()).To(ContainSubstring("graphRootMounted=1"))
+	})
+
 	It("podman run a container based on a complex local image name", func() {
 		imageName := strings.TrimPrefix(nginx, "quay.io/")
 		session := podmanTest.Podman([]string{"run", imageName, "ls"})
-- 
cgit v1.2.3-54-g00ecf


From 3fd2d1bf709b52d1b560a722832d67ad37e09f1b Mon Sep 17 00:00:00 2001
From: Nikolay Edigaryev <edigaryev@gmail.com>
Date: Wed, 17 Feb 2021 21:18:39 +0300
Subject: API: fix libpod's container wait endpoint condition conversion

Signed-off-by: Nikolay Edigaryev <edigaryev@gmail.com>
---
 pkg/api/handlers/decoder.go | 15 +++++++++++++++
 test/apiv2/20-containers.at |  2 +-
 2 files changed, 16 insertions(+), 1 deletion(-)

(limited to 'test')

diff --git a/pkg/api/handlers/decoder.go b/pkg/api/handlers/decoder.go
index 54087168a..123d325aa 100644
--- a/pkg/api/handlers/decoder.go
+++ b/pkg/api/handlers/decoder.go
@@ -6,6 +6,7 @@ import (
 	"syscall"
 	"time"
 
+	"github.com/containers/podman/v2/libpod/define"
 	"github.com/containers/podman/v2/pkg/util"
 	"github.com/gorilla/schema"
 	"github.com/sirupsen/logrus"
@@ -19,6 +20,7 @@ func NewAPIDecoder() *schema.Decoder {
 	d.IgnoreUnknownKeys(true)
 	d.RegisterConverter(map[string][]string{}, convertURLValuesString)
 	d.RegisterConverter(time.Time{}, convertTimeString)
+	d.RegisterConverter(define.ContainerStatus(0), convertContainerStatusString)
 
 	var Signal syscall.Signal
 	d.RegisterConverter(Signal, convertSignal)
@@ -46,6 +48,19 @@ func convertURLValuesString(query string) reflect.Value {
 	return reflect.ValueOf(f)
 }
 
+func convertContainerStatusString(query string) reflect.Value {
+	result, err := define.StringToContainerStatus(query)
+	if err != nil {
+		logrus.Infof("convertContainerStatusString: Failed to parse %s: %s", query, err.Error())
+
+		// We return nil here instead of result because reflect.ValueOf().IsValid() will be true
+		// in github.com/gorilla/schema's decoder, which means there's no parsing error
+		return reflect.ValueOf(nil)
+	}
+
+	return reflect.ValueOf(result)
+}
+
 // isZero() can be used to determine if parsing failed.
 func convertTimeString(query string) reflect.Value {
 	var (
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index 0da196e46..292562934 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -63,7 +63,7 @@ cid=$(jq -r '.Id' <<<"$output")
 # Prior to the fix in #6835, this would fail 500 "args must not be empty"
 t POST   libpod/containers/${cid}/start '' 204
 # Container should exit almost immediately. Wait for it, confirm successful run
-t POST   libpod/containers/${cid}/wait  '' 200 '0'
+t POST   libpod/containers/${cid}/wait?condition=stopped&condition=exited  '' 200 '0'
 t GET    libpod/containers/${cid}/json 200 \
   .Id=$cid \
   .State.Status~\\\(exited\\\|stopped\\\) \
-- 
cgit v1.2.3-54-g00ecf


From 2b97dfc5eea1df424dd360d49424cf8768f31ef6 Mon Sep 17 00:00:00 2001
From: Nikolay Edigaryev <edigaryev@gmail.com>
Date: Thu, 18 Feb 2021 01:40:41 +0300
Subject: Quote URL

Signed-off-by: Nikolay Edigaryev <edigaryev@gmail.com>
---
 test/apiv2/20-containers.at | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'test')

diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index 292562934..a99e9a184 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -63,7 +63,7 @@ cid=$(jq -r '.Id' <<<"$output")
 # Prior to the fix in #6835, this would fail 500 "args must not be empty"
 t POST   libpod/containers/${cid}/start '' 204
 # Container should exit almost immediately. Wait for it, confirm successful run
-t POST   libpod/containers/${cid}/wait?condition=stopped&condition=exited  '' 200 '0'
+t POST   "libpod/containers/${cid}/wait?condition=stopped&condition=exited"  '' 200 '0'
 t GET    libpod/containers/${cid}/json 200 \
   .Id=$cid \
   .State.Status~\\\(exited\\\|stopped\\\) \
-- 
cgit v1.2.3-54-g00ecf


From 3d14b56282dc16518aac1825db318d93495785af Mon Sep 17 00:00:00 2001
From: Daniel J Walsh <dwalsh@redhat.com>
Date: Fri, 5 Feb 2021 13:08:15 -0500
Subject: Implement missing arguments for podman build

Buildah bud passes a bunch more flags then podman build.

We need to implement hook up all of these flags to get full functionality.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>

<MH: Fix cherry pick conflicts>

Signed-off-by: Matthew Heon <mheon@redhat.com>
---
 cmd/podman/images/build.go                         |  61 ++++-
 go.mod                                             |   1 +
 pkg/api/handlers/compat/images_build.go            | 183 +++++++++----
 pkg/bindings/images/build.go                       | 154 +++++++----
 test/e2e/build_test.go                             |  51 ++++
 .../containers/ocicrypt/helpers/parse_helpers.go   | 301 +++++++++++++++++++++
 vendor/modules.txt                                 |   1 +
 7 files changed, 643 insertions(+), 109 deletions(-)
 create mode 100644 vendor/github.com/containers/ocicrypt/helpers/parse_helpers.go

(limited to 'test')

diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index a35fea442..0c97a2488 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -1,9 +1,11 @@
 package images
 
 import (
+	"io"
 	"os"
 	"path/filepath"
 	"strings"
+	"time"
 
 	"github.com/containers/buildah"
 	"github.com/containers/buildah/imagebuildah"
@@ -11,6 +13,8 @@ import (
 	"github.com/containers/buildah/pkg/parse"
 	"github.com/containers/common/pkg/completion"
 	"github.com/containers/common/pkg/config"
+	encconfig "github.com/containers/ocicrypt/config"
+	enchelpers "github.com/containers/ocicrypt/helpers"
 	"github.com/containers/podman/v2/cmd/podman/common"
 	"github.com/containers/podman/v2/cmd/podman/registry"
 	"github.com/containers/podman/v2/cmd/podman/utils"
@@ -78,7 +82,8 @@ func useLayers() string {
 
 func init() {
 	registry.Commands = append(registry.Commands, registry.CliCommand{
-		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+		Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+
 		Command: buildCmd,
 	})
 	buildFlags(buildCmd)
@@ -151,8 +156,21 @@ func buildFlags(cmd *cobra.Command) {
 	// Add the completion functions
 	fromAndBudFlagsCompletions := buildahCLI.GetFromAndBudFlagsCompletions()
 	completion.CompleteCommandFlags(cmd, fromAndBudFlagsCompletions)
-	_ = flags.MarkHidden("signature-policy")
 	flags.SetNormalizeFunc(buildahCLI.AliasFlags)
+	if registry.IsRemote() {
+		flag = flags.Lookup("isolation")
+		buildOpts.Isolation = buildah.OCI
+		if err := flag.Value.Set(buildah.OCI); err != nil {
+			logrus.Errorf("unable to set --isolation to %v: %v", buildah.OCI, err)
+		}
+		flag.DefValue = buildah.OCI
+		_ = flags.MarkHidden("disable-content-trust")
+		_ = flags.MarkHidden("cache-from")
+		_ = flags.MarkHidden("sign-by")
+		_ = flags.MarkHidden("signature-policy")
+		_ = flags.MarkHidden("tls-verify")
+		_ = flags.MarkHidden("compress")
+	}
 }
 
 // build executes the build command.
@@ -308,6 +326,10 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
 		flags.Layers = false
 	}
 
+	var stdin io.Reader
+	if flags.Stdin {
+		stdin = os.Stdin
+	}
 	var stdout, stderr, reporter *os.File
 	stdout = os.Stdout
 	stderr = os.Stderr
@@ -402,10 +424,21 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
 		runtimeFlags = append(runtimeFlags, "--systemd-cgroup")
 	}
 
+	imageOS, arch, err := parse.PlatformFromOptions(c)
+	if err != nil {
+		return nil, err
+	}
+
+	decConfig, err := getDecryptConfig(flags.DecryptionKeys)
+	if err != nil {
+		return nil, errors.Wrapf(err, "unable to obtain decrypt config")
+	}
+
 	opts := imagebuildah.BuildOptions{
 		AddCapabilities: flags.CapAdd,
 		AdditionalTags:  tags,
 		Annotations:     flags.Annotation,
+		Architecture:    arch,
 		Args:            args,
 		BlobDirectory:   flags.BlobCache,
 		CNIConfigDir:    flags.CNIConfigDir,
@@ -433,17 +466,26 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
 		DropCapabilities:        flags.CapDrop,
 		Err:                     stderr,
 		ForceRmIntermediateCtrs: flags.ForceRm,
+		From:                    flags.From,
 		IDMappingOptions:        idmappingOptions,
 		IIDFile:                 flags.Iidfile,
+		In:                      stdin,
 		Isolation:               isolation,
+		Jobs:                    &flags.Jobs,
 		Labels:                  flags.Label,
 		Layers:                  flags.Layers,
+		LogRusage:               flags.LogRusage,
+		Manifest:                flags.Manifest,
+		MaxPullPushRetries:      3,
 		NamespaceOptions:        nsValues,
 		NoCache:                 flags.NoCache,
+		OS:                      imageOS,
+		OciDecryptConfig:        decConfig,
 		Out:                     stdout,
 		Output:                  output,
 		OutputFormat:            format,
 		PullPolicy:              pullPolicy,
+		PullPushRetryDelay:      2 * time.Second,
 		Quiet:                   flags.Quiet,
 		RemoveIntermediateCtrs:  flags.Rm,
 		ReportWriter:            reporter,
@@ -459,3 +501,18 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
 
 	return &entities.BuildOptions{BuildOptions: opts}, nil
 }
+
+func getDecryptConfig(decryptionKeys []string) (*encconfig.DecryptConfig, error) {
+	decConfig := &encconfig.DecryptConfig{}
+	if len(decryptionKeys) > 0 {
+		// decryption
+		dcc, err := enchelpers.CreateCryptoConfig([]string{}, decryptionKeys)
+		if err != nil {
+			return nil, errors.Wrapf(err, "invalid decryption keys")
+		}
+		cc := encconfig.CombineCryptoConfigs([]encconfig.CryptoConfig{dcc})
+		decConfig = cc.DecryptConfig
+	}
+
+	return decConfig, nil
+}
diff --git a/go.mod b/go.mod
index 67eb91b81..a6faae7fc 100644
--- a/go.mod
+++ b/go.mod
@@ -14,6 +14,7 @@ require (
 	github.com/containers/common v0.33.4
 	github.com/containers/conmon v2.0.20+incompatible
 	github.com/containers/image/v5 v5.10.2
+	github.com/containers/ocicrypt v1.0.3
 	github.com/containers/psgo v1.5.2
 	github.com/containers/storage v1.24.6
 	github.com/coreos/go-systemd/v22 v22.1.0
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index 415ff85cd..0f27a090f 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -60,29 +60,39 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 	}()
 
 	query := struct {
-		BuildArgs   string   `schema:"buildargs"`
-		CacheFrom   string   `schema:"cachefrom"`
-		CpuPeriod   uint64   `schema:"cpuperiod"`  // nolint
-		CpuQuota    int64    `schema:"cpuquota"`   // nolint
-		CpuSetCpus  string   `schema:"cpusetcpus"` // nolint
-		CpuShares   uint64   `schema:"cpushares"`  // nolint
-		Dockerfile  string   `schema:"dockerfile"`
-		ExtraHosts  string   `schema:"extrahosts"`
-		ForceRm     bool     `schema:"forcerm"`
-		HTTPProxy   bool     `schema:"httpproxy"`
-		Labels      string   `schema:"labels"`
-		Layers      bool     `schema:"layers"`
-		MemSwap     int64    `schema:"memswap"`
-		Memory      int64    `schema:"memory"`
-		NetworkMode string   `schema:"networkmode"`
-		NoCache     bool     `schema:"nocache"`
-		Outputs     string   `schema:"outputs"`
-		Platform    string   `schema:"platform"`
-		Pull        bool     `schema:"pull"`
-		Quiet       bool     `schema:"q"`
-		Registry    string   `schema:"registry"`
-		Remote      string   `schema:"remote"`
-		Rm          bool     `schema:"rm"`
+		AddHosts               string `schema:"extrahosts"`
+		AdditionalCapabilities string `schema:"addcaps"`
+		Annotations            string `schema:"annotations"`
+		BuildArgs              string `schema:"buildargs"`
+		CacheFrom              string `schema:"cachefrom"`
+		ConfigureNetwork       int64  `schema:"networkmode"`
+		CpuPeriod              uint64 `schema:"cpuperiod"`  // nolint
+		CpuQuota               int64  `schema:"cpuquota"`   // nolint
+		CpuSetCpus             string `schema:"cpusetcpus"` // nolint
+		CpuShares              uint64 `schema:"cpushares"`  // nolint
+		Devices                string `schema:"devices"`
+		Dockerfile             string `schema:"dockerfile"`
+		DropCapabilities       string `schema:"dropcaps"`
+		ForceRm                bool   `schema:"forcerm"`
+		From                   string `schema:"from"`
+		HTTPProxy              bool   `schema:"httpproxy"`
+		Isolation              int64  `schema:"isolation"`
+		Jobs                   uint64 `schema:"jobs"` // nolint
+		Labels                 string `schema:"labels"`
+		Layers                 bool   `schema:"layers"`
+		LogRusage              bool   `schema:"rusage"`
+		Manifest               string `schema:"manifest"`
+		MemSwap                int64  `schema:"memswap"`
+		Memory                 int64  `schema:"memory"`
+		NoCache                bool   `schema:"nocache"`
+		OutputFormat           string `schema:"outputformat"`
+		Platform               string `schema:"platform"`
+		Pull                   bool   `schema:"pull"`
+		Quiet                  bool   `schema:"q"`
+		Registry               string `schema:"registry"`
+		Rm                     bool   `schema:"rm"`
+		//FIXME SecurityOpt in remote API is not handled
+		SecurityOpt string   `schema:"securityopt"`
 		ShmSize     int      `schema:"shmsize"`
 		Squash      bool     `schema:"squash"`
 		Tag         []string `schema:"t"`
@@ -101,14 +111,57 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	// convert label formats
+	var addCaps = []string{}
+	if _, found := r.URL.Query()["addcaps"]; found {
+		var m = []string{}
+		if err := json.Unmarshal([]byte(query.AdditionalCapabilities), &m); err != nil {
+			utils.BadRequest(w, "addcaps", query.AdditionalCapabilities, err)
+			return
+		}
+		addCaps = m
+	}
+	addhosts := []string{}
+	if _, found := r.URL.Query()["extrahosts"]; found {
+		if err := json.Unmarshal([]byte(query.AddHosts), &addhosts); err != nil {
+			utils.BadRequest(w, "extrahosts", query.AddHosts, err)
+			return
+		}
+	}
+
+	// convert label formats
+	var dropCaps = []string{}
+	if _, found := r.URL.Query()["dropcaps"]; found {
+		var m = []string{}
+		if err := json.Unmarshal([]byte(query.DropCapabilities), &m); err != nil {
+			utils.BadRequest(w, "dropcaps", query.DropCapabilities, err)
+			return
+		}
+		dropCaps = m
+	}
+
+	// convert label formats
+	var devices = []string{}
+	if _, found := r.URL.Query()["devices"]; found {
+		var m = []string{}
+		if err := json.Unmarshal([]byte(query.DropCapabilities), &m); err != nil {
+			utils.BadRequest(w, "devices", query.DropCapabilities, err)
+			return
+		}
+		devices = m
+	}
+
 	var output string
 	if len(query.Tag) > 0 {
 		output = query.Tag[0]
 	}
-
-	var additionalNames []string
+	format := buildah.Dockerv2ImageManifest
+	if utils.IsLibpodRequest(r) {
+		format = query.OutputFormat
+	}
+	var additionalTags []string
 	if len(query.Tag) > 1 {
-		additionalNames = query.Tag[1:]
+		additionalTags = query.Tag[1:]
 	}
 
 	var buildArgs = map[string]string{}
@@ -119,18 +172,22 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
+	// convert label formats
+	var annotations = []string{}
+	if _, found := r.URL.Query()["annotations"]; found {
+		if err := json.Unmarshal([]byte(query.Annotations), &annotations); err != nil {
+			utils.BadRequest(w, "annotations", query.Annotations, err)
+			return
+		}
+	}
+
 	// convert label formats
 	var labels = []string{}
 	if _, found := r.URL.Query()["labels"]; found {
-		var m = map[string]string{}
-		if err := json.Unmarshal([]byte(query.Labels), &m); err != nil {
+		if err := json.Unmarshal([]byte(query.Labels), &labels); err != nil {
 			utils.BadRequest(w, "labels", query.Labels, err)
 			return
 		}
-
-		for k, v := range m {
-			labels = append(labels, k+"="+v)
-		}
 	}
 
 	pullPolicy := buildah.PullIfMissing
@@ -160,27 +217,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 
 	reporter := channel.NewWriter(make(chan []byte, 1))
 	defer reporter.Close()
+
 	buildOptions := imagebuildah.BuildOptions{
-		ContextDirectory:               contextDirectory,
-		PullPolicy:                     pullPolicy,
-		Registry:                       query.Registry,
-		IgnoreUnrecognizedInstructions: true,
-		Quiet:                          query.Quiet,
-		Layers:                         query.Layers,
-		Isolation:                      buildah.IsolationChroot,
-		Compression:                    archive.Gzip,
-		Args:                           buildArgs,
-		Output:                         output,
-		AdditionalTags:                 additionalNames,
-		Out:                            stdout,
-		Err:                            auxout,
-		ReportWriter:                   reporter,
-		OutputFormat:                   buildah.Dockerv2ImageManifest,
-		SystemContext: &types.SystemContext{
-			AuthFilePath:     authfile,
-			DockerAuthConfig: creds,
-		},
+		AddCapabilities: addCaps,
+		AdditionalTags:  additionalTags,
+		Annotations:     annotations,
+		Args:            buildArgs,
 		CommonBuildOpts: &buildah.CommonBuildOptions{
+			AddHost:    addhosts,
 			CPUPeriod:  query.CpuPeriod,
 			CPUQuota:   query.CpuQuota,
 			CPUShares:  query.CpuShares,
@@ -190,12 +234,37 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 			MemorySwap: query.MemSwap,
 			ShmSize:    strconv.Itoa(query.ShmSize),
 		},
-		Squash:                  query.Squash,
-		Labels:                  labels,
-		NoCache:                 query.NoCache,
-		RemoveIntermediateCtrs:  query.Rm,
-		ForceRmIntermediateCtrs: query.ForceRm,
-		Target:                  query.Target,
+		Compression:                    archive.Gzip,
+		ConfigureNetwork:               buildah.NetworkConfigurationPolicy(query.ConfigureNetwork),
+		ContextDirectory:               contextDirectory,
+		Devices:                        devices,
+		DropCapabilities:               dropCaps,
+		Err:                            auxout,
+		ForceRmIntermediateCtrs:        query.ForceRm,
+		From:                           query.From,
+		IgnoreUnrecognizedInstructions: true,
+		// FIXME, This is very broken.  Buildah will only work with chroot
+		//		Isolation:                      buildah.Isolation(query.Isolation),
+		Isolation: buildah.IsolationChroot,
+
+		Labels:                 labels,
+		Layers:                 query.Layers,
+		Manifest:               query.Manifest,
+		NoCache:                query.NoCache,
+		Out:                    stdout,
+		Output:                 output,
+		OutputFormat:           format,
+		PullPolicy:             pullPolicy,
+		Quiet:                  query.Quiet,
+		Registry:               query.Registry,
+		RemoveIntermediateCtrs: query.Rm,
+		ReportWriter:           reporter,
+		Squash:                 query.Squash,
+		SystemContext: &types.SystemContext{
+			AuthFilePath:     authfile,
+			DockerAuthConfig: creds,
+		},
+		Target: query.Target,
 	}
 
 	runtime := r.Context().Value("runtime").(*libpod.Runtime)
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index 02765816f..8ea09b881 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -31,36 +31,31 @@ import (
 func Build(ctx context.Context, containerFiles []string, options entities.BuildOptions) (*entities.BuildReport, error) {
 	params := url.Values{}
 
-	if t := options.Output; len(t) > 0 {
-		params.Set("t", t)
+	if caps := options.AddCapabilities; len(caps) > 0 {
+		c, err := jsoniter.MarshalToString(caps)
+		if err != nil {
+			return nil, err
+		}
+		params.Add("addcaps", c)
 	}
+
+	if annotations := options.Annotations; len(annotations) > 0 {
+		l, err := jsoniter.MarshalToString(annotations)
+		if err != nil {
+			return nil, err
+		}
+		params.Set("annotations", l)
+	}
+	params.Add("t", options.Output)
 	for _, tag := range options.AdditionalTags {
 		params.Add("t", tag)
 	}
-	if options.Quiet {
-		params.Set("q", "1")
-	}
-	if options.NoCache {
-		params.Set("nocache", "1")
-	}
-	if options.Layers {
-		params.Set("layers", "1")
-	}
-	//	 TODO cachefrom
-	if options.PullPolicy == buildah.PullAlways {
-		params.Set("pull", "1")
-	}
-	if options.RemoveIntermediateCtrs {
-		params.Set("rm", "1")
-	}
-	if options.ForceRmIntermediateCtrs {
-		params.Set("forcerm", "1")
-	}
-	if mem := options.CommonBuildOpts.Memory; mem > 0 {
-		params.Set("memory", strconv.Itoa(int(mem)))
-	}
-	if memSwap := options.CommonBuildOpts.MemorySwap; memSwap > 0 {
-		params.Set("memswap", strconv.Itoa(int(memSwap)))
+	if buildArgs := options.Args; len(buildArgs) > 0 {
+		bArgs, err := jsoniter.MarshalToString(buildArgs)
+		if err != nil {
+			return nil, err
+		}
+		params.Set("buildargs", bArgs)
 	}
 	if cpuShares := options.CommonBuildOpts.CPUShares; cpuShares > 0 {
 		params.Set("cpushares", strconv.Itoa(int(cpuShares)))
@@ -74,22 +69,38 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
 	if cpuQuota := options.CommonBuildOpts.CPUQuota; cpuQuota > 0 {
 		params.Set("cpuquota", strconv.Itoa(int(cpuQuota)))
 	}
-	if buildArgs := options.Args; len(buildArgs) > 0 {
-		bArgs, err := jsoniter.MarshalToString(buildArgs)
+	params.Set("networkmode", strconv.Itoa(int(options.ConfigureNetwork)))
+	params.Set("outputformat", options.OutputFormat)
+
+	if devices := options.Devices; len(devices) > 0 {
+		d, err := jsoniter.MarshalToString(devices)
 		if err != nil {
 			return nil, err
 		}
-		params.Set("buildargs", bArgs)
+		params.Add("devices", d)
 	}
-	if shmSize := options.CommonBuildOpts.ShmSize; len(shmSize) > 0 {
-		shmBytes, err := units.RAMInBytes(shmSize)
+
+	if caps := options.DropCapabilities; len(caps) > 0 {
+		c, err := jsoniter.MarshalToString(caps)
 		if err != nil {
 			return nil, err
 		}
-		params.Set("shmsize", strconv.Itoa(int(shmBytes)))
+		params.Add("dropcaps", c)
 	}
-	if options.Squash {
-		params.Set("squash", "1")
+
+	if options.ForceRmIntermediateCtrs {
+		params.Set("forcerm", "1")
+	}
+	if len(options.From) > 0 {
+		params.Set("from", options.From)
+	}
+
+	params.Set("isolation", strconv.Itoa(int(options.Isolation)))
+	if options.CommonBuildOpts.HTTPProxy {
+		params.Set("httpproxy", "1")
+	}
+	if options.Jobs != nil {
+		params.Set("jobs", strconv.FormatUint(uint64(*options.Jobs), 10))
 	}
 	if labels := options.Labels; len(labels) > 0 {
 		l, err := jsoniter.MarshalToString(labels)
@@ -98,10 +109,66 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
 		}
 		params.Set("labels", l)
 	}
-	if options.CommonBuildOpts.HTTPProxy {
-		params.Set("httpproxy", "1")
+	if options.Layers {
+		params.Set("layers", "1")
+	}
+	if options.LogRusage {
+		params.Set("rusage", "1")
+	}
+	if len(options.Manifest) > 0 {
+		params.Set("manifest", options.Manifest)
+	}
+	if memSwap := options.CommonBuildOpts.MemorySwap; memSwap > 0 {
+		params.Set("memswap", strconv.Itoa(int(memSwap)))
+	}
+	if mem := options.CommonBuildOpts.Memory; mem > 0 {
+		params.Set("memory", strconv.Itoa(int(mem)))
+	}
+	if options.NoCache {
+		params.Set("nocache", "1")
+	}
+	if t := options.Output; len(t) > 0 {
+		params.Set("output", t)
+	}
+	var platform string
+	if len(options.OS) > 0 {
+		platform = options.OS
+	}
+	if len(options.Architecture) > 0 {
+		if len(platform) == 0 {
+			platform = "linux"
+		}
+		platform += "/" + options.Architecture
+	}
+	if len(platform) > 0 {
+		params.Set("platform", platform)
+	}
+	if options.PullPolicy == buildah.PullAlways {
+		params.Set("pull", "1")
+	}
+	if options.Quiet {
+		params.Set("q", "1")
+	}
+	if options.RemoveIntermediateCtrs {
+		params.Set("rm", "1")
+	}
+	if hosts := options.CommonBuildOpts.AddHost; len(hosts) > 0 {
+		h, err := jsoniter.MarshalToString(hosts)
+		if err != nil {
+			return nil, err
+		}
+		params.Set("extrahosts", h)
+	}
+	if shmSize := options.CommonBuildOpts.ShmSize; len(shmSize) > 0 {
+		shmBytes, err := units.RAMInBytes(shmSize)
+		if err != nil {
+			return nil, err
+		}
+		params.Set("shmsize", strconv.Itoa(int(shmBytes)))
+	}
+	if options.Squash {
+		params.Set("squash", "1")
 	}
-
 	var (
 		headers map[string]string
 		err     error
@@ -124,19 +191,6 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
 		stdout = options.Out
 	}
 
-	// TODO network?
-
-	var platform string
-	if OS := options.OS; len(OS) > 0 {
-		platform += OS
-	}
-	if arch := options.Architecture; len(arch) > 0 {
-		platform += "/" + arch
-	}
-	if len(platform) > 0 {
-		params.Set("platform", platform)
-	}
-
 	entries := make([]string, len(containerFiles))
 	copy(entries, containerFiles)
 	entries = append(entries, options.ContextDirectory)
diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go
index 71b4c0089..43524298f 100644
--- a/test/e2e/build_test.go
+++ b/test/e2e/build_test.go
@@ -458,4 +458,55 @@ RUN [[ -L /test/dummy-symlink ]] && echo SYMLNKOK || echo SYMLNKERR`
 		Expect(ok).To(BeTrue())
 	})
 
+	It("podman build --from, --add-host, --cap-drop, --cap-add", func() {
+		targetPath, err := CreateTempDirInTempDir()
+		Expect(err).To(BeNil())
+
+		containerFile := filepath.Join(targetPath, "Containerfile")
+		content := `FROM scratch
+RUN cat /etc/hosts
+RUN grep CapEff /proc/self/status`
+
+		Expect(ioutil.WriteFile(containerFile, []byte(content), 0755)).To(BeNil())
+
+		defer func() {
+			Expect(os.RemoveAll(containerFile)).To(BeNil())
+		}()
+
+		// When
+		session := podmanTest.Podman([]string{
+			"build", "--cap-drop=all", "--cap-add=net_bind_service", "--add-host", "testhost:1.2.3.4", "--from", "alpine", targetPath,
+		})
+		session.WaitWithDefaultTimeout()
+
+		// Then
+		Expect(session.ExitCode()).To(Equal(0))
+		Expect(strings.Fields(session.OutputToString())).
+			To(ContainElement("alpine"))
+		Expect(strings.Fields(session.OutputToString())).
+			To(ContainElement("testhost"))
+		Expect(strings.Fields(session.OutputToString())).
+			To(ContainElement("0000000000000400"))
+	})
+
+	It("podman build --arch", func() {
+		targetPath, err := CreateTempDirInTempDir()
+		Expect(err).To(BeNil())
+
+		containerFile := filepath.Join(targetPath, "Containerfile")
+		Expect(ioutil.WriteFile(containerFile, []byte("FROM alpine"), 0755)).To(BeNil())
+
+		defer func() {
+			Expect(os.RemoveAll(containerFile)).To(BeNil())
+		}()
+
+		// When
+		session := podmanTest.Podman([]string{
+			"build", "--arch", "arm64", targetPath,
+		})
+		session.WaitWithDefaultTimeout()
+
+		// Then
+		Expect(session.ExitCode()).To(Equal(0))
+	})
 })
diff --git a/vendor/github.com/containers/ocicrypt/helpers/parse_helpers.go b/vendor/github.com/containers/ocicrypt/helpers/parse_helpers.go
new file mode 100644
index 000000000..288296ea5
--- /dev/null
+++ b/vendor/github.com/containers/ocicrypt/helpers/parse_helpers.go
@@ -0,0 +1,301 @@
+package helpers
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strconv"
+	"strings"
+
+	"github.com/containers/ocicrypt"
+	encconfig "github.com/containers/ocicrypt/config"
+	encutils "github.com/containers/ocicrypt/utils"
+
+	"github.com/pkg/errors"
+)
+
+// processRecipientKeys sorts the array of recipients by type. Recipients may be either
+// x509 certificates, public keys, or PGP public keys identified by email address or name
+func processRecipientKeys(recipients []string) ([][]byte, [][]byte, [][]byte, error) {
+	var (
+		gpgRecipients [][]byte
+		pubkeys       [][]byte
+		x509s         [][]byte
+	)
+	for _, recipient := range recipients {
+
+		idx := strings.Index(recipient, ":")
+		if idx < 0 {
+			return nil, nil, nil, errors.New("Invalid recipient format")
+		}
+
+		protocol := recipient[:idx]
+		value := recipient[idx+1:]
+
+		switch protocol {
+		case "pgp":
+			gpgRecipients = append(gpgRecipients, []byte(value))
+
+		case "jwe":
+			tmp, err := ioutil.ReadFile(value)
+			if err != nil {
+				return nil, nil, nil, errors.Wrap(err, "Unable to read file")
+			}
+			if !encutils.IsPublicKey(tmp) {
+				return nil, nil, nil, errors.New("File provided is not a public key")
+			}
+			pubkeys = append(pubkeys, tmp)
+
+		case "pkcs7":
+			tmp, err := ioutil.ReadFile(value)
+			if err != nil {
+				return nil, nil, nil, errors.Wrap(err, "Unable to read file")
+			}
+			if !encutils.IsCertificate(tmp) {
+				return nil, nil, nil, errors.New("File provided is not an x509 cert")
+			}
+			x509s = append(x509s, tmp)
+
+		default:
+			return nil, nil, nil, errors.New("Provided protocol not recognized")
+		}
+	}
+	return gpgRecipients, pubkeys, x509s, nil
+}
+
+// processx509Certs processes x509 certificate files
+func processx509Certs(keys []string) ([][]byte, error) {
+	var x509s [][]byte
+	for _, key := range keys {
+		tmp, err := ioutil.ReadFile(key)
+		if err != nil {
+			return nil, errors.Wrap(err, "Unable to read file")
+		}
+		if !encutils.IsCertificate(tmp) {
+			continue
+		}
+		x509s = append(x509s, tmp)
+
+	}
+	return x509s, nil
+}
+
+// processPwdString process a password that may be in any of the following formats:
+// - file=<passwordfile>
+// - pass=<password>
+// - fd=<filedescriptor>
+// - <password>
+func processPwdString(pwdString string) ([]byte, error) {
+	if strings.HasPrefix(pwdString, "file=") {
+		return ioutil.ReadFile(pwdString[5:])
+	} else if strings.HasPrefix(pwdString, "pass=") {
+		return []byte(pwdString[5:]), nil
+	} else if strings.HasPrefix(pwdString, "fd=") {
+		fdStr := pwdString[3:]
+		fd, err := strconv.Atoi(fdStr)
+		if err != nil {
+			return nil, errors.Wrapf(err, "could not parse file descriptor %s", fdStr)
+		}
+		f := os.NewFile(uintptr(fd), "pwdfile")
+		if f == nil {
+			return nil, fmt.Errorf("%s is not a valid file descriptor", fdStr)
+		}
+		defer f.Close()
+		pwd := make([]byte, 64)
+		n, err := f.Read(pwd)
+		if err != nil {
+			return nil, errors.Wrapf(err, "could not read from file descriptor")
+		}
+		return pwd[:n], nil
+	}
+	return []byte(pwdString), nil
+}
+
+// processPrivateKeyFiles sorts the different types of private key files; private key files may either be
+// private keys or GPG private key ring files. The private key files may include the password for the
+// private key and take any of the following forms:
+// - <filename>
+// - <filename>:file=<passwordfile>
+// - <filename>:pass=<password>
+// - <filename>:fd=<filedescriptor>
+// - <filename>:<password>
+func processPrivateKeyFiles(keyFilesAndPwds []string) ([][]byte, [][]byte, [][]byte, [][]byte, error) {
+	var (
+		gpgSecretKeyRingFiles [][]byte
+		gpgSecretKeyPasswords [][]byte
+		privkeys              [][]byte
+		privkeysPasswords     [][]byte
+		err                   error
+	)
+	// keys needed for decryption in case of adding a recipient
+	for _, keyfileAndPwd := range keyFilesAndPwds {
+		var password []byte
+
+		parts := strings.Split(keyfileAndPwd, ":")
+		if len(parts) == 2 {
+			password, err = processPwdString(parts[1])
+			if err != nil {
+				return nil, nil, nil, nil, err
+			}
+		}
+
+		keyfile := parts[0]
+		tmp, err := ioutil.ReadFile(keyfile)
+		if err != nil {
+			return nil, nil, nil, nil, err
+		}
+		isPrivKey, err := encutils.IsPrivateKey(tmp, password)
+		if encutils.IsPasswordError(err) {
+			return nil, nil, nil, nil, err
+		}
+		if isPrivKey {
+			privkeys = append(privkeys, tmp)
+			privkeysPasswords = append(privkeysPasswords, password)
+		} else if encutils.IsGPGPrivateKeyRing(tmp) {
+			gpgSecretKeyRingFiles = append(gpgSecretKeyRingFiles, tmp)
+			gpgSecretKeyPasswords = append(gpgSecretKeyPasswords, password)
+		} else {
+			// ignore if file is not recognized, so as not to error if additional
+			// metadata/cert files exists
+			continue
+		}
+	}
+	return gpgSecretKeyRingFiles, gpgSecretKeyPasswords, privkeys, privkeysPasswords, nil
+}
+
+// CreateDecryptCryptoConfig creates the CryptoConfig object that contains the necessary
+// information to perform decryption from command line options and possibly
+// LayerInfos describing the image and helping us to query for the PGP decryption keys
+func CreateDecryptCryptoConfig(keys []string, decRecipients []string) (encconfig.CryptoConfig, error) {
+	ccs := []encconfig.CryptoConfig{}
+
+	// x509 cert is needed for PKCS7 decryption
+	_, _, x509s, err := processRecipientKeys(decRecipients)
+	if err != nil {
+		return encconfig.CryptoConfig{}, err
+	}
+
+	// x509 certs can also be passed in via keys
+	x509FromKeys, err := processx509Certs(keys)
+	if err != nil {
+		return encconfig.CryptoConfig{}, err
+	}
+	x509s = append(x509s, x509FromKeys...)
+
+	gpgSecretKeyRingFiles, gpgSecretKeyPasswords, privKeys, privKeysPasswords, err := processPrivateKeyFiles(keys)
+	if err != nil {
+		return encconfig.CryptoConfig{}, err
+	}
+
+	if len(gpgSecretKeyRingFiles) > 0 {
+		gpgCc, err := encconfig.DecryptWithGpgPrivKeys(gpgSecretKeyRingFiles, gpgSecretKeyPasswords)
+		if err != nil {
+			return encconfig.CryptoConfig{}, err
+		}
+		ccs = append(ccs, gpgCc)
+	}
+
+	/* TODO: Add in GPG client query for secret keys in the future.
+	_, err = createGPGClient(context)
+	gpgInstalled := err == nil
+	if gpgInstalled {
+		if len(gpgSecretKeyRingFiles) == 0 && len(privKeys) == 0 && descs != nil {
+			// Get pgp private keys from keyring only if no private key was passed
+			gpgPrivKeys, gpgPrivKeyPasswords, err := getGPGPrivateKeys(context, gpgSecretKeyRingFiles, descs, true)
+			if err != nil {
+				return encconfig.CryptoConfig{}, err
+			}
+
+			gpgCc, err := encconfig.DecryptWithGpgPrivKeys(gpgPrivKeys, gpgPrivKeyPasswords)
+			if err != nil {
+				return encconfig.CryptoConfig{}, err
+			}
+			ccs = append(ccs, gpgCc)
+
+		} else if len(gpgSecretKeyRingFiles) > 0 {
+			gpgCc, err := encconfig.DecryptWithGpgPrivKeys(gpgSecretKeyRingFiles, gpgSecretKeyPasswords)
+			if err != nil {
+				return encconfig.CryptoConfig{}, err
+			}
+			ccs = append(ccs, gpgCc)
+
+		}
+	}
+	*/
+
+	x509sCc, err := encconfig.DecryptWithX509s(x509s)
+	if err != nil {
+		return encconfig.CryptoConfig{}, err
+	}
+	ccs = append(ccs, x509sCc)
+
+	privKeysCc, err := encconfig.DecryptWithPrivKeys(privKeys, privKeysPasswords)
+	if err != nil {
+		return encconfig.CryptoConfig{}, err
+	}
+	ccs = append(ccs, privKeysCc)
+
+	return encconfig.CombineCryptoConfigs(ccs), nil
+}
+
+// CreateCryptoConfig from the list of recipient strings and list of key paths of private keys
+func CreateCryptoConfig(recipients []string, keys []string) (encconfig.CryptoConfig, error) {
+	var decryptCc *encconfig.CryptoConfig
+	ccs := []encconfig.CryptoConfig{}
+	if len(keys) > 0 {
+		dcc, err := CreateDecryptCryptoConfig(keys, []string{})
+		if err != nil {
+			return encconfig.CryptoConfig{}, err
+		}
+		decryptCc = &dcc
+		ccs = append(ccs, dcc)
+	}
+
+	if len(recipients) > 0 {
+		gpgRecipients, pubKeys, x509s, err := processRecipientKeys(recipients)
+		if err != nil {
+			return encconfig.CryptoConfig{}, err
+		}
+		encryptCcs := []encconfig.CryptoConfig{}
+
+		// Create GPG client with guessed GPG version and default homedir
+		gpgClient, err := ocicrypt.NewGPGClient("", "")
+		gpgInstalled := err == nil
+		if len(gpgRecipients) > 0 && gpgInstalled {
+			gpgPubRingFile, err := gpgClient.ReadGPGPubRingFile()
+			if err != nil {
+				return encconfig.CryptoConfig{}, err
+			}
+
+			gpgCc, err := encconfig.EncryptWithGpg(gpgRecipients, gpgPubRingFile)
+			if err != nil {
+				return encconfig.CryptoConfig{}, err
+			}
+			encryptCcs = append(encryptCcs, gpgCc)
+		}
+
+		// Create Encryption Crypto Config
+		pkcs7Cc, err := encconfig.EncryptWithPkcs7(x509s)
+		if err != nil {
+			return encconfig.CryptoConfig{}, err
+		}
+		encryptCcs = append(encryptCcs, pkcs7Cc)
+
+		jweCc, err := encconfig.EncryptWithJwe(pubKeys)
+		if err != nil {
+			return encconfig.CryptoConfig{}, err
+		}
+		encryptCcs = append(encryptCcs, jweCc)
+		ecc := encconfig.CombineCryptoConfigs(encryptCcs)
+		if decryptCc != nil {
+			ecc.EncryptConfig.AttachDecryptConfig(decryptCc.DecryptConfig)
+		}
+		ccs = append(ccs, ecc)
+	}
+
+	if len(ccs) > 0 {
+		return encconfig.CombineCryptoConfigs(ccs), nil
+	} else {
+		return encconfig.CryptoConfig{}, nil
+	}
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 0f4c2b9a7..ad6465022 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -159,6 +159,7 @@ github.com/containers/libtrust
 github.com/containers/ocicrypt
 github.com/containers/ocicrypt/blockcipher
 github.com/containers/ocicrypt/config
+github.com/containers/ocicrypt/helpers
 github.com/containers/ocicrypt/keywrap
 github.com/containers/ocicrypt/keywrap/jwe
 github.com/containers/ocicrypt/keywrap/pgp
-- 
cgit v1.2.3-54-g00ecf


From 566c8a43baf63d43f3bf2320f0feadc6104d931e Mon Sep 17 00:00:00 2001
From: Daniel J Walsh <dwalsh@redhat.com>
Date: Mon, 8 Feb 2021 14:26:51 -0500
Subject: Bump containers/buildah to v1.19.4

Fix handling of --iidfile to happen on the client side.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
---
 cmd/podman/images/build.go        | 14 ++++++++++++--
 pkg/domain/infra/tunnel/images.go | 11 -----------
 test/e2e/build_test.go            |  2 +-
 3 files changed, 13 insertions(+), 14 deletions(-)

(limited to 'test')

diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index 0c97a2488..abd3ced5b 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -264,7 +264,18 @@ func build(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
-	_, err = registry.ImageEngine().Build(registry.GetContext(), containerFiles, *apiBuildOpts)
+	report, err := registry.ImageEngine().Build(registry.GetContext(), containerFiles, *apiBuildOpts)
+
+	if cmd.Flag("iidfile").Changed {
+		f, err := os.Create(buildOpts.Iidfile)
+		if err != nil {
+			return err
+		}
+		if _, err := f.WriteString("sha256:" + report.ID); err != nil {
+			return err
+		}
+	}
+
 	return err
 }
 
@@ -468,7 +479,6 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
 		ForceRmIntermediateCtrs: flags.ForceRm,
 		From:                    flags.From,
 		IDMappingOptions:        idmappingOptions,
-		IIDFile:                 flags.Iidfile,
 		In:                      stdin,
 		Isolation:               isolation,
 		Jobs:                    &flags.Jobs,
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 214a9fef8..b5f09ab22 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -349,17 +349,6 @@ func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts en
 	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
 }
 
diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go
index 43524298f..9bab4c926 100644
--- a/test/e2e/build_test.go
+++ b/test/e2e/build_test.go
@@ -194,7 +194,7 @@ var _ = Describe("Podman build", func() {
 		inspect := podmanTest.Podman([]string{"inspect", string(id)})
 		inspect.WaitWithDefaultTimeout()
 		data := inspect.InspectImageJSON()
-		Expect(data[0].ID).To(Equal(string(id)))
+		Expect("sha256:" + data[0].ID).To(Equal(string(id)))
 	})
 
 	It("podman Test PATH in built image", func() {
-- 
cgit v1.2.3-54-g00ecf