From 7e7a79b075f7d65657d95169f02c2c1c03198b93 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Tue, 16 Aug 2022 18:30:19 -0400 Subject: podman manifest create: accept --amend and --insecure flags Accept a --amend flag in `podman manifest create`, and treat `--insecure` as we would `--tls-verify=false` in `podman manifest`'s "add", "create", and "push" subcommands. Signed-off-by: Nalin Dahyabhai --- pkg/api/handlers/libpod/manifests.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'pkg/api/handlers') diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go index b0c93f3b9..fa83bbfe1 100644 --- a/pkg/api/handlers/libpod/manifests.go +++ b/pkg/api/handlers/libpod/manifests.go @@ -36,6 +36,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) { Name string `schema:"name"` Images []string `schema:"images"` All bool `schema:"all"` + Amend bool `schema:"amend"` }{ // Add defaults here once needed. } @@ -70,7 +71,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) { imageEngine := abi.ImageEngine{Libpod: runtime} - createOptions := entities.ManifestCreateOptions{All: query.All} + createOptions := entities.ManifestCreateOptions{All: query.All, Amend: query.Amend} manID, err := imageEngine.ManifestCreate(r.Context(), query.Name, query.Images, createOptions) if err != nil { utils.InternalServerError(w, err) -- cgit v1.2.3-54-g00ecf From aa197a65ff245f4d244968fd6010537a76a42e10 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 17 Aug 2022 14:39:32 -0400 Subject: sort hc.Binds returned from compat api Signed-off-by: Josh Patterson --- pkg/api/handlers/compat/containers.go | 1 + 1 file changed, 1 insertion(+) (limited to 'pkg/api/handlers') diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index ae063dc9f..0b82c48f6 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -467,6 +467,7 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON, if err := json.Unmarshal(h, &hc); err != nil { return nil, err } + sort.Strings(hc.Binds) // k8s-file == json-file if hc.LogConfig.Type == define.KubernetesLogging { -- cgit v1.2.3-54-g00ecf From b9fb60c68acb57e56edae0b35dd408f454d32be5 Mon Sep 17 00:00:00 2001 From: Vladimir Kochnev Date: Wed, 17 Aug 2022 03:04:55 +0300 Subject: Simplify ImagesPull for when Quiet flag is on Refactor ImagesPull the same way the ImagesPush and ManifestPush are done. [NO NEW TESTS NEEDED] Signed-off-by: Vladimir Kochnev --- pkg/api/handlers/libpod/images_pull.go | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) (limited to 'pkg/api/handlers') diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go index 7e24ae5ac..57b2e3a78 100644 --- a/pkg/api/handlers/libpod/images_pull.go +++ b/pkg/api/handlers/libpod/images_pull.go @@ -82,17 +82,32 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { pullOptions.IdentityToken = authConf.IdentityToken } - writer := channel.NewWriter(make(chan []byte)) - defer writer.Close() - - pullOptions.Writer = writer - pullPolicy, err := config.ParsePullPolicy(query.PullPolicy) if err != nil { utils.Error(w, http.StatusBadRequest, err) return } + // Let's keep thing simple when running in quiet mode and pull directly. + if query.Quiet { + images, err := runtime.LibimageRuntime().Pull(r.Context(), query.Reference, pullPolicy, pullOptions) + var report entities.ImagePullReport + if err != nil { + report.Error = err.Error() + } + for _, image := range images { + report.Images = append(report.Images, image.ID()) + // Pull last ID from list and publish in 'id' stanza. This maintains previous API contract + report.ID = image.ID() + } + utils.WriteResponse(w, http.StatusOK, report) + return + } + + writer := channel.NewWriter(make(chan []byte)) + defer writer.Close() + pullOptions.Writer = writer + var pulledImages []*libimage.Image var pullError error runCtx, cancel := context.WithCancel(r.Context()) @@ -118,10 +133,8 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { select { case s := <-writer.Chan(): report.Stream = string(s) - if !query.Quiet { - if err := enc.Encode(report); err != nil { - logrus.Warnf("Failed to encode json: %v", err) - } + if err := enc.Encode(report); err != nil { + logrus.Warnf("Failed to encode json: %v", err) } flush() case <-runCtx.Done(): -- cgit v1.2.3-54-g00ecf From e48681e600e55718a9699006ac940738fa08f896 Mon Sep 17 00:00:00 2001 From: Vladimir Kochnev Date: Wed, 17 Aug 2022 03:07:01 +0300 Subject: Use request Context() in API handlers Request object has its own context which must be used during a request lifetime instead of just context.Background() [NO NEW TESTS NEEDED] Signed-off-by: Vladimir Kochnev --- pkg/api/handlers/compat/auth.go | 3 +-- pkg/api/handlers/compat/images_build.go | 2 +- pkg/api/handlers/libpod/containers_create.go | 5 ++--- pkg/api/handlers/libpod/images_push.go | 2 +- pkg/api/handlers/libpod/manifests.go | 4 ++-- pkg/api/handlers/types.go | 2 +- 6 files changed, 8 insertions(+), 10 deletions(-) (limited to 'pkg/api/handlers') diff --git a/pkg/api/handlers/compat/auth.go b/pkg/api/handlers/compat/auth.go index 37d2b784d..ee478b9e3 100644 --- a/pkg/api/handlers/compat/auth.go +++ b/pkg/api/handlers/compat/auth.go @@ -1,7 +1,6 @@ package compat import ( - "context" "encoding/json" "errors" "fmt" @@ -44,7 +43,7 @@ func Auth(w http.ResponseWriter, r *http.Request) { fmt.Println("Authenticating with existing credentials...") registry := stripAddressOfScheme(authConfig.ServerAddress) - if err := DockerClient.CheckAuth(context.Background(), sysCtx, authConfig.Username, authConfig.Password, registry); err == nil { + if err := DockerClient.CheckAuth(r.Context(), sysCtx, authConfig.Username, authConfig.Password, registry); err == nil { utils.WriteResponse(w, http.StatusOK, entities.AuthReport{ IdentityToken: "", Status: "Login Succeeded", diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index a00f0b089..020991cc7 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -694,7 +694,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { success bool ) - runCtx, cancel := context.WithCancel(context.Background()) + runCtx, cancel := context.WithCancel(r.Context()) go func() { defer cancel() imageID, _, err = runtime.Build(r.Context(), buildOptions, containerFiles...) diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go index 1307c267a..429f45f91 100644 --- a/pkg/api/handlers/libpod/containers_create.go +++ b/pkg/api/handlers/libpod/containers_create.go @@ -1,7 +1,6 @@ package libpod import ( - "context" "encoding/json" "fmt" "net/http" @@ -63,12 +62,12 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), runtime, &sg, false, nil) + rtSpec, spec, opts, err := generate.MakeContainer(r.Context(), runtime, &sg, false, nil) if err != nil { utils.InternalServerError(w, err) return } - ctr, err := generate.ExecuteCreate(context.Background(), runtime, rtSpec, spec, false, opts...) + ctr, err := generate.ExecuteCreate(r.Context(), runtime, rtSpec, spec, false, opts...) if err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/handlers/libpod/images_push.go b/pkg/api/handlers/libpod/images_push.go index e931fd2f9..be6f5b131 100644 --- a/pkg/api/handlers/libpod/images_push.go +++ b/pkg/api/handlers/libpod/images_push.go @@ -90,7 +90,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) { // Let's keep thing simple when running in quiet mode and push directly. if query.Quiet { - if err := imageEngine.Push(context.Background(), source, destination, options); err != nil { + if err := imageEngine.Push(r.Context(), source, destination, options); err != nil { utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err)) return } diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go index fa83bbfe1..8391def5c 100644 --- a/pkg/api/handlers/libpod/manifests.go +++ b/pkg/api/handlers/libpod/manifests.go @@ -293,7 +293,7 @@ func ManifestPushV3(w http.ResponseWriter, r *http.Request) { options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) } imageEngine := abi.ImageEngine{Libpod: runtime} - digest, err := imageEngine.ManifestPush(context.Background(), source, query.Destination, options) + digest, err := imageEngine.ManifestPush(r.Context(), source, query.Destination, options) if err != nil { utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", query.Destination, err)) return @@ -367,7 +367,7 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) { // Let's keep thing simple when running in quiet mode and push directly. if query.Quiet { - digest, err := imageEngine.ManifestPush(context.Background(), source, destination, options) + digest, err := imageEngine.ManifestPush(r.Context(), source, destination, options) if err != nil { utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err)) return diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go index b533e131c..6d245d950 100644 --- a/pkg/api/handlers/types.go +++ b/pkg/api/handlers/types.go @@ -162,7 +162,7 @@ type ExecStartConfig struct { func ImageDataToImageInspect(ctx context.Context, l *libimage.Image) (*ImageInspect, error) { options := &libimage.InspectOptions{WithParent: true, WithSize: true} - info, err := l.Inspect(context.Background(), options) + info, err := l.Inspect(ctx, options) if err != nil { return nil, err } -- cgit v1.2.3-54-g00ecf From b4584ea8546be227c74174130ec3a04a93996d28 Mon Sep 17 00:00:00 2001 From: Aditya R Date: Wed, 24 Aug 2022 11:22:33 +0530 Subject: run,create: add support for --env-merge for preprocessing vars Allow end users to preprocess default environment variables before injecting them into container using `--env-merge` Usage ``` podman run -it --rm --env-merge some=${some}-edit --env-merge some2=${some2}-edit2 myimage sh ``` Closes: https://github.com/containers/podman/issues/15288 Signed-off-by: Aditya R --- cmd/podman/common/create.go | 8 ++++++++ docs/source/markdown/options/env-merge.md | 5 +++++ docs/source/markdown/podman-create.1.md.in | 2 ++ docs/source/markdown/podman-run.1.md.in | 2 ++ go.mod | 1 + pkg/api/handlers/compat/containers_create.go | 1 + pkg/api/handlers/types.go | 1 + pkg/domain/entities/pods.go | 1 + pkg/specgen/generate/container.go | 12 ++++++++++++ pkg/specgen/specgen.go | 3 +++ pkg/specgenutil/specgen.go | 3 +++ test/e2e/run_env_test.go | 11 +++++++++++ vendor/modules.txt | 1 + 13 files changed, 51 insertions(+) create mode 100644 docs/source/markdown/options/env-merge.md (limited to 'pkg/api/handlers') diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 00873b95b..1e573cc2d 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -124,6 +124,14 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, "This is a Docker specific option and is a NOOP", ) + envMergeFlagName := "env-merge" + createFlags.StringArrayVar( + &cf.EnvMerge, + envMergeFlagName, []string{}, + "Preprocess environment variables from image before injecting them into the container", + ) + _ = cmd.RegisterFlagCompletionFunc(envMergeFlagName, completion.AutocompleteNone) + envFlagName := "env" createFlags.StringArrayP( envFlagName, "e", Env(), diff --git a/docs/source/markdown/options/env-merge.md b/docs/source/markdown/options/env-merge.md new file mode 100644 index 000000000..aa1aa003d --- /dev/null +++ b/docs/source/markdown/options/env-merge.md @@ -0,0 +1,5 @@ +#### **--env-merge**=*env* + +Preprocess default environment variables for the containers. For example +if image contains environment variable `hello=world` user can preprocess +it using `--env-merge hello=${hello}-some` so new value will be `hello=world-some`. diff --git a/docs/source/markdown/podman-create.1.md.in b/docs/source/markdown/podman-create.1.md.in index 9518568bb..0e65e7e3a 100644 --- a/docs/source/markdown/podman-create.1.md.in +++ b/docs/source/markdown/podman-create.1.md.in @@ -208,6 +208,8 @@ Read in a line delimited file of environment variables. See **Environment** note @@option env-host +@@option env-merge + @@option expose #### **--gidmap**=*container_gid:host_gid:amount* diff --git a/docs/source/markdown/podman-run.1.md.in b/docs/source/markdown/podman-run.1.md.in index 3e31ccc45..98d57a9c1 100644 --- a/docs/source/markdown/podman-run.1.md.in +++ b/docs/source/markdown/podman-run.1.md.in @@ -243,6 +243,8 @@ Read in a line delimited file of environment variables. See **Environment** note @@option env-host +@@option env-merge + @@option expose #### **--gidmap**=*container_gid:host_gid:amount* diff --git a/go.mod b/go.mod index 635c0a17d..a694e6add 100644 --- a/go.mod +++ b/go.mod @@ -49,6 +49,7 @@ require ( github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab github.com/opencontainers/runtime-tools v0.9.1-0.20220714195903-17b3287fafb7 github.com/opencontainers/selinux v1.10.1 + github.com/openshift/imagebuilder v1.2.4-0.20220711175835-4151e43600df github.com/rootless-containers/rootlesskit v1.0.1 github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.5.0 diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go index 9fff8b4c8..d4f5d5f36 100644 --- a/pkg/api/handlers/compat/containers_create.go +++ b/pkg/api/handlers/compat/containers_create.go @@ -408,6 +408,7 @@ func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.C Systemd: "true", // podman default TmpFS: parsedTmp, TTY: cc.Config.Tty, + EnvMerge: cc.EnvMerge, UnsetEnv: cc.UnsetEnv, UnsetEnvAll: cc.UnsetEnvAll, User: cc.Config.User, diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go index b533e131c..ebbc5f63a 100644 --- a/pkg/api/handlers/types.go +++ b/pkg/api/handlers/types.go @@ -127,6 +127,7 @@ type CreateContainerConfig struct { dockerContainer.Config // desired container configuration HostConfig dockerContainer.HostConfig // host dependent configuration for container NetworkingConfig dockerNetwork.NetworkingConfig // network configuration for container + EnvMerge []string // preprocess env variables from image before injecting into containers UnsetEnv []string // unset specified default environment variables UnsetEnvAll bool // unset all default environment variables } diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index 14ce370c1..33ca2c807 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -263,6 +263,7 @@ type ContainerCreateOptions struct { TTY bool Timezone string Umask string + EnvMerge []string UnsetEnv []string UnsetEnvAll bool UIDMap []string diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 85cd8f5ca..e293ce010 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -19,6 +19,7 @@ import ( "github.com/containers/podman/v4/pkg/signal" "github.com/containers/podman/v4/pkg/specgen" spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/openshift/imagebuilder" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) @@ -131,6 +132,17 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat defaultEnvs = envLib.Join(envLib.DefaultEnvVariables(), envLib.Join(defaultEnvs, envs)) } + for _, e := range s.EnvMerge { + processedWord, err := imagebuilder.ProcessWord(e, envLib.Slice(defaultEnvs)) + if err != nil { + return nil, fmt.Errorf("unable to process variables for --env-merge %s: %w", e, err) + } + splitWord := strings.Split(processedWord, "=") + if _, ok := defaultEnvs[splitWord[0]]; ok { + defaultEnvs[splitWord[0]] = splitWord[1] + } + } + for _, e := range s.UnsetEnv { delete(defaultEnvs, e) } diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index b90f07ef8..51b6736a9 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -204,6 +204,9 @@ type ContainerBasicConfig struct { // The execution domain system allows Linux to provide limited support // for binaries compiled under other UNIX-like operating systems. Personality *spec.LinuxPersonality `json:"personality,omitempty"` + // EnvMerge takes the specified environment variables from image and preprocess them before injecting them into the + // container. + EnvMerge []string `json:"envmerge,omitempty"` // UnsetEnv unsets the specified default environment variables from the image or from buildin or containers.conf // Optional. UnsetEnv []string `json:"unsetenv,omitempty"` diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 7392e7b44..aab2eebd5 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -839,6 +839,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions if !s.Volatile { s.Volatile = c.Rm } + if len(s.EnvMerge) == 0 || len(c.EnvMerge) != 0 { + s.EnvMerge = c.EnvMerge + } if len(s.UnsetEnv) == 0 || len(c.UnsetEnv) != 0 { s.UnsetEnv = c.UnsetEnv } diff --git a/test/e2e/run_env_test.go b/test/e2e/run_env_test.go index bab52efc5..9e78e150a 100644 --- a/test/e2e/run_env_test.go +++ b/test/e2e/run_env_test.go @@ -82,6 +82,17 @@ var _ = Describe("Podman run", func() { Expect(session.OutputToString()).To(ContainSubstring("HOSTNAME")) }) + It("podman run with --env-merge", func() { + dockerfile := `FROM quay.io/libpod/alpine:latest +ENV hello=world +` + podmanTest.BuildImage(dockerfile, "test", "false") + session := podmanTest.Podman([]string{"run", "--rm", "--env-merge", "hello=${hello}-earth", "test", "env"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("world-earth")) + }) + It("podman run --env-host environment test", func() { env := append(os.Environ(), "FOO=BAR") session := podmanTest.PodmanAsUser([]string{"run", "--rm", "--env-host", ALPINE, "/bin/printenv", "FOO"}, 0, 0, "", env) diff --git a/vendor/modules.txt b/vendor/modules.txt index eb9c7a34d..feb9f00d5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -620,6 +620,7 @@ github.com/opencontainers/selinux/go-selinux/label github.com/opencontainers/selinux/pkg/pwalk github.com/opencontainers/selinux/pkg/pwalkdir # github.com/openshift/imagebuilder v1.2.4-0.20220711175835-4151e43600df +## explicit github.com/openshift/imagebuilder github.com/openshift/imagebuilder/dockerfile/command github.com/openshift/imagebuilder/dockerfile/parser -- cgit v1.2.3-54-g00ecf From c7fda06f669ab1be6b36aa3312c6c6d732e06c9b Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Thu, 25 Aug 2022 14:10:49 -0400 Subject: Compat API image remove events now have 'delete' status Change only the compat API, so we don't force a breaking change on Libpod API users. Partial fix for #15485 Signed-off-by: Matthew Heon --- pkg/api/handlers/compat/events.go | 6 ++++++ test/apiv2/10-images.at | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'pkg/api/handlers') diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go index 18fb35966..105404a0d 100644 --- a/pkg/api/handlers/compat/events.go +++ b/pkg/api/handlers/compat/events.go @@ -89,6 +89,12 @@ func GetEvents(w http.ResponseWriter, r *http.Request) { } e := entities.ConvertToEntitiesEvent(*evt) + // Some events differ between Libpod and Docker endpoints. + // Handle these differences for Docker-compat. + if !utils.IsLibpodRequest(r) && e.Type == "image" && e.Status == "remove" { + e.Status = "delete" + e.Action = "delete" + } if !utils.IsLibpodRequest(r) && e.Status == "died" { e.Status = "die" e.Action = "die" diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at index 4fd954e37..86ee2a1f5 100644 --- a/test/apiv2/10-images.at +++ b/test/apiv2/10-images.at @@ -239,4 +239,23 @@ fi cleanBuildTest +# compat API vs libpod API event differences: +# on image removal, libpod produces 'remove' events. +# compat produces 'delete' events. +podman image build -t test:test -< Date: Thu, 25 Aug 2022 12:10:53 +0530 Subject: remote: fix implementation of build with --userns=auto for API `podman-remote` and Libpod API does not supports build with `--userns=auto` since `IDMappingOptions` were not implemented for API and bindings, following PR implements passing `IDMappingOptions` via bindings to API. Closes: https://github.com/containers/podman/issues/15476 Signed-off-by: Aditya R --- pkg/api/handlers/compat/images_build.go | 10 ++++++++++ pkg/bindings/images/build.go | 7 +++++++ test/e2e/build/Containerfile.userns-auto | 2 ++ test/e2e/run_userns_test.go | 30 ++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 test/e2e/build/Containerfile.userns-auto (limited to 'pkg/api/handlers') diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 020991cc7..7ba1029a7 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -101,6 +101,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { ForceRm bool `schema:"forcerm"` From string `schema:"from"` HTTPProxy bool `schema:"httpproxy"` + IDMappingOptions string `schema:"idmappingoptions"` IdentityLabel bool `schema:"identitylabel"` Ignore bool `schema:"ignore"` Isolation string `schema:"isolation"` @@ -389,6 +390,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } } + var idMappingOptions buildahDefine.IDMappingOptions + if _, found := r.URL.Query()["idmappingoptions"]; found { + if err := json.Unmarshal([]byte(query.IDMappingOptions), &idMappingOptions); err != nil { + utils.BadRequest(w, "idmappingoptions", query.IDMappingOptions, err) + return + } + } + var cacheFrom reference.Named if _, found := r.URL.Query()["cachefrom"]; found { cacheFrom, err = parse.RepoNameToNamedReference(query.CacheFrom) @@ -644,6 +653,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Excludes: excludes, ForceRmIntermediateCtrs: query.ForceRm, From: fromImage, + IDMappingOptions: &idMappingOptions, IgnoreUnrecognizedInstructions: query.Ignore, Isolation: isolation, Jobs: &jobs, diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 2615bc516..8348ac54b 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -88,6 +88,13 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } params.Set("additionalbuildcontexts", string(additionalBuildContextMap)) } + if options.IDMappingOptions != nil { + idmappingsOptions, err := jsoniter.Marshal(options.IDMappingOptions) + if err != nil { + return nil, err + } + params.Set("idmappingoptions", string(idmappingsOptions)) + } if buildArgs := options.Args; len(buildArgs) > 0 { bArgs, err := jsoniter.MarshalToString(buildArgs) if err != nil { diff --git a/test/e2e/build/Containerfile.userns-auto b/test/e2e/build/Containerfile.userns-auto new file mode 100644 index 000000000..921610982 --- /dev/null +++ b/test/e2e/build/Containerfile.userns-auto @@ -0,0 +1,2 @@ +FROM alpine +RUN cat /proc/self/uid_map diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go index f247b2dac..62e512d3a 100644 --- a/test/e2e/run_userns_test.go +++ b/test/e2e/run_userns_test.go @@ -8,6 +8,7 @@ import ( "strings" . "github.com/containers/podman/v4/test/utils" + "github.com/containers/storage" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" @@ -42,6 +43,33 @@ var _ = Describe("Podman UserNS support", func() { }) + // Note: Lot of tests for build with --userns=auto are already there in buildah + // but they are skipped in podman CI because bud tests are executed in rootfull + // environment ( where mappings for the `containers` user is not present in /etc/subuid ) + // causing them to skip hence this is a redundant test for sanity to make sure + // we don't break this feature for podman-remote. + It("podman build with --userns=auto", func() { + u, err := user.Current() + Expect(err).To(BeNil()) + name := u.Name + if name == "root" { + name = "containers" + } + content, err := ioutil.ReadFile("/etc/subuid") + if err != nil { + Skip("cannot read /etc/subuid") + } + if !strings.Contains(string(content), name) { + Skip("cannot find mappings for the current user") + } + session := podmanTest.Podman([]string{"build", "-f", "build/Containerfile.userns-auto", "-t", "test", "--userns=auto"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + // `1024` is the default size or length of the range of user IDs + // that is mapped between the two user namespaces by --userns=auto. + Expect(session.OutputToString()).To(ContainSubstring(fmt.Sprintf("%d", storage.AutoUserNsMinSize))) + }) + It("podman uidmapping and gidmapping", func() { session := podmanTest.Podman([]string{"run", "--uidmap=0:100:5000", "--gidmap=0:200:5000", "alpine", "echo", "hello"}) session.WaitWithDefaultTimeout() @@ -157,6 +185,8 @@ var _ = Describe("Podman UserNS support", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) l := session.OutputToString() + // `1024` is the default size or length of the range of user IDs + // that is mapped between the two user namespaces by --userns=auto. Expect(l).To(ContainSubstring("1024")) m[l] = l } -- cgit v1.2.3-54-g00ecf