diff options
Diffstat (limited to 'libpod/container.go')
-rw-r--r-- | libpod/container.go | 159 |
1 files changed, 54 insertions, 105 deletions
diff --git a/libpod/container.go b/libpod/container.go index c8ab42fc3..2d96b1120 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -11,39 +11,16 @@ import ( "github.com/containernetworking/cni/pkg/types" cnitypes "github.com/containernetworking/cni/pkg/types/current" "github.com/containers/image/manifest" + "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/lock" "github.com/containers/libpod/pkg/namespaces" + "github.com/containers/libpod/pkg/rootless" "github.com/containers/storage" "github.com/cri-o/ocicni/pkg/ocicni" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) -// ContainerStatus represents the current state of a container -type ContainerStatus int - -const ( - // ContainerStateUnknown indicates that the container is in an error - // state where information about it cannot be retrieved - ContainerStateUnknown ContainerStatus = iota - // ContainerStateConfigured indicates that the container has had its - // storage configured but it has not been created in the OCI runtime - ContainerStateConfigured ContainerStatus = iota - // ContainerStateCreated indicates the container has been created in - // the OCI runtime but not started - ContainerStateCreated ContainerStatus = iota - // ContainerStateRunning indicates the container is currently executing - ContainerStateRunning ContainerStatus = iota - // ContainerStateStopped indicates that the container was running but has - // exited - ContainerStateStopped ContainerStatus = iota - // ContainerStatePaused indicates that the container has been paused - ContainerStatePaused ContainerStatus = iota - // ContainerStateExited indicates the the container has stopped and been - // cleaned up - ContainerStateExited ContainerStatus = iota -) - // CgroupfsDefaultCgroupParent is the cgroup parent for CGroupFS in libpod const CgroupfsDefaultCgroupParent = "/libpod_parent" @@ -51,6 +28,10 @@ const CgroupfsDefaultCgroupParent = "/libpod_parent" // manager in libpod const SystemdDefaultCgroupParent = "machine.slice" +// SystemdDefaultRootlessCgroupParent is the cgroup parent for the systemd cgroup +// manager in libpod when running as rootless +const SystemdDefaultRootlessCgroupParent = "user.slice" + // JournaldLogging is the string conmon expects to specify journald logging const JournaldLogging = "journald" @@ -135,7 +116,6 @@ const ( // assume that their callers handled this requirement. Generally speaking, if a // function takes the container lock and accesses any part of state, it should // syncContainer() immediately after locking. -// ffjson: skip type Container struct { config *ContainerConfig @@ -146,9 +126,10 @@ type Container struct { // Functions called on a batched container will not lock or sync batched bool - valid bool - lock lock.Locker - runtime *Runtime + valid bool + lock lock.Locker + runtime *Runtime + ociRuntime *OCIRuntime rootlessSlirpSyncR *os.File rootlessSlirpSyncW *os.File @@ -157,14 +138,16 @@ type Container struct { // being checkpointed. If requestedIP is set it will be used instead // of config.StaticIP. requestedIP net.IP + + // This is true if a container is restored from a checkpoint. + restoreFromCheckpoint bool } // ContainerState contains the current state of the container // It is stored on disk in a tmpfs and recreated on reboot -// easyjson:json type ContainerState struct { // The current state of the running container - State ContainerStatus `json:"state"` + State define.ContainerStatus `json:"state"` // The path to the JSON OCI runtime spec for this container ConfigPath string `json:"configPath,omitempty"` // RunDir is a per-boot directory for container content @@ -188,6 +171,8 @@ type ContainerState struct { OOMKilled bool `json:"oomKilled,omitempty"` // PID is the PID of a running container PID int `json:"pid,omitempty"` + // ConmonPID is the PID of the container's conmon + ConmonPID int `json:"conmonPid,omitempty"` // ExecSessions contains active exec sessions for container // Exec session ID is mapped to PID of exec process ExecSessions map[string]*ExecSession `json:"execSessions,omitempty"` @@ -222,7 +207,6 @@ type ContainerState struct { } // ExecSession contains information on an active exec session -// easyjson:json type ExecSession struct { ID string `json:"id"` Command []string `json:"command"` @@ -232,7 +216,6 @@ type ExecSession struct { // ContainerConfig contains all information that was used to create the // container. It may not be changed once created. // It is stored, read-only, on disk -// easyjson:json type ContainerConfig struct { Spec *spec.Spec `json:"spec"` ID string `json:"id"` @@ -425,51 +408,6 @@ type ContainerNamedVolume struct { Options []string `json:"options,omitempty"` } -// ContainerStatus returns a string representation for users -// of a container state -func (t ContainerStatus) String() string { - switch t { - case ContainerStateUnknown: - return "unknown" - case ContainerStateConfigured: - return "configured" - case ContainerStateCreated: - return "created" - case ContainerStateRunning: - return "running" - case ContainerStateStopped: - return "stopped" - case ContainerStatePaused: - return "paused" - case ContainerStateExited: - return "exited" - } - return "bad state" -} - -// StringToContainerStatus converts a string representation of a containers -// status into an actual container status type -func StringToContainerStatus(status string) (ContainerStatus, error) { - switch status { - case ContainerStateUnknown.String(): - return ContainerStateUnknown, nil - case ContainerStateConfigured.String(): - return ContainerStateConfigured, nil - case ContainerStateCreated.String(): - return ContainerStateCreated, nil - case ContainerStateRunning.String(): - return ContainerStateRunning, nil - case ContainerStateStopped.String(): - return ContainerStateStopped, nil - case ContainerStatePaused.String(): - return ContainerStatePaused, nil - case ContainerStateExited.String(): - return ContainerStateExited, nil - default: - return ContainerStateUnknown, errors.Wrapf(ErrInvalidArg, "unknown container state: %s", status) - } -} - // Config accessors // Unlocked @@ -507,7 +445,7 @@ func (c *Container) specFromState() (*spec.Spec, error) { if err != nil { return nil, errors.Wrapf(err, "error reading container config") } - if err := json.Unmarshal([]byte(content), &returnSpec); err != nil { + if err := json.Unmarshal(content, &returnSpec); err != nil { return nil, errors.Wrapf(err, "error unmarshalling container config") } } else { @@ -701,10 +639,7 @@ func (c *Container) HostsAdd() []string { // trigger some OCI hooks. func (c *Container) UserVolumes() []string { volumes := make([]string, 0, len(c.config.UserVolumes)) - for _, vol := range c.config.UserVolumes { - volumes = append(volumes, vol) - } - + volumes = append(volumes, c.config.UserVolumes...) return volumes } @@ -712,10 +647,7 @@ func (c *Container) UserVolumes() []string { // This is not added to the spec, but is instead used during image commit. func (c *Container) Entrypoint() []string { entrypoint := make([]string, 0, len(c.config.Entrypoint)) - for _, str := range c.config.Entrypoint { - entrypoint = append(entrypoint, str) - } - + entrypoint = append(entrypoint, c.config.Entrypoint...) return entrypoint } @@ -723,10 +655,7 @@ func (c *Container) Entrypoint() []string { // This is not added to the spec, but is instead used during image commit func (c *Container) Command() []string { command := make([]string, 0, len(c.config.Command)) - for _, str := range c.config.Command { - command = append(command, str) - } - + command = append(command, c.config.Command...) return command } @@ -793,7 +722,7 @@ func (c *Container) LogDriver() string { // RuntimeName returns the name of the runtime func (c *Container) RuntimeName() string { - return c.runtime.ociRuntime.name + return c.config.OCIRuntime } // Runtime spec accessors @@ -820,13 +749,13 @@ func (c *Container) WorkingDir() string { // Require locking // State returns the current state of the container -func (c *Container) State() (ContainerStatus, error) { +func (c *Container) State() (define.ContainerStatus, error) { if !c.batched { c.lock.Lock() defer c.lock.Unlock() if err := c.syncContainer(); err != nil { - return ContainerStateUnknown, err + return define.ContainerStateUnknown, err } } return c.state.State, nil @@ -916,7 +845,7 @@ func (c *Container) OOMKilled() (bool, error) { return c.state.OOMKilled, nil } -// PID returns the PID of the container +// PID returns the PID of the container. // If the container is not running, a pid of 0 will be returned. No error will // occur. func (c *Container) PID() (int, error) { @@ -932,6 +861,22 @@ func (c *Container) PID() (int, error) { return c.state.PID, nil } +// ConmonPID Returns the PID of the container's conmon process. +// If the container is not running, a PID of 0 will be returned. No error will +// occur. +func (c *Container) ConmonPID() (int, error) { + if !c.batched { + c.lock.Lock() + defer c.lock.Unlock() + + if err := c.syncContainer(); err != nil { + return -1, err + } + } + + return c.state.ConmonPID, nil +} + // ExecSessions retrieves active exec sessions running in the container func (c *Container) ExecSessions() ([]string, error) { if !c.batched { @@ -965,7 +910,7 @@ func (c *Container) ExecSession(id string) (*ExecSession, error) { session, ok := c.state.ExecSessions[id] if !ok { - return nil, errors.Wrapf(ErrNoSuchCtr, "no exec session with ID %s found in container %s", id, c.ID()) + return nil, errors.Wrapf(define.ErrNoSuchCtr, "no exec session with ID %s found in container %s", id, c.ID()) } returnSession := new(ExecSession) @@ -990,7 +935,7 @@ func (c *Container) IPs() ([]net.IPNet, error) { } if !c.config.CreateNetNS { - return nil, errors.Wrapf(ErrInvalidArg, "container %s network namespace is not managed by libpod", c.ID()) + return nil, errors.Wrapf(define.ErrInvalidArg, "container %s network namespace is not managed by libpod", c.ID()) } ips := make([]net.IPNet, 0) @@ -1018,7 +963,7 @@ func (c *Container) Routes() ([]types.Route, error) { } if !c.config.CreateNetNS { - return nil, errors.Wrapf(ErrInvalidArg, "container %s network namespace is not managed by libpod", c.ID()) + return nil, errors.Wrapf(define.ErrInvalidArg, "container %s network namespace is not managed by libpod", c.ID()) } routes := make([]types.Route, 0) @@ -1085,7 +1030,7 @@ func (c *Container) StoppedByUser() (bool, error) { // NamespacePath returns the path of one of the container's namespaces // If the container is not running, an error will be returned -func (c *Container) NamespacePath(ns LinuxNS) (string, error) { +func (c *Container) NamespacePath(linuxNS LinuxNS) (string, error) { //nolint:interfacer if !c.batched { c.lock.Lock() defer c.lock.Unlock() @@ -1094,15 +1039,15 @@ func (c *Container) NamespacePath(ns LinuxNS) (string, error) { } } - if c.state.State != ContainerStateRunning && c.state.State != ContainerStatePaused { - return "", errors.Wrapf(ErrCtrStopped, "cannot get namespace path unless container %s is running", c.ID()) + if c.state.State != define.ContainerStateRunning && c.state.State != define.ContainerStatePaused { + return "", errors.Wrapf(define.ErrCtrStopped, "cannot get namespace path unless container %s is running", c.ID()) } - if ns == InvalidNS { - return "", errors.Wrapf(ErrInvalidArg, "invalid namespace requested from container %s", c.ID()) + if linuxNS == InvalidNS { + return "", errors.Wrapf(define.ErrInvalidArg, "invalid namespace requested from container %s", c.ID()) } - return fmt.Sprintf("/proc/%d/ns/%s", c.state.PID, ns.String()), nil + return fmt.Sprintf("/proc/%d/ns/%s", c.state.PID, linuxNS.String()), nil } // CGroupPath returns a cgroups "path" for a given container. @@ -1111,9 +1056,13 @@ func (c *Container) CGroupPath() (string, error) { case CgroupfsCgroupsManager: return filepath.Join(c.config.CgroupParent, fmt.Sprintf("libpod-%s", c.ID())), nil case SystemdCgroupsManager: + if rootless.IsRootless() { + uid := rootless.GetRootlessUID() + return filepath.Join(c.config.CgroupParent, fmt.Sprintf("user-%d.slice/user@%d.service/user.slice", uid, uid), createUnitName("libpod", c.ID())), nil + } return filepath.Join(c.config.CgroupParent, createUnitName("libpod", c.ID())), nil default: - return "", errors.Wrapf(ErrInvalidArg, "unsupported CGroup manager %s in use", c.runtime.config.CgroupManager) + return "", errors.Wrapf(define.ErrInvalidArg, "unsupported CGroup manager %s in use", c.runtime.config.CgroupManager) } } |