diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container_exec.go | 2 | ||||
-rw-r--r-- | libpod/container_internal.go | 10 | ||||
-rw-r--r-- | libpod/define/errors.go | 4 | ||||
-rw-r--r-- | libpod/define/fileinfo.go | 2 | ||||
-rw-r--r-- | libpod/image/image.go | 3 | ||||
-rw-r--r-- | libpod/image/utils.go | 2 | ||||
-rw-r--r-- | libpod/oci.go | 4 | ||||
-rw-r--r-- | libpod/oci_conmon_exec_linux.go | 13 | ||||
-rw-r--r-- | libpod/oci_conmon_linux.go | 13 | ||||
-rw-r--r-- | libpod/oci_missing.go | 5 | ||||
-rw-r--r-- | libpod/runtime.go | 125 | ||||
-rw-r--r-- | libpod/runtime_img.go | 3 | ||||
-rw-r--r-- | libpod/shutdown/handler.go | 2 |
13 files changed, 144 insertions, 44 deletions
diff --git a/libpod/container_exec.go b/libpod/container_exec.go index 8d8ed14aa..c359f1e5d 100644 --- a/libpod/container_exec.go +++ b/libpod/container_exec.go @@ -773,7 +773,7 @@ func (c *Container) cleanupExecBundle(sessionID string) error { return err } - return c.ociRuntime.ExecContainerCleanup(c, sessionID) + return nil } // the path to a containers exec session bundle diff --git a/libpod/container_internal.go b/libpod/container_internal.go index a53027ab2..80c00a622 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -685,7 +685,11 @@ func (c *Container) removeIPv4Allocations() error { // This is necessary for restarting containers func (c *Container) removeConmonFiles() error { // Files are allowed to not exist, so ignore ENOENT - attachFile := filepath.Join(c.bundlePath(), "attach") + attachFile, err := c.AttachSocketPath() + if err != nil { + return errors.Wrapf(err, "failed to get attach socket path for container %s", c.ID()) + } + if err := os.Remove(attachFile); err != nil && !os.IsNotExist(err) { return errors.Wrapf(err, "error removing container %s attach file", c.ID()) } @@ -1309,7 +1313,7 @@ func (c *Container) stop(timeout uint) error { } // We have to check stopErr *after* we lock again - otherwise, we have a - // change of panicing on a double-unlock. Ref: GH Issue 9615 + // change of panicking on a double-unlock. Ref: GH Issue 9615 if stopErr != nil { return stopErr } @@ -1672,7 +1676,7 @@ func (c *Container) chownVolume(volumeName string) error { // TODO: For now, I've disabled chowning volumes owned by non-Podman // drivers. This may be safe, but it's really going to be a case-by-case - // thing, I think - safest to leave disabled now and reenable later if + // thing, I think - safest to leave disabled now and re-enable later if // there is a demand. if vol.state.NeedsChown && !vol.UsesVolumeDriver() { vol.state.NeedsChown = false diff --git a/libpod/define/errors.go b/libpod/define/errors.go index e19ac6a27..8d943099b 100644 --- a/libpod/define/errors.go +++ b/libpod/define/errors.go @@ -206,4 +206,8 @@ var ( // ErrCanceled indicates that an operation has been cancelled by a user. // Useful for potentially long running tasks. ErrCanceled = errors.New("cancelled by user") + + // ErrConmonVersionFormat is used when the expected versio-format of conmon + // has changed. + ErrConmonVersionFormat = "conmon version changed format" ) diff --git a/libpod/define/fileinfo.go b/libpod/define/fileinfo.go index 2c7b6fe99..eec99e300 100644 --- a/libpod/define/fileinfo.go +++ b/libpod/define/fileinfo.go @@ -5,7 +5,7 @@ import ( "time" ) -// FileInfo describes the attributes of a file or diretory. +// FileInfo describes the attributes of a file or directory. type FileInfo struct { Name string `json:"name"` Size int64 `json:"size"` diff --git a/libpod/image/image.go b/libpod/image/image.go index 12dc22360..3c9fb3a37 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -617,7 +617,8 @@ func (i *Image) TopLayer() string { func (i *Image) Remove(ctx context.Context, force bool) error { parent, err := i.GetParent(ctx) if err != nil { - return err + logrus.Warnf("error determining parent of image: %v, ignoring the error", err) + parent = nil } if _, err := i.imageruntime.store.DeleteImage(i.ID(), true); err != nil { return err diff --git a/libpod/image/utils.go b/libpod/image/utils.go index 0b4264112..dfe35c017 100644 --- a/libpod/image/utils.go +++ b/libpod/image/utils.go @@ -50,7 +50,7 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er // If more then one candidate and the candidates all have same name // and only one is read/write return it. - // Othewise return error with the list of candidates + // Otherwise return error with the list of candidates if len(candidates) > 1 { var ( rwImage *Image diff --git a/libpod/oci.go b/libpod/oci.go index f2053f1b5..1f2c7dd71 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -94,10 +94,6 @@ type OCIRuntime interface { // ExecUpdateStatus checks the status of a given exec session. // Returns true if the session is still running, or false if it exited. ExecUpdateStatus(ctr *Container, sessionID string) (bool, error) - // ExecContainerCleanup cleans up after an exec session exits. - // It removes any files left by the exec session that are no longer - // needed, including the attach socket. - ExecContainerCleanup(ctr *Container, sessionID string) error // CheckpointContainer checkpoints the given container. // Some OCI runtimes may not support this - if SupportsCheckpoint() diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go index b43316951..76338b86c 100644 --- a/libpod/oci_conmon_exec_linux.go +++ b/libpod/oci_conmon_exec_linux.go @@ -284,17 +284,6 @@ func (r *ConmonOCIRuntime) ExecUpdateStatus(ctr *Container, sessionID string) (b return true, nil } -// ExecContainerCleanup cleans up files created when a command is run via -// ExecContainer. This includes the attach socket for the exec session. -func (r *ConmonOCIRuntime) ExecContainerCleanup(ctr *Container, sessionID string) error { - // Clean up the sockets dir. Issue #3962 - // Also ignore if it doesn't exist for some reason; hence the conditional return below - if err := os.RemoveAll(filepath.Join(r.socketsDir, sessionID)); err != nil && !os.IsNotExist(err) { - return err - } - return nil -} - // ExecAttachSocketPath is the path to a container's exec session attach socket. func (r *ConmonOCIRuntime) ExecAttachSocketPath(ctr *Container, sessionID string) (string, error) { // We don't even use container, so don't validity check it @@ -302,7 +291,7 @@ func (r *ConmonOCIRuntime) ExecAttachSocketPath(ctr *Container, sessionID string return "", errors.Wrapf(define.ErrInvalidArg, "must provide a valid session ID to get attach socket path") } - return filepath.Join(r.socketsDir, sessionID, "attach"), nil + return filepath.Join(ctr.execBundlePath(sessionID), "attach"), nil } // This contains pipes used by the exec API. diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index dbe91c232..c1acec977 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -59,7 +59,6 @@ type ConmonOCIRuntime struct { conmonEnv []string tmpDir string exitsDir string - socketsDir string logSizeMax int64 noPivot bool reservePorts bool @@ -149,7 +148,6 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime } runtime.exitsDir = filepath.Join(runtime.tmpDir, "exits") - runtime.socketsDir = filepath.Join(runtime.tmpDir, "socket") // Create the exit files and attach sockets directories if err := os.MkdirAll(runtime.exitsDir, 0750); err != nil { @@ -158,13 +156,6 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime return nil, errors.Wrapf(err, "error creating OCI runtime exit files directory") } } - if err := os.MkdirAll(runtime.socketsDir, 0750); err != nil { - // The directory is allowed to exist - if !os.IsExist(err) { - return nil, errors.Wrap(err, "error creating OCI runtime attach sockets directory") - } - } - return runtime, nil } @@ -865,7 +856,7 @@ func (r *ConmonOCIRuntime) AttachSocketPath(ctr *Container) (string, error) { return "", errors.Wrapf(define.ErrInvalidArg, "must provide a valid container to get attach socket path") } - return filepath.Join(r.socketsDir, ctr.ID(), "attach"), nil + return filepath.Join(ctr.bundlePath(), "attach"), nil } // ExitFilePath is the path to a container's exit file. @@ -1240,7 +1231,7 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p "-p", pidPath, "-n", ctr.Name(), "--exit-dir", exitDir, - "--socket-dir-path", r.socketsDir, + "--full-attach", } if len(r.runtimeFlags) > 0 { rFlags := []string{} diff --git a/libpod/oci_missing.go b/libpod/oci_missing.go index eb8cdebad..10526f368 100644 --- a/libpod/oci_missing.go +++ b/libpod/oci_missing.go @@ -151,11 +151,6 @@ func (r *MissingRuntime) ExecUpdateStatus(ctr *Container, sessionID string) (boo return false, r.printError() } -// ExecContainerCleanup is not available as the runtime is missing -func (r *MissingRuntime) ExecContainerCleanup(ctr *Container, sessionID string) error { - return r.printError() -} - // CheckpointContainer is not available as the runtime is missing func (r *MissingRuntime) CheckpointContainer(ctr *Container, options ContainerCheckpointOptions) error { return r.printError() diff --git a/libpod/runtime.go b/libpod/runtime.go index 98ca2d5a4..3518ed25a 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -2,10 +2,14 @@ package libpod import ( "bufio" + "bytes" "context" "fmt" "os" + "os/exec" "path/filepath" + "regexp" + "strconv" "strings" "sync" "syscall" @@ -25,6 +29,7 @@ import ( "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/util" "github.com/containers/storage" + "github.com/containers/storage/pkg/unshare" "github.com/cri-o/ocicni/pkg/ocicni" "github.com/docker/docker/pkg/namesgenerator" spec "github.com/opencontainers/runtime-spec/specs-go" @@ -32,6 +37,17 @@ import ( "github.com/sirupsen/logrus" ) +const ( + // conmonMinMajorVersion is the major version required for conmon. + conmonMinMajorVersion = 2 + + // conmonMinMinorVersion is the minor version required for conmon. + conmonMinMinorVersion = 0 + + // conmonMinPatchVersion is the sub-minor version required for conmon. + conmonMinPatchVersion = 24 +) + // A RuntimeOption is a functional option which alters the Runtime created by // NewRuntime type RuntimeOption func(*Runtime) error @@ -260,7 +276,7 @@ func getLockManager(runtime *Runtime) (lock.Manager, error) { // Sets up containers/storage, state store, OCI runtime func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { // Find a working conmon binary - cPath, err := runtime.config.FindConmon() + cPath, err := findConmon(runtime.config.Engine.ConmonPath) if err != nil { return err } @@ -323,9 +339,16 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { } logrus.Debugf("Set libpod namespace to %q", runtime.config.Engine.Namespace) + hasCapSysAdmin, err := unshare.HasCapSysAdmin() + if err != nil { + return err + } + + needsUserns := !hasCapSysAdmin + // Set up containers/storage var store storage.Store - if os.Geteuid() != 0 { + if needsUserns { logrus.Debug("Not configuring container store") } else if runtime.noStore { logrus.Debug("No store required. Not opening container store.") @@ -465,7 +488,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { // If we need to refresh, then it is safe to assume there are // no containers running. Create immediately a namespace, as // we will need to access the storage. - if os.Geteuid() != 0 { + if needsUserns { aliveLock.Unlock() // Unlock to avoid deadlock as BecomeRootInUserNS will reexec. pausePid, err := util.GetRootlessPauseProcessPidPathGivenDir(runtime.config.Engine.TmpDir) if err != nil { @@ -532,6 +555,102 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { return nil } +// findConmon iterates over conmonPaths and returns the path +// to the first conmon binary with a new enough version. If none is found, +// we try to do a path lookup of "conmon". +func findConmon(conmonPaths []string) (string, error) { + foundOutdatedConmon := false + for _, path := range conmonPaths { + stat, err := os.Stat(path) + if err != nil { + continue + } + if stat.IsDir() { + continue + } + if err := probeConmon(path); err != nil { + logrus.Warnf("Conmon at %s invalid: %v", path, err) + foundOutdatedConmon = true + continue + } + logrus.Debugf("Using conmon: %q", path) + return path, nil + } + + // Search the $PATH as last fallback + if path, err := exec.LookPath("conmon"); err == nil { + if err := probeConmon(path); err != nil { + logrus.Warnf("Conmon at %s is invalid: %v", path, err) + foundOutdatedConmon = true + } else { + logrus.Debugf("Using conmon from $PATH: %q", path) + return path, nil + } + } + + if foundOutdatedConmon { + return "", errors.Wrapf(define.ErrConmonOutdated, + "please update to v%d.%d.%d or later", + conmonMinMajorVersion, conmonMinMinorVersion, conmonMinPatchVersion) + } + + return "", errors.Wrapf(define.ErrInvalidArg, + "could not find a working conmon binary (configured options: %v)", + conmonPaths) +} + +// probeConmon calls conmon --version and verifies it is a new enough version for +// the runtime expectations the container engine currently has. +func probeConmon(conmonBinary string) error { + cmd := exec.Command(conmonBinary, "--version") + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return err + } + r := regexp.MustCompile(`^conmon version (?P<Major>\d+).(?P<Minor>\d+).(?P<Patch>\d+)`) + + matches := r.FindStringSubmatch(out.String()) + if len(matches) != 4 { + return errors.Wrap(err, define.ErrConmonVersionFormat) + } + major, err := strconv.Atoi(matches[1]) + if err != nil { + return errors.Wrap(err, define.ErrConmonVersionFormat) + } + if major < conmonMinMajorVersion { + return define.ErrConmonOutdated + } + if major > conmonMinMajorVersion { + return nil + } + + minor, err := strconv.Atoi(matches[2]) + if err != nil { + return errors.Wrap(err, define.ErrConmonVersionFormat) + } + if minor < conmonMinMinorVersion { + return define.ErrConmonOutdated + } + if minor > conmonMinMinorVersion { + return nil + } + + patch, err := strconv.Atoi(matches[3]) + if err != nil { + return errors.Wrap(err, define.ErrConmonVersionFormat) + } + if patch < conmonMinPatchVersion { + return define.ErrConmonOutdated + } + if patch > conmonMinPatchVersion { + return nil + } + + return nil +} + // TmpDir gets the current Libpod temporary files directory. func (r *Runtime) TmpDir() (string, error) { if !r.valid { diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index 3588467a5..2b101c01f 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -66,7 +66,8 @@ func (r *Runtime) RemoveImage(ctx context.Context, img *image.Image, force bool) hasChildren, err := img.IsParent(ctx) if err != nil { - return nil, err + logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err) + hasChildren = false } if (len(img.Names()) > 1 && !img.InputIsID()) || hasChildren { diff --git a/libpod/shutdown/handler.go b/libpod/shutdown/handler.go index ac1d33910..848b6729a 100644 --- a/libpod/shutdown/handler.go +++ b/libpod/shutdown/handler.go @@ -18,7 +18,7 @@ var ( stopped bool sigChan chan os.Signal cancelChan chan bool - // Syncronize accesses to the map + // Synchronize accesses to the map handlerLock sync.Mutex // Definitions of all on-shutdown handlers handlers map[string]func(os.Signal) error |