From 18e9ae59ca0800789ea6cfef3a27516801a7e1a5 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Thu, 11 Nov 2021 15:35:11 +0100 Subject: Fix network mode in play kube We need to use the config network mode when no network mode was set. To do so we have to keep the nsmode empty, MakeContainer() will use the correct network mode from the config when needed. Fixes #12248 Signed-off-by: Paul Holzinger Signed-off-by: Matthew Heon --- pkg/specgen/generate/pod_create.go | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'pkg') diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go index e523aef42..c33c366bd 100644 --- a/pkg/specgen/generate/pod_create.go +++ b/pkg/specgen/generate/pod_create.go @@ -8,7 +8,6 @@ import ( "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/domain/entities" - "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/specgen" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -115,15 +114,6 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) { logrus.Debugf("No networking because the infra container is missing") break } - if rootless.IsRootless() { - logrus.Debugf("Pod will use slirp4netns") - if p.InfraContainerSpec.NetNS.NSMode != "host" { - p.InfraContainerSpec.NetworkOptions = p.NetworkOptions - p.InfraContainerSpec.NetNS.NSMode = specgen.NamespaceMode("slirp4netns") - } - } else { - logrus.Debugf("Pod using bridge network mode") - } case specgen.Bridge: p.InfraContainerSpec.NetNS.NSMode = specgen.Bridge logrus.Debugf("Pod using bridge network mode") @@ -157,7 +147,6 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) { return nil, errors.Errorf("pods presently do not support network mode %s", p.NetNS.NSMode) } - libpod.WithPodCgroups() if len(p.InfraCommand) > 0 { p.InfraContainerSpec.Entrypoint = p.InfraCommand } -- cgit v1.2.3-54-g00ecf From 4ed07fb67d11a875f10173a2a20e9149157b77ce Mon Sep 17 00:00:00 2001 From: Michael Scherer Date: Fri, 12 Nov 2021 12:56:57 +0100 Subject: Always create working directory when using compat API Docker/Moby always create the working directory, and some tools rely on that behavior (example, woodpecker/drone). Fixes #11842 Signed-off-by: Michael Scherer Signed-off-by: Matthew Heon --- pkg/api/handlers/compat/containers_create.go | 2 ++ pkg/specgen/generate/container_create.go | 3 +++ pkg/specgen/specgen.go | 4 ++++ test/python/docker/compat/test_containers.py | 14 ++++++++++++++ 4 files changed, 23 insertions(+) (limited to 'pkg') diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go index 94d20a04a..1e175d664 100644 --- a/pkg/api/handlers/compat/containers_create.go +++ b/pkg/api/handlers/compat/containers_create.go @@ -86,6 +86,8 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "fill out specgen")) return } + // moby always create the working directory + sg.CreateWorkingDir = true ic := abi.ContainerEngine{Libpod: runtime} report, err := ic.ContainerCreate(r.Context(), sg) diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index f82b2a3c6..fc66145df 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -333,6 +333,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. if s.WorkDir == "" { s.WorkDir = "/" } + if s.CreateWorkingDir { + options = append(options, libpod.WithCreateWorkingDir()) + } if s.StopSignal != nil { options = append(options, libpod.WithStopSignal(*s.StopSignal)) } diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index 0c30c498a..50ef3f197 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -264,6 +264,10 @@ type ContainerStorageConfig struct { // If unset, the default, /, will be used. // Optional. WorkDir string `json:"work_dir,omitempty"` + // Create the working directory if it doesn't exist. + // If unset, it doesn't create it. + // Optional. + CreateWorkingDir bool `json:"create_working_dir,omitempty"` // RootfsPropagation is the rootfs propagation mode for the container. // If not set, the default of rslave will be used. // Optional. diff --git a/test/python/docker/compat/test_containers.py b/test/python/docker/compat/test_containers.py index 1ad1e7f15..e6f7d992d 100644 --- a/test/python/docker/compat/test_containers.py +++ b/test/python/docker/compat/test_containers.py @@ -251,3 +251,17 @@ class TestContainers(unittest.TestCase): ctr.start() ret, out = ctr.exec_run(["stat", "-c", "%u:%g", "/workspace"]) self.assertEqual(out.rstrip(), b'1042:1043', "UID/GID set in dockerfile") + + + def test_non_existant_workdir(self): + dockerfile = (B'FROM quay.io/libpod/alpine:latest\n' + B'USER root\n' + B'WORKDIR /workspace/scratch\n' + B'RUN touch test') + img: Image + img, out = self.client.images.build(fileobj=io.BytesIO(dockerfile)) + ctr: Container = self.client.containers.create(image=img.id, detach=True, command="top", + volumes=["test_non_existant_workdir:/workspace"]) + ctr.start() + ret, out = ctr.exec_run(["stat", "/workspace/scratch/test"]) + self.assertEqual(ret, 0, "Working directory created if it doesn't exist") -- cgit v1.2.3-54-g00ecf From db6b9131ef1a14cd19cdd52425fb60d90862f05e Mon Sep 17 00:00:00 2001 From: Aditya Rajan Date: Mon, 15 Nov 2021 14:39:26 +0530 Subject: secret: honor custom target for secrets with run Honor custom `target` if specified while running or creating containers with secret `type=mount`. Example: `podman run -it --secret token,type=mount,target=TOKEN ubi8/ubi:latest bash` Signed-off-by: Aditya Rajan --- libpod/container.go | 2 ++ libpod/container_internal_linux.go | 11 +++++++- pkg/specgen/generate/container_create.go | 1 + pkg/specgen/specgen.go | 1 + pkg/specgenutil/specgen.go | 5 ++-- test/e2e/run_test.go | 48 +++++++++++++++++++++++++++++--- 6 files changed, 60 insertions(+), 8 deletions(-) (limited to 'pkg') diff --git a/libpod/container.go b/libpod/container.go index a4bbb5dd0..8bbe02b58 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -253,6 +253,8 @@ type ContainerSecret struct { GID uint32 // Mode is the mode of the secret file Mode uint32 + // Secret target inside container + Target string } // ContainerNetworkDescriptions describes the relationship between the CNI diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 89869e2f5..1c85339c7 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -1777,8 +1777,17 @@ rootless=%d return errors.Wrapf(err, "error creating secrets mount") } for _, secret := range c.Secrets() { + secretFileName := secret.Name + base := "/run/secrets" + if secret.Target != "" { + secretFileName = secret.Target + //If absolute path for target given remove base. + if filepath.IsAbs(secretFileName) { + base = "" + } + } src := filepath.Join(c.config.SecretsPath, secret.Name) - dest := filepath.Join("/run/secrets", secret.Name) + dest := filepath.Join(base, secretFileName) c.state.BindMounts[dest] = src } } diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index fc66145df..4003567e9 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -429,6 +429,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. UID: s.UID, GID: s.GID, Mode: s.Mode, + Target: s.Target, }) } options = append(options, libpod.WithSecrets(secrs)) diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index 50ef3f197..70518c073 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -513,6 +513,7 @@ type SpecGenerator struct { type Secret struct { Source string + Target string UID uint32 GID uint32 Mode uint32 diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 8007e5d8e..eba173a81 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -861,6 +861,7 @@ func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error) if len(split) == 1 { mountSecret := specgen.Secret{ Source: val, + Target: target, UID: uid, GID: gid, Mode: mode, @@ -926,11 +927,9 @@ func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error) return nil, nil, errors.Wrapf(secretParseError, "no source found %s", val) } if secretType == "mount" { - if target != "" { - return nil, nil, errors.Wrapf(secretParseError, "target option is invalid for mounted secrets") - } mountSecret := specgen.Secret{ Source: source, + Target: target, UID: uid, GID: gid, Mode: mode, diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index a5a0aad8b..e21b1dcf3 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1670,6 +1670,50 @@ WORKDIR /madethis`, BB) }) + It("podman run --secret source=mysecret,type=mount with target", func() { + secretsString := "somesecretdata" + secretFilePath := filepath.Join(podmanTest.TempDir, "secret") + err := ioutil.WriteFile(secretFilePath, []byte(secretsString), 0755) + Expect(err).To(BeNil()) + + session := podmanTest.Podman([]string{"secret", "create", "mysecret_target", secretFilePath}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"run", "--secret", "source=mysecret_target,type=mount,target=hello", "--name", "secr_target", ALPINE, "cat", "/run/secrets/hello"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(Equal(secretsString)) + + session = podmanTest.Podman([]string{"inspect", "secr_target", "--format", " {{(index .Config.Secrets 0).Name}}"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("mysecret_target")) + + }) + + It("podman run --secret source=mysecret,type=mount with target at /tmp", func() { + secretsString := "somesecretdata" + secretFilePath := filepath.Join(podmanTest.TempDir, "secret") + err := ioutil.WriteFile(secretFilePath, []byte(secretsString), 0755) + Expect(err).To(BeNil()) + + session := podmanTest.Podman([]string{"secret", "create", "mysecret_target2", secretFilePath}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"run", "--secret", "source=mysecret_target2,type=mount,target=/tmp/hello", "--name", "secr_target2", ALPINE, "cat", "/tmp/hello"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(Equal(secretsString)) + + session = podmanTest.Podman([]string{"inspect", "secr_target2", "--format", " {{(index .Config.Secrets 0).Name}}"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("mysecret_target2")) + + }) + It("podman run --secret source=mysecret,type=env", func() { secretsString := "somesecretdata" secretFilePath := filepath.Join(podmanTest.TempDir, "secret") @@ -1695,10 +1739,6 @@ WORKDIR /madethis`, BB) session := podmanTest.Podman([]string{"secret", "create", "mysecret", secretFilePath}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - // target with mount type should fail - session = podmanTest.Podman([]string{"run", "--secret", "source=mysecret,type=mount,target=anotherplace", "--name", "secr", ALPINE, "cat", "/run/secrets/mysecret"}) - session.WaitWithDefaultTimeout() - Expect(session).To(ExitWithError()) session = podmanTest.Podman([]string{"run", "--secret", "source=mysecret,type=env,target=anotherplace", "--name", "secr", ALPINE, "printenv", "anotherplace"}) session.WaitWithDefaultTimeout() -- cgit v1.2.3-54-g00ecf From 8e6ee43bb29b5e0ec7d467b45278e3cc3b4e242d Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 17 Nov 2021 10:26:26 +0100 Subject: rootless: use auto cleanup functions simplify code using auto cleanup functions [NO NEW TESTS NEEDED] it is a refactoring of existing code Signed-off-by: Giuseppe Scrivano --- pkg/rootless/rootless_linux.c | 203 ++++++++++++++++++++---------------------- 1 file changed, 97 insertions(+), 106 deletions(-) (limited to 'pkg') diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 6ce4b1e29..b60aea855 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -19,6 +19,33 @@ #include #include +#define cleanup_free __attribute__ ((cleanup (cleanup_freep))) +#define cleanup_close __attribute__ ((cleanup (cleanup_closep))) +#define cleanup_dir __attribute__ ((cleanup (cleanup_dirp))) + +static inline void +cleanup_freep (void *p) +{ + void **pp = (void **) p; + free (*pp); +} + +static inline void +cleanup_closep (void *p) +{ + int *pp = p; + if (*pp >= 0) + TEMP_FAILURE_RETRY (close (*pp)); +} + +static inline void +cleanup_dirp (DIR **p) +{ + DIR *dir = *p; + if (dir) + closedir (dir); +} + int rename_noreplace (int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { int ret; @@ -114,8 +141,8 @@ do_pause () static char ** get_cmd_line_args () { - int fd; - char *buffer; + cleanup_free char *buffer = NULL; + cleanup_close int fd = -1; size_t allocated; size_t used = 0; int ret; @@ -134,10 +161,7 @@ get_cmd_line_args () { ret = TEMP_FAILURE_RETRY (read (fd, buffer + used, allocated - used)); if (ret < 0) - { - free (buffer); - return NULL; - } + return NULL; if (ret == 0) break; @@ -148,30 +172,21 @@ get_cmd_line_args () allocated += 512; char *tmp = realloc (buffer, allocated); if (tmp == NULL) - { - free (buffer); - return NULL; - } + return NULL; buffer = tmp; } } - close (fd); for (i = 0; i < used; i++) if (buffer[i] == '\0') argc++; if (argc == 0) - { - free (buffer); - return NULL; - } + return NULL; argv = malloc (sizeof (char *) * (argc + 1)); if (argv == NULL) - { - free (buffer); - return NULL; - } + return NULL; + argc = 0; argv[argc++] = buffer; @@ -181,15 +196,19 @@ get_cmd_line_args () argv[argc] = NULL; + /* Move ownership. */ + buffer = NULL; + return argv; } static bool can_use_shortcut () { - int argc; - char **argv; + cleanup_free char **argv = NULL; + cleanup_free char *argv0 = NULL; bool ret = true; + int argc; #ifdef DISABLE_JOIN_SHORTCUT return false; @@ -199,12 +218,10 @@ can_use_shortcut () if (argv == NULL) return false; + argv0 = argv[0]; + if (strstr (argv[0], "podman") == NULL) - { - free (argv[0]); - free (argv); - return false; - } + return false; for (argc = 0; argv[argc]; argc++) { @@ -229,8 +246,6 @@ can_use_shortcut () } } - free (argv[0]); - free (argv); return ret; } @@ -250,8 +265,7 @@ static void __attribute__((constructor)) init() const char *listen_pid; const char *listen_fds; const char *listen_fdnames; - - DIR *d; + cleanup_dir DIR *d = NULL; pause = getenv ("_PODMAN_PAUSE"); if (pause && pause[0]) @@ -299,7 +313,6 @@ static void __attribute__((constructor)) init() FD_SET (fd % FD_SETSIZE, &(open_files_set[fd / FD_SETSIZE])); } - closedir (d); } listen_pid = getenv("LISTEN_PID"); @@ -327,19 +340,22 @@ static void __attribute__((constructor)) init() xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); if (geteuid () != 0 && xdg_runtime_dir && xdg_runtime_dir[0] && can_use_shortcut ()) { - int r; - int fd; + cleanup_free char *cwd = NULL; + cleanup_close int userns_fd = -1; + cleanup_close int mntns_fd = -1; + cleanup_close int fd = -1; long pid; char buf[12]; uid_t uid; gid_t gid; char path[PATH_MAX]; const char *const suffix = "/libpod/tmp/pause.pid"; - char *cwd = getcwd (NULL, 0); char uid_fmt[16]; char gid_fmt[16]; size_t len; + int r; + cwd = getcwd (NULL, 0); if (cwd == NULL) { fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); @@ -355,45 +371,40 @@ static void __attribute__((constructor)) init() fd = open (path, O_RDONLY); if (fd < 0) - { - free (cwd); - return; - } + return; r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf) - 1)); - close (fd); + if (r < 0) - { - free (cwd); - return; - } + return; buf[r] = '\0'; pid = strtol (buf, NULL, 10); if (pid == LONG_MAX) - { - free (cwd); - return; - } + return; uid = geteuid (); gid = getegid (); sprintf (path, "/proc/%ld/ns/user", pid); - fd = open (path, O_RDONLY); - if (fd < 0 || setns (fd, 0) < 0) - { - free (cwd); - return; - } - close (fd); + userns_fd = open (path, O_RDONLY); + if (userns_fd < 0) + return; - /* Errors here cannot be ignored as we already joined a ns. */ sprintf (path, "/proc/%ld/ns/mnt", pid); - fd = open (path, O_RDONLY); - if (fd < 0) + mntns_fd = open (path, O_RDONLY); + if (mntns_fd < 0) + return; + + if (setns (userns_fd, 0) < 0) + return; + + /* The user namespace was joined, after this point errors are + not recoverable anymore. */ + + if (setns (mntns_fd, 0) < 0) { - fprintf (stderr, "cannot open %s: %s", path, strerror (errno)); + fprintf (stderr, "cannot join mount namespace for %ld: %s", pid, strerror (errno)); exit (EXIT_FAILURE); } @@ -404,14 +415,6 @@ static void __attribute__((constructor)) init() setenv ("_CONTAINERS_ROOTLESS_UID", uid_fmt, 1); setenv ("_CONTAINERS_ROOTLESS_GID", gid_fmt, 1); - r = setns (fd, 0); - if (r < 0) - { - fprintf (stderr, "cannot join mount namespace for %ld: %s", pid, strerror (errno)); - exit (EXIT_FAILURE); - } - close (fd); - if (syscall_setresgid (0, 0, 0) < 0) { fprintf (stderr, "cannot setresgid: %s\n", strerror (errno)); @@ -430,7 +433,6 @@ static void __attribute__((constructor)) init() _exit (EXIT_FAILURE); } - free (cwd); rootless_uid_init = uid; rootless_gid_init = gid; } @@ -619,15 +621,17 @@ join_namespace_or_die (const char *name, int ns_fd) int reexec_userns_join (int pid_to_join, char *pause_pid_file_path) { + cleanup_close int userns_fd = -1; + cleanup_close int mntns_fd = -1; + cleanup_free char *cwd = NULL; char uid[16]; char gid[16]; - char **argv; + cleanup_free char *argv0 = NULL; + cleanup_free char **argv = NULL; int pid; - int mnt_ns = -1; - int user_ns = -1; - char *cwd = getcwd (NULL, 0); sigset_t sigset, oldsigset; + cwd = getcwd (NULL, 0); if (cwd == NULL) { fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); @@ -644,15 +648,14 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) _exit (EXIT_FAILURE); } - user_ns = open_namespace (pid_to_join, "user"); - if (user_ns < 0) - return user_ns; - mnt_ns = open_namespace (pid_to_join, "mnt"); - if (mnt_ns < 0) - { - close (user_ns); - return mnt_ns; - } + argv0 = argv[0]; + + userns_fd = open_namespace (pid_to_join, "user"); + if (userns_fd < 0) + return userns_fd; + mntns_fd = open_namespace (pid_to_join, "mnt"); + if (mntns_fd < 0) + return mntns_fd; pid = fork (); if (pid < 0) @@ -662,10 +665,6 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) { int f; - /* We passed down these fds, close them. */ - close (user_ns); - close (mnt_ns); - for (f = 3; f <= open_files_max_fd; f++) if (is_fd_inherited (f)) close (f); @@ -721,10 +720,8 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) _exit (EXIT_FAILURE); } - join_namespace_or_die ("user", user_ns); - join_namespace_or_die ("mnt", mnt_ns); - close (user_ns); - close (mnt_ns); + join_namespace_or_die ("user", userns_fd); + join_namespace_or_die ("mnt", mntns_fd); if (syscall_setresgid (0, 0, 0) < 0) { @@ -743,7 +740,6 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) fprintf (stderr, "cannot chdir to %s: %s\n", cwd, strerror (errno)); _exit (EXIT_FAILURE); } - free (cwd); if (pause_pid_file_path && pause_pid_file_path[0] != '\0') { @@ -784,7 +780,7 @@ static int copy_file_to_fd (const char *file_to_read, int outfd) { char buf[512]; - int fd; + cleanup_close int fd = -1; fd = open (file_to_read, O_RDONLY); if (fd < 0) @@ -796,10 +792,7 @@ copy_file_to_fd (const char *file_to_read, int outfd) r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof buf)); if (r < 0) - { - close (fd); - return r; - } + return r; if (r == 0) break; @@ -808,36 +801,33 @@ copy_file_to_fd (const char *file_to_read, int outfd) { w = TEMP_FAILURE_RETRY (write (outfd, &buf[t], r - t)); if (w < 0) - { - close (fd); - return w; - } + return w; t += w; } } - close (fd); return 0; } int reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_read, int outputfd) { + cleanup_free char **argv = NULL; + cleanup_free char *argv0 = NULL; + cleanup_free char *cwd = NULL; + sigset_t sigset, oldsigset; int ret; pid_t pid; char b; - char **argv; char uid[16]; char gid[16]; - char *cwd = getcwd (NULL, 0); - sigset_t sigset, oldsigset; + cwd = getcwd (NULL, 0); if (cwd == NULL) { fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); _exit (EXIT_FAILURE); } - sprintf (uid, "%d", geteuid ()); sprintf (gid, "%d", getegid ()); @@ -898,6 +888,8 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re _exit (EXIT_FAILURE); } + argv0 = argv[0]; + if (do_socket_activation) { char s[32]; @@ -942,7 +934,6 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re TEMP_FAILURE_RETRY (write (ready, "1", 1)); _exit (EXIT_FAILURE); } - free (cwd); if (pause_pid_file_path && pause_pid_file_path[0] != '\0') { @@ -956,8 +947,8 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re ret = TEMP_FAILURE_RETRY (write (ready, "0", 1)); if (ret < 0) { - fprintf (stderr, "cannot write to ready pipe: %s\n", strerror (errno)); - _exit (EXIT_FAILURE); + fprintf (stderr, "cannot write to ready pipe: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); } close (ready); -- cgit v1.2.3-54-g00ecf From a92b71333e1040f8ac5131e4f5fd41fd6fa18b30 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 17 Nov 2021 10:33:32 +0100 Subject: rootless: reuse existing open_namespace function there is already a function for opening a namespace path, reuse it. Signed-off-by: Giuseppe Scrivano --- pkg/rootless/rootless_linux.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'pkg') diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index b60aea855..1dd5ad0a1 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -249,6 +249,22 @@ can_use_shortcut () return ret; } +static int +open_namespace (int pid_to_join, const char *ns_file) +{ + char ns_path[PATH_MAX]; + int ret; + + ret = snprintf (ns_path, PATH_MAX, "/proc/%d/ns/%s", pid_to_join, ns_file); + if (ret == PATH_MAX) + { + fprintf (stderr, "internal error: namespace path too long\n"); + return -1; + } + + return open (ns_path, O_CLOEXEC | O_RDONLY); +} + int is_fd_inherited(int fd) { @@ -386,13 +402,11 @@ static void __attribute__((constructor)) init() uid = geteuid (); gid = getegid (); - sprintf (path, "/proc/%ld/ns/user", pid); - userns_fd = open (path, O_RDONLY); + userns_fd = open_namespace (pid, "user"); if (userns_fd < 0) return; - sprintf (path, "/proc/%ld/ns/mnt", pid); - mntns_fd = open (path, O_RDONLY); + mntns_fd = open_namespace (pid, "mnt"); if (mntns_fd < 0) return; @@ -592,22 +606,6 @@ create_pause_process (const char *pause_pid_file_path, char **argv) } } -static int -open_namespace (int pid_to_join, const char *ns_file) -{ - char ns_path[PATH_MAX]; - int ret; - - ret = snprintf (ns_path, PATH_MAX, "/proc/%d/ns/%s", pid_to_join, ns_file); - if (ret == PATH_MAX) - { - fprintf (stderr, "internal error: namespace path too long\n"); - return -1; - } - - return open (ns_path, O_CLOEXEC | O_RDONLY); -} - static void join_namespace_or_die (const char *name, int ns_fd) { -- cgit v1.2.3-54-g00ecf From b5ded05f98341575b9699197cd8a75840004b340 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 17 Nov 2021 10:55:28 +0100 Subject: rootless: drop strerror(errno) calls *printf functions already support printing the errno string with %m Signed-off-by: Giuseppe Scrivano --- pkg/rootless/rootless_linux.c | 71 ++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 35 deletions(-) (limited to 'pkg') diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 1dd5ad0a1..73da93195 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -346,7 +346,7 @@ static void __attribute__((constructor)) init() if (saved_systemd_listen_pid == NULL || saved_systemd_listen_fds == NULL) { - fprintf (stderr, "save socket listen environments error: %s\n", strerror (errno)); + fprintf (stderr, "save socket listen environments error: %m\n"); _exit (EXIT_FAILURE); } } @@ -374,14 +374,15 @@ static void __attribute__((constructor)) init() cwd = getcwd (NULL, 0); if (cwd == NULL) { - fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); + fprintf (stderr, "error getting current working directory: %m\n"); _exit (EXIT_FAILURE); } len = snprintf (path, PATH_MAX, "%s%s", xdg_runtime_dir, suffix); if (len >= PATH_MAX) { - fprintf (stderr, "invalid value for XDG_RUNTIME_DIR: %s", strerror (ENAMETOOLONG)); + errno = ENAMETOOLONG; + fprintf (stderr, "invalid value for XDG_RUNTIME_DIR: %m"); exit (EXIT_FAILURE); } @@ -418,7 +419,7 @@ static void __attribute__((constructor)) init() if (setns (mntns_fd, 0) < 0) { - fprintf (stderr, "cannot join mount namespace for %ld: %s", pid, strerror (errno)); + fprintf (stderr, "cannot join mount namespace for %ld: %m", pid); exit (EXIT_FAILURE); } @@ -431,19 +432,19 @@ static void __attribute__((constructor)) init() if (syscall_setresgid (0, 0, 0) < 0) { - fprintf (stderr, "cannot setresgid: %s\n", strerror (errno)); + fprintf (stderr, "cannot setresgid: %m\n"); _exit (EXIT_FAILURE); } if (syscall_setresuid (0, 0, 0) < 0) { - fprintf (stderr, "cannot setresuid: %s\n", strerror (errno)); + fprintf (stderr, "cannot setresuid: %m\n"); _exit (EXIT_FAILURE); } if (chdir (cwd) < 0) { - fprintf (stderr, "cannot chdir to %s: %s\n", cwd, strerror (errno)); + fprintf (stderr, "cannot chdir to %s: %m\n", cwd); _exit (EXIT_FAILURE); } @@ -545,7 +546,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv) fd = mkstemp (tmp_file_path); if (fd < 0) { - fprintf (stderr, "error creating temporary file: %s\n", strerror (errno)); + fprintf (stderr, "error creating temporary file: %m\n"); kill (pid, SIGKILL); _exit (EXIT_FAILURE); } @@ -553,7 +554,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv) r = TEMP_FAILURE_RETRY (write (fd, pid_str, strlen (pid_str))); if (r < 0) { - fprintf (stderr, "cannot write to file descriptor: %s\n", strerror (errno)); + fprintf (stderr, "cannot write to file descriptor: %m\n"); kill (pid, SIGKILL); _exit (EXIT_FAILURE); } @@ -571,7 +572,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv) r = TEMP_FAILURE_RETRY (write (p[1], "0", 1)); if (r < 0) { - fprintf (stderr, "cannot write to pipe: %s\n", strerror (errno)); + fprintf (stderr, "cannot write to pipe: %m\n"); _exit (EXIT_FAILURE); } close (p[1]); @@ -632,7 +633,7 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) cwd = getcwd (NULL, 0); if (cwd == NULL) { - fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); + fprintf (stderr, "error getting current working directory: %m\n"); _exit (EXIT_FAILURE); } @@ -642,7 +643,7 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) argv = get_cmd_line_args (); if (argv == NULL) { - fprintf (stderr, "cannot read argv: %s\n", strerror (errno)); + fprintf (stderr, "cannot read argv: %m\n"); _exit (EXIT_FAILURE); } @@ -657,7 +658,7 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) pid = fork (); if (pid < 0) - fprintf (stderr, "cannot fork: %s\n", strerror (errno)); + fprintf (stderr, "cannot fork: %m\n"); if (pid) { @@ -678,22 +679,22 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) if (sigfillset (&sigset) < 0) { - fprintf (stderr, "cannot fill sigset: %s\n", strerror (errno)); + fprintf (stderr, "cannot fill sigset: %m\n"); _exit (EXIT_FAILURE); } if (sigdelset (&sigset, SIGCHLD) < 0) { - fprintf (stderr, "cannot sigdelset(SIGCHLD): %s\n", strerror (errno)); + fprintf (stderr, "cannot sigdelset(SIGCHLD): %m\n"); _exit (EXIT_FAILURE); } if (sigdelset (&sigset, SIGTERM) < 0) { - fprintf (stderr, "cannot sigdelset(SIGTERM): %s\n", strerror (errno)); + fprintf (stderr, "cannot sigdelset(SIGTERM): %m\n"); _exit (EXIT_FAILURE); } if (sigprocmask (SIG_BLOCK, &sigset, &oldsigset) < 0) { - fprintf (stderr, "cannot block signals: %s\n", strerror (errno)); + fprintf (stderr, "cannot block signals: %m\n"); _exit (EXIT_FAILURE); } @@ -714,7 +715,7 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) if (prctl (PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) < 0) { - fprintf (stderr, "cannot prctl(PR_SET_PDEATHSIG): %s\n", strerror (errno)); + fprintf (stderr, "cannot prctl(PR_SET_PDEATHSIG): %m\n"); _exit (EXIT_FAILURE); } @@ -723,19 +724,19 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) if (syscall_setresgid (0, 0, 0) < 0) { - fprintf (stderr, "cannot setresgid: %s\n", strerror (errno)); + fprintf (stderr, "cannot setresgid: %m\n"); _exit (EXIT_FAILURE); } if (syscall_setresuid (0, 0, 0) < 0) { - fprintf (stderr, "cannot setresuid: %s\n", strerror (errno)); + fprintf (stderr, "cannot setresuid: %m\n"); _exit (EXIT_FAILURE); } if (chdir (cwd) < 0) { - fprintf (stderr, "cannot chdir to %s: %s\n", cwd, strerror (errno)); + fprintf (stderr, "cannot chdir to %s: %m\n", cwd); _exit (EXIT_FAILURE); } @@ -746,7 +747,7 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) } if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0) { - fprintf (stderr, "cannot block signals: %s\n", strerror (errno)); + fprintf (stderr, "cannot block signals: %m\n"); _exit (EXIT_FAILURE); } @@ -822,7 +823,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re cwd = getcwd (NULL, 0); if (cwd == NULL) { - fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); + fprintf (stderr, "error getting current working directory: %m\n"); _exit (EXIT_FAILURE); } @@ -832,7 +833,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re pid = syscall_clone (CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, NULL); if (pid < 0) { - fprintf (stderr, "cannot clone: %s\n", strerror (errno)); + fprintf (stderr, "cannot clone: %m\n"); check_proc_sys_userns_file (_max_user_namespaces); check_proc_sys_userns_file (_unprivileged_user_namespaces); } @@ -860,29 +861,29 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re if (sigfillset (&sigset) < 0) { - fprintf (stderr, "cannot fill sigset: %s\n", strerror (errno)); + fprintf (stderr, "cannot fill sigset: %m\n"); _exit (EXIT_FAILURE); } if (sigdelset (&sigset, SIGCHLD) < 0) { - fprintf (stderr, "cannot sigdelset(SIGCHLD): %s\n", strerror (errno)); + fprintf (stderr, "cannot sigdelset(SIGCHLD): %m\n"); _exit (EXIT_FAILURE); } if (sigdelset (&sigset, SIGTERM) < 0) { - fprintf (stderr, "cannot sigdelset(SIGTERM): %s\n", strerror (errno)); + fprintf (stderr, "cannot sigdelset(SIGTERM): %m\n"); _exit (EXIT_FAILURE); } if (sigprocmask (SIG_BLOCK, &sigset, &oldsigset) < 0) { - fprintf (stderr, "cannot block signals: %s\n", strerror (errno)); + fprintf (stderr, "cannot block signals: %m\n"); _exit (EXIT_FAILURE); } argv = get_cmd_line_args (); if (argv == NULL) { - fprintf (stderr, "cannot read argv: %s\n", strerror (errno)); + fprintf (stderr, "cannot read argv: %m\n"); _exit (EXIT_FAILURE); } @@ -906,7 +907,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re ret = TEMP_FAILURE_RETRY (read (ready, &b, 1)); if (ret < 0) { - fprintf (stderr, "cannot read from sync pipe: %s\n", strerror (errno)); + fprintf (stderr, "cannot read from sync pipe: %m\n"); _exit (EXIT_FAILURE); } if (ret != 1 || b != '0') @@ -914,21 +915,21 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re if (syscall_setresgid (0, 0, 0) < 0) { - fprintf (stderr, "cannot setresgid: %s\n", strerror (errno)); + fprintf (stderr, "cannot setresgid: %m\n"); TEMP_FAILURE_RETRY (write (ready, "1", 1)); _exit (EXIT_FAILURE); } if (syscall_setresuid (0, 0, 0) < 0) { - fprintf (stderr, "cannot setresuid: %s\n", strerror (errno)); + fprintf (stderr, "cannot setresuid: %m\n"); TEMP_FAILURE_RETRY (write (ready, "1", 1)); _exit (EXIT_FAILURE); } if (chdir (cwd) < 0) { - fprintf (stderr, "cannot chdir to %s: %s\n", cwd, strerror (errno)); + fprintf (stderr, "cannot chdir to %s: %m\n", cwd); TEMP_FAILURE_RETRY (write (ready, "1", 1)); _exit (EXIT_FAILURE); } @@ -945,14 +946,14 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re ret = TEMP_FAILURE_RETRY (write (ready, "0", 1)); if (ret < 0) { - fprintf (stderr, "cannot write to ready pipe: %s\n", strerror (errno)); + fprintf (stderr, "cannot write to ready pipe: %m\n"); _exit (EXIT_FAILURE); } close (ready); if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0) { - fprintf (stderr, "cannot block signals: %s\n", strerror (errno)); + fprintf (stderr, "cannot block signals: %m\n"); _exit (EXIT_FAILURE); } -- cgit v1.2.3-54-g00ecf From 0282f98b3cabad5ff873dc7c391151854f1501b7 Mon Sep 17 00:00:00 2001 From: etenzy Date: Wed, 17 Nov 2021 15:30:40 +0100 Subject: fix: take absolute path for dd on apple silicon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #12329 [NO NEW TESTS NEEDED] podman machine Signed-off-by: Michael Rödel --- pkg/machine/qemu/options_darwin_arm64.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pkg') diff --git a/pkg/machine/qemu/options_darwin_arm64.go b/pkg/machine/qemu/options_darwin_arm64.go index 43cd3d69d..727a275d2 100644 --- a/pkg/machine/qemu/options_darwin_arm64.go +++ b/pkg/machine/qemu/options_darwin_arm64.go @@ -24,7 +24,7 @@ func (v *MachineVM) addArchOptions() []string { func (v *MachineVM) prepare() error { ovmfDir := getOvmfDir(v.ImagePath, v.Name) - cmd := []string{"dd", "if=/dev/zero", "conv=sync", "bs=1m", "count=64", "of=" + ovmfDir} + cmd := []string{"/bin/dd", "if=/dev/zero", "conv=sync", "bs=1m", "count=64", "of=" + ovmfDir} return exec.Command(cmd[0], cmd[1:]...).Run() } -- cgit v1.2.3-54-g00ecf From 76fd7dbd159491e920689104310c4a104744c42c Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Tue, 16 Nov 2021 16:08:40 +0100 Subject: podman machine start wait for ssh Wait for sshd to be ready before we return from start. This should make podman machine ssh immediately available without any race conditions. Fixes #11532 [NO NEW TESTS NEEDED] I could not reproduce the issue so I am not sure if this fixes it. Signed-off-by: Paul Holzinger --- pkg/machine/ignition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pkg') diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go index ef6c741cd..5c465d37d 100644 --- a/pkg/machine/ignition.go +++ b/pkg/machine/ignition.go @@ -81,7 +81,7 @@ func NewIgnitionFile(ign DynamicIgnition) error { // so a listening host knows it can being interacting with it ready := `[Unit] Requires=dev-virtio\\x2dports-%s.device -After=remove-moby.service +After=remove-moby.service sshd.socket sshd.service OnFailure=emergency.target OnFailureJobMode=isolate [Service] -- cgit v1.2.3-54-g00ecf From 2c7b673c5c22d7b1d153768891983221fc6e0312 Mon Sep 17 00:00:00 2001 From: Michael Scherer Date: Tue, 16 Nov 2021 19:07:23 +0100 Subject: Change error message for compatibility with docker Fix #12315 Signed-off-by: Michael Scherer --- pkg/api/handlers/compat/containers_create.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pkg') diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go index 1e175d664..d5abb6e44 100644 --- a/pkg/api/handlers/compat/containers_create.go +++ b/pkg/api/handlers/compat/containers_create.go @@ -55,7 +55,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { newImage, resolvedName, err := runtime.LibimageRuntime().LookupImage(body.Config.Image, nil) if err != nil { if errors.Cause(err) == storage.ErrImageUnknown { - utils.Error(w, "No such image", http.StatusNotFound, err) + utils.Error(w, "No such image", http.StatusNotFound, errors.Wrap(err, "No such image")) return } -- cgit v1.2.3-54-g00ecf From a10963f2e5c4fe056b527b3632c1c5b6077d7b07 Mon Sep 17 00:00:00 2001 From: Aditya Rajan Date: Mon, 22 Nov 2021 16:35:21 +0530 Subject: compat: add layer caching compatiblity for non podman clients Non-podman clients do not set `layers` while making request. This is supposed to be `true` bydefault but `non-podman-clients i.e Docker` dont know about this field as a result they end up setting this values to `false`. Causing builds to never use cache for layers. Adds compatiblity for `docker SDK`. [NO NEW TESTS NEEDED] Signed-off-by: Aditya Rajan --- pkg/api/handlers/compat/images_build.go | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'pkg') diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 6152f1c02..7bbc4b99c 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -134,6 +134,15 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { return } + // if layers field not set assume its not from a valid podman-client + // could be a docker client, set `layers=true` since that is the default + // expected behviour + if !utils.IsLibpodRequest(r) { + if _, found := r.URL.Query()["layers"]; !found { + query.Layers = true + } + } + // convert addcaps formats var addCaps = []string{} if _, found := r.URL.Query()["addcaps"]; found { -- cgit v1.2.3-54-g00ecf From ca518ecdee6fba52e9e9a464a4915a4caaa3081b Mon Sep 17 00:00:00 2001 From: Aditya Rajan Date: Mon, 22 Nov 2021 21:14:10 +0530 Subject: swagger: add layers to build api docs Add missing `layer` entry to swagger docs for `/build`. Signed-off-by: Aditya Rajan --- pkg/api/server/register_images.go | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'pkg') diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index f66669256..bc7ea72c9 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -1500,6 +1500,13 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // JSON map of key, value pairs to set as labels on the new image // (As of version 1.xx) // - in: query + // name: layers + // type: boolean + // default: true + // description: | + // Cache intermediate layers during build. + // (As of version 1.xx) + // - in: query // name: networkmode // type: string // default: bridge -- cgit v1.2.3-54-g00ecf From 4a7af72ea95bd6ebba19db8d052527c5beb9c0eb Mon Sep 17 00:00:00 2001 From: Urvashi Mohnani Date: Mon, 15 Nov 2021 10:05:42 -0500 Subject: Add note about volume with unprivileged container Add a note to the generated kube yaml if we detect a volume is being mounted. The note lets the user know what needs to be done to avoid permission denied error when trying to access the volume for an unprivileged container. Add the same note to the man pages. NO NEW TESTS NEEDED Signed-off-by: Urvashi Mohnani --- docs/source/markdown/podman-generate-kube.1.md | 6 ++++++ pkg/domain/infra/abi/generate.go | 8 ++++++++ 2 files changed, 14 insertions(+) (limited to 'pkg') diff --git a/docs/source/markdown/podman-generate-kube.1.md b/docs/source/markdown/podman-generate-kube.1.md index a583afcf9..0add97144 100644 --- a/docs/source/markdown/podman-generate-kube.1.md +++ b/docs/source/markdown/podman-generate-kube.1.md @@ -19,6 +19,12 @@ Potential name conflicts between volumes are avoided by using a standard naming Note that if an init container is created with type `once` and the pod has been started, the init container will not show up in the generated kube YAML as `once` type init containers are deleted after they are run. If the pod has only been created and not started, it will be in the generated kube YAML. Init containers created with type `always` will always be generated in the kube YAML as they are never deleted, even after running to completion. +*Note*: When using volumes and generating a Kubernetes YAML for an unprivileged and rootless podman container on an **SELinux enabled system**, one of the following options must be completed: + * Add the "privileged: true" option to the pod spec + * Add `type: spc_t` under the `securityContext` `seLinuxOptions` in the pod spec + * Relabel the volume via the CLI command `chcon -t container_file_t context -R ` +Once completed, the correct permissions will be in place to access the volume when the pod/container is created in a Kubernetes cluster. + Note that the generated Kubernetes YAML file can be used to re-run the deployment via podman-play-kube(1). ## OPTIONS diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index a4d6bcf86..0defa1923 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -124,6 +124,14 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, if err != nil { return nil, err } + if len(po.Spec.Volumes) != 0 { + warning := ` +# NOTE: If you generated this yaml from an unprivileged and rootless podman container on an SELinux +# enabled system, check the podman generate kube man page for steps to follow to ensure that your pod/container +# has the right permissions to access the volumes added. +` + content = append(content, []byte(warning)) + } b, err := generateKubeYAML(libpod.ConvertV1PodToYAMLPod(po)) if err != nil { return nil, err -- cgit v1.2.3-54-g00ecf From 741d98fadea94d4042922cb6edabb468f11a4eb3 Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Sun, 28 Nov 2021 19:02:15 +0100 Subject: fix: error reporting for archive endpoint Returning 500 when copying to read-only destination. Signed-off-by: Matej Vasek --- pkg/api/handlers/compat/containers_archive.go | 4 +++- test/python/docker/compat/test_containers.py | 14 +++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'pkg') diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index cda23a399..54cbe01e9 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -133,8 +133,10 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, return } - w.WriteHeader(http.StatusOK) if err := copyFunc(); err != nil { logrus.Error(err.Error()) + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return } + w.WriteHeader(http.StatusOK) } diff --git a/test/python/docker/compat/test_containers.py b/test/python/docker/compat/test_containers.py index e6f7d992d..d6eacd560 100644 --- a/test/python/docker/compat/test_containers.py +++ b/test/python/docker/compat/test_containers.py @@ -8,6 +8,7 @@ from typing import IO, Optional from docker import DockerClient, errors from docker.models.containers import Container from docker.models.images import Image +from docker.models.volumes import Volume from test.python.docker import Podman from test.python.docker.compat import common, constant @@ -207,9 +208,14 @@ class TestContainers(unittest.TestCase): def test_copy_to_container(self): ctr: Optional[Container] = None + vol: Optional[Volume] = None try: test_file_content = b"Hello World!" - ctr = self.client.containers.create(image="alpine", detach=True, command="top") + vol = self.client.volumes.create("test-volume") + ctr = self.client.containers.create(image="alpine", + detach=True, + command="top", + volumes=["test-volume:/test-volume-read-only:ro"]) ctr.start() buff: IO[bytes] = io.BytesIO() @@ -234,10 +240,16 @@ class TestContainers(unittest.TestCase): ret, out = ctr.exec_run(["cat", "/tmp/a.txt"]) self.assertEqual(ret, 0) self.assertEqual(out.rstrip(), test_file_content, "Content of copied file") + + buff.seek(0) + with self.assertRaises(errors.APIError): + ctr.put_archive("/test-volume-read-only/", buff) finally: if ctr is not None: ctr.stop() ctr.remove() + if vol is not None: + vol.remove(force=True) def test_mount_preexisting_dir(self): dockerfile = (B'FROM quay.io/libpod/alpine:latest\n' -- cgit v1.2.3-54-g00ecf From ab5ca6f759d80cd3725aec1678678f57fd795e71 Mon Sep 17 00:00:00 2001 From: Aditya Rajan Date: Wed, 24 Nov 2021 15:51:07 +0530 Subject: compat: Add compatiblity with Docker/Moby API for scenarios where build fails In order to maintain compatiblity with `moby API` we must the field `errorDetail` which is primary error reporting field with stream. Currently podman is using `error` which is already deprecated by moby. Check: https://github.com/moby/moby/blob/master/pkg/jsonmessage/jsonmessage.go#L147 [NO NEW TESTS NEEDED] We can't test this in podman CI since we dont have a docker client. Signed-off-by: Aditya Rajan --- pkg/api/handlers/compat/images_build.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'pkg') diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 7bbc4b99c..ac5934c13 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -24,6 +24,7 @@ import ( "github.com/containers/podman/v3/pkg/auth" "github.com/containers/podman/v3/pkg/channel" "github.com/containers/storage/pkg/archive" + "github.com/docker/docker/pkg/jsonmessage" "github.com/gorilla/schema" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" @@ -546,8 +547,10 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { for { m := struct { - Stream string `json:"stream,omitempty"` - Error string `json:"error,omitempty"` + Stream string `json:"stream,omitempty"` + Error *jsonmessage.JSONError `json:"errorDetail,omitempty"` + // NOTE: `error` is being deprecated check https://github.com/moby/moby/blob/master/pkg/jsonmessage/jsonmessage.go#L148 + ErrorMessage string `json:"error,omitempty"` // deprecate this slowly }{} select { @@ -570,7 +573,10 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } flush() case e := <-stderr.Chan(): - m.Error = string(e) + m.ErrorMessage = string(e) + m.Error = &jsonmessage.JSONError{ + Message: m.ErrorMessage, + } if err := enc.Encode(m); err != nil { logrus.Warnf("Failed to json encode error %v", err) } -- cgit v1.2.3-54-g00ecf From e1cf9d4c28af64035984b8963f73fb92b29480f3 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Wed, 24 Nov 2021 10:34:16 -0500 Subject: Only open save output file with WRONLY The previous code fails on a MAC when opening /dev/stdout Fixes: https://github.com/containers/podman/issues/12402 [NO NEW TESTS NEEDED] No easy way to test this. Signed-off-by: Daniel J Walsh --- pkg/domain/infra/tunnel/images.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'pkg') diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index ab2a93c75..14dc5b92c 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -264,7 +264,10 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, defer func() { _ = os.Remove(f.Name()) }() } default: - f, err = os.Create(opts.Output) + // This code was added to allow for opening stdout replacing + // os.Create(opts.Output) which was attempting to open the file + // for read/write which fails on Darwin platforms + f, err = os.OpenFile(opts.Output, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) } if err != nil { return err -- cgit v1.2.3-54-g00ecf From 658d133390120105cf673cd7dfe5d3436be29d38 Mon Sep 17 00:00:00 2001 From: Shion Tanaka Date: Sat, 27 Nov 2021 13:34:04 +0900 Subject: Fixed the containerfile not found during remote build. [NO NEW TESTS NEEDED] Signed-off-by: Shion Tanaka --- pkg/bindings/images/build.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'pkg') diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 4c3c83837..63cc508dc 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -345,6 +345,11 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } c = tmpFile.Name() } + cfDir := filepath.Dir(c) + if absDir, err := filepath.EvalSymlinks(cfDir); err == nil { + name := filepath.ToSlash(strings.TrimPrefix(c, cfDir+string(filepath.Separator))) + c = filepath.Join(absDir, name) + } containerfile, err := filepath.Abs(c) if err != nil { logrus.Errorf("cannot find absolute path of %v: %v", c, err) -- cgit v1.2.3-54-g00ecf From d9527638845d6eb756885e858a7c27670b8ca687 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Thu, 2 Dec 2021 13:25:54 +0100 Subject: compat: images/json Do not list manifest lists. Docker doesn't either. Fixes: #12453 Signed-off-by: Valentin Rothberg --- pkg/api/handlers/compat/images.go | 12 +++++++++--- test/apiv2/10-images.at | 7 +++++++ 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'pkg') diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index 0b7ba8bee..5c73cb0bd 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -393,14 +393,20 @@ func GetImages(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed get images")) return } - var summaries = make([]*entities.ImageSummary, len(images)) - for j, img := range images { + + summaries := make([]*entities.ImageSummary, 0, len(images)) + for _, img := range images { + // If the image is a manifest list, extract as much as we can. + if isML, _ := img.IsManifestList(r.Context()); isML { + continue + } + is, err := handlers.ImageToImageSummary(img) if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed transform image summaries")) return } - summaries[j] = is + summaries = append(summaries, is) } utils.WriteResponse(w, http.StatusOK, summaries) } diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at index d3fde9f9d..ec32ffb59 100644 --- a/test/apiv2/10-images.at +++ b/test/apiv2/10-images.at @@ -10,6 +10,13 @@ t GET libpod/images/json 200 \ .[0].Id~[0-9a-f]\\{64\\} iid=$(jq -r '.[0].Id' <<<"$output") +# Create an empty manifest and make sure it is not listed +# in the compat endpoint. +t GET images/json 200 length=1 +podman manifest create foo +t GET images/json 200 length=1 +t GET libpod/images/json 200 length=2 + t GET libpod/images/$iid/exists 204 t GET libpod/images/$PODMAN_TEST_IMAGE_NAME/exists 204 t GET libpod/images/${iid}abcdef/exists 404 \ -- cgit v1.2.3-54-g00ecf From bb1293133d18c95223362e6202e4eee967ab43e4 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Fri, 19 Nov 2021 09:58:26 +0100 Subject: Allow containerPortsToServicePorts to fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an error return to it and affected callers. Should not affect behavior, the function can't currently fail. Signed-off-by: Miloslav Trmač --- libpod/kube.go | 29 ++++++++++++++++++++--------- pkg/domain/infra/abi/generate.go | 12 ++++++++++-- 2 files changed, 30 insertions(+), 11 deletions(-) (limited to 'pkg') diff --git a/libpod/kube.go b/libpod/kube.go index 7afa7be3a..29f01c6c5 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -79,7 +79,10 @@ func (p *Pod) GenerateForKube(ctx context.Context) (*v1.Pod, []v1.ServicePort, e return nil, servicePorts, err } spState := newServicePortState() - servicePorts = spState.containerPortsToServicePorts(ports) + servicePorts, err = spState.containerPortsToServicePorts(ports) + if err != nil { + return nil, servicePorts, err + } hostNetwork = infraContainer.NetworkMode() == string(namespaces.NetworkMode(specgen.Host)) } pod, err := p.podWithContainers(ctx, allContainers, ports, hostNetwork) @@ -242,13 +245,17 @@ func ConvertV1PodToYAMLPod(pod *v1.Pod) *YAMLPod { } // GenerateKubeServiceFromV1Pod creates a v1 service object from a v1 pod object -func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) YAMLService { +func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) (YAMLService, error) { service := YAMLService{} selector := make(map[string]string) selector["app"] = pod.Labels["app"] ports := servicePorts if len(ports) == 0 { - ports = containersToServicePorts(pod.Spec.Containers) + p, err := containersToServicePorts(pod.Spec.Containers) + if err != nil { + return service, err + } + ports = p } serviceSpec := v1.ServiceSpec{ Ports: ports, @@ -262,7 +269,7 @@ func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) YA APIVersion: pod.TypeMeta.APIVersion, } service.TypeMeta = tm - return service + return service, nil } // servicePortState allows calling containerPortsToServicePorts for a single service @@ -280,7 +287,7 @@ func newServicePortState() servicePortState { // containerPortsToServicePorts takes a slice of containerports and generates a // slice of service ports -func (state *servicePortState) containerPortsToServicePorts(containerPorts []v1.ContainerPort) []v1.ServicePort { +func (state *servicePortState) containerPortsToServicePorts(containerPorts []v1.ContainerPort) ([]v1.ServicePort, error) { sps := make([]v1.ServicePort, 0, len(containerPorts)) for _, cp := range containerPorts { // Legal nodeport range is 30000-32767 @@ -294,18 +301,22 @@ func (state *servicePortState) containerPortsToServicePorts(containerPorts []v1. } sps = append(sps, servicePort) } - return sps + return sps, nil } // containersToServicePorts takes a slice of v1.Containers and generates an // inclusive list of serviceports to expose -func containersToServicePorts(containers []v1.Container) []v1.ServicePort { +func containersToServicePorts(containers []v1.Container) ([]v1.ServicePort, error) { state := newServicePortState() sps := make([]v1.ServicePort, 0, len(containers)) for _, ctr := range containers { - sps = append(sps, state.containerPortsToServicePorts(ctr.Ports)...) + ports, err := state.containerPortsToServicePorts(ctr.Ports) + if err != nil { + return nil, err + } + sps = append(sps, ports...) } - return sps + return sps, nil } func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, ports []v1.ContainerPort, hostNetwork bool) (*v1.Pod, error) { diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index 0defa1923..68bb351bf 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -139,7 +139,11 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, podContent = append(podContent, b) if options.Service { - b, err := generateKubeYAML(libpod.GenerateKubeServiceFromV1Pod(po, []k8sAPI.ServicePort{})) + svc, err := libpod.GenerateKubeServiceFromV1Pod(po, []k8sAPI.ServicePort{}) + if err != nil { + return nil, err + } + b, err := generateKubeYAML(svc) if err != nil { return nil, err } @@ -177,7 +181,11 @@ func getKubePods(ctx context.Context, pods []*libpod.Pod, getService bool) ([][] pos = append(pos, b) if getService { - b, err := generateKubeYAML(libpod.GenerateKubeServiceFromV1Pod(po, sp)) + svc, err := libpod.GenerateKubeServiceFromV1Pod(po, sp) + if err != nil { + return nil, nil, err + } + b, err := generateKubeYAML(svc) if err != nil { return nil, nil, err } -- cgit v1.2.3-54-g00ecf