diff options
-rw-r--r-- | pkg/api/handlers/compat/images_build.go | 92 | ||||
-rw-r--r-- | pkg/bindings/images/build.go | 18 | ||||
-rw-r--r-- | test/e2e/build_test.go | 27 | ||||
-rw-r--r-- | test/e2e/prune_test.go | 1 | ||||
-rw-r--r-- | test/system/070-build.bats | 39 |
5 files changed, 152 insertions, 25 deletions
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 0f27a090f..9b26f1147 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -10,9 +10,11 @@ import ( "os" "path/filepath" "strconv" + "time" "github.com/containers/buildah" "github.com/containers/buildah/imagebuildah" + "github.com/containers/buildah/util" "github.com/containers/image/v5/types" "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/pkg/api/handlers/utils" @@ -20,6 +22,7 @@ import ( "github.com/containers/podman/v2/pkg/channel" "github.com/containers/storage/pkg/archive" "github.com/gorilla/schema" + specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -65,6 +68,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Annotations string `schema:"annotations"` BuildArgs string `schema:"buildargs"` CacheFrom string `schema:"cachefrom"` + Compression uint64 `schema:"compression"` ConfigureNetwork int64 `schema:"networkmode"` CpuPeriod uint64 `schema:"cpuperiod"` // nolint CpuQuota int64 `schema:"cpuquota"` // nolint @@ -73,17 +77,20 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Devices string `schema:"devices"` Dockerfile string `schema:"dockerfile"` DropCapabilities string `schema:"dropcaps"` + Excludes string `schema:"excludes"` ForceRm bool `schema:"forcerm"` From string `schema:"from"` HTTPProxy bool `schema:"httpproxy"` Isolation int64 `schema:"isolation"` - Jobs uint64 `schema:"jobs"` // nolint + Ignore bool `schema:"ignore"` + Jobs int `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"` + NamespaceOptions string `schema:"nsoptions"` NoCache bool `schema:"nocache"` OutputFormat string `schema:"outputformat"` Platform string `schema:"platform"` @@ -129,6 +136,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } } + compression := archive.Compression(query.Compression) // convert label formats var dropCaps = []string{} if _, found := r.URL.Query()["dropcaps"]; found { @@ -156,7 +164,15 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { output = query.Tag[0] } format := buildah.Dockerv2ImageManifest + registry := query.Registry + isolation := buildah.IsolationChroot + /* + // FIXME, This is very broken. Buildah will only work with chroot + isolation := buildah.IsolationDefault + */ if utils.IsLibpodRequest(r) { + // isolation = buildah.Isolation(query.Isolation) + registry = "" format = query.OutputFormat } var additionalTags []string @@ -172,6 +188,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } } + var excludes = []string{} + if _, found := r.URL.Query()["excludes"]; found { + if err := json.Unmarshal([]byte(query.Excludes), &excludes); err != nil { + utils.BadRequest(w, "excludes", query.Excludes, err) + return + } + } + // convert label formats var annotations = []string{} if _, found := r.URL.Query()["annotations"]; found { @@ -182,6 +206,19 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } // convert label formats + nsoptions := buildah.NamespaceOptions{} + if _, found := r.URL.Query()["nsoptions"]; found { + if err := json.Unmarshal([]byte(query.NamespaceOptions), &nsoptions); err != nil { + utils.BadRequest(w, "nsoptions", query.NamespaceOptions, err) + return + } + } else { + nsoptions = append(nsoptions, buildah.NamespaceOption{ + Name: string(specs.NetworkNamespace), + Host: true, + }) + } + // convert label formats var labels = []string{} if _, found := r.URL.Query()["labels"]; found { if err := json.Unmarshal([]byte(query.Labels), &labels); err != nil { @@ -189,6 +226,10 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { return } } + jobs := 1 + if _, found := r.URL.Query()["jobs"]; found { + jobs = query.Jobs + } pullPolicy := buildah.PullIfMissing if _, found := r.URL.Query()["pull"]; found { @@ -218,6 +259,12 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { reporter := channel.NewWriter(make(chan []byte, 1)) defer reporter.Close() + runtime := r.Context().Value("runtime").(*libpod.Runtime) + rtc, err := runtime.GetConfig() + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) + return + } buildOptions := imagebuildah.BuildOptions{ AddCapabilities: addCaps, AdditionalTags: additionalTags, @@ -234,32 +281,36 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { MemorySwap: query.MemSwap, ShmSize: strconv.Itoa(query.ShmSize), }, - Compression: archive.Gzip, + CNIConfigDir: rtc.Network.CNIPluginDirs[0], + CNIPluginPath: util.DefaultCNIPluginPath, + Compression: compression, ConfigureNetwork: buildah.NetworkConfigurationPolicy(query.ConfigureNetwork), ContextDirectory: contextDirectory, Devices: devices, DropCapabilities: dropCaps, Err: auxout, + Excludes: excludes, 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, + IgnoreUnrecognizedInstructions: query.Ignore, + Isolation: isolation, + Jobs: &jobs, + Labels: labels, + Layers: query.Layers, + Manifest: query.Manifest, + MaxPullPushRetries: 3, + NamespaceOptions: nsoptions, + NoCache: query.NoCache, + Out: stdout, + Output: output, + OutputFormat: format, + PullPolicy: pullPolicy, + PullPushRetryDelay: time.Duration(2 * time.Second), + Quiet: query.Quiet, + Registry: registry, + RemoveIntermediateCtrs: query.Rm, + ReportWriter: reporter, + Squash: query.Squash, SystemContext: &types.SystemContext{ AuthFilePath: authfile, DockerAuthConfig: creds, @@ -267,7 +318,6 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Target: query.Target, } - runtime := r.Context().Value("runtime").(*libpod.Runtime) runCtx, cancel := context.WithCancel(context.Background()) var imageID string go func() { diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 8ea09b881..76f9c56e5 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -57,6 +57,13 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } params.Set("buildargs", bArgs) } + if excludes := options.Excludes; len(excludes) > 0 { + bArgs, err := jsoniter.MarshalToString(excludes) + if err != nil { + return nil, err + } + params.Set("excludes", bArgs) + } if cpuShares := options.CommonBuildOpts.CPUShares; cpuShares > 0 { params.Set("cpushares", strconv.Itoa(int(cpuShares))) } @@ -94,7 +101,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO if len(options.From) > 0 { params.Set("from", options.From) } - + if options.IgnoreUnrecognizedInstructions { + params.Set("ignore", "1") + } params.Set("isolation", strconv.Itoa(int(options.Isolation))) if options.CommonBuildOpts.HTTPProxy { params.Set("httpproxy", "1") @@ -159,6 +168,13 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } params.Set("extrahosts", h) } + if nsoptions := options.NamespaceOptions; len(nsoptions) > 0 { + ns, err := jsoniter.MarshalToString(nsoptions) + if err != nil { + return nil, err + } + params.Set("nsoptions", ns) + } if shmSize := options.CommonBuildOpts.ShmSize; len(shmSize) > 0 { shmBytes, err := units.RAMInBytes(shmSize) if err != nil { diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go index 9bab4c926..bdd35db8f 100644 --- a/test/e2e/build_test.go +++ b/test/e2e/build_test.go @@ -489,7 +489,7 @@ RUN grep CapEff /proc/self/status` To(ContainElement("0000000000000400")) }) - It("podman build --arch", func() { + It("podman build --isolation && --arch", func() { targetPath, err := CreateTempDirInTempDir() Expect(err).To(BeNil()) @@ -502,11 +502,34 @@ RUN grep CapEff /proc/self/status` // When session := podmanTest.Podman([]string{ - "build", "--arch", "arm64", targetPath, + "build", "--isolation", "oci", "--arch", "arm64", targetPath, }) session.WaitWithDefaultTimeout() + // Then + Expect(session.ExitCode()).To(Equal(0)) + // When + session = podmanTest.Podman([]string{ + "build", "--isolation", "chroot", "--arch", "arm64", targetPath, + }) + session.WaitWithDefaultTimeout() // Then Expect(session.ExitCode()).To(Equal(0)) + + // When + session = podmanTest.Podman([]string{ + "build", "--isolation", "rootless", "--arch", "arm64", targetPath, + }) + session.WaitWithDefaultTimeout() + // Then + Expect(session.ExitCode()).To(Equal(0)) + + // When + session = podmanTest.Podman([]string{ + "build", "--isolation", "bogus", "--arch", "arm64", targetPath, + }) + session.WaitWithDefaultTimeout() + // Then + Expect(session.ExitCode()).To(Equal(125)) }) }) diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go index f84312103..f19627170 100644 --- a/test/e2e/prune_test.go +++ b/test/e2e/prune_test.go @@ -111,7 +111,6 @@ var _ = Describe("Podman prune", func() { It("podman image prune dangling images", func() { podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true") podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true") - none := podmanTest.Podman([]string{"images", "-a"}) none.WaitWithDefaultTimeout() Expect(none.ExitCode()).To(Equal(0)) diff --git a/test/system/070-build.bats b/test/system/070-build.bats index 7a42a4c18..3ae95b5f5 100644 --- a/test/system/070-build.bats +++ b/test/system/070-build.bats @@ -453,6 +453,45 @@ EOF run_podman rmi -a --force } +@test "build with copy-from referencing the base image" { + skip_if_rootless "cannot mount as rootless" + target=busybox-derived + target_mt=busybox-mt-derived + tmpdir=$PODMAN_TMPDIR/build-test + mkdir -p $tmpdir + containerfile1=$tmpdir/Containerfile1 + cat >$containerfile1 <<EOF +FROM quay.io/libpod/busybox AS build +RUN rm -f /bin/paste +USER 1001 +COPY --from=quay.io/libpod/busybox /bin/paste /test/ +EOF + containerfile2=$tmpdir/Containerfile2 + cat >$containerfile2 <<EOF +FROM quay.io/libpod/busybox AS test +RUN rm -f /bin/nl +FROM quay.io/libpod/alpine AS final +COPY --from=quay.io/libpod/busybox /bin/nl /test/ +EOF + run_podman build -t ${target} -f ${containerfile1} ${tmpdir} + run_podman build --jobs 4 -t ${target} -f ${containerfile1} ${tmpdir} + + run_podman build -t ${target} -f ${containerfile2} ${tmpdir} + run_podman build --no-cache --jobs 4 -t ${target_mt} -f ${containerfile2} ${tmpdir} + + # (can only test locally; podman-remote has no image mount command) + if ! is_remote; then + run_podman image mount ${target} + root_single_job=$output + + run_podman image mount ${target_mt} + root_multi_job=$output + + # Check that both the version with --jobs 1 and --jobs=N have the same number of files + test $(find $root_single_job -type f | wc -l) = $(find $root_multi_job -type f | wc -l) + fi +} + @test "podman build --logfile test" { tmpdir=$PODMAN_TMPDIR/build-test mkdir -p $tmpdir |