libct: rm BaseContainer and Container interfaces

The only implementation of these is linuxContainer. It does not make
sense to have an interface with a single implementation, and we do not
foresee other types of containers being added to runc.

Remove BaseContainer and Container interfaces, moving their methods
documentation to linuxContainer.

Rename linuxContainer to Container.

Adopt users from using interface to using struct.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin
2022-02-11 12:07:29 -08:00
parent c4c48896eb
commit 102b8abd26
12 changed files with 128 additions and 194 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"golang.org/x/sys/unix"
)
func killContainer(container libcontainer.Container) error {
func killContainer(container *libcontainer.Container) error {
_ = container.Signal(unix.SIGKILL, false)
for i := 0; i < 100; i++ {
time.Sleep(100 * time.Millisecond)
-67
View File
@@ -5,11 +5,9 @@
package libcontainer
import (
"os"
"time"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runtime-spec/specs-go"
)
// Status is the status of a container.
@@ -59,68 +57,3 @@ type BaseState struct {
// Config is the container's configuration.
Config configs.Config `json:"config"`
}
// BaseContainer is a libcontainer container object.
//
// Each container is thread-safe within the same process. Since a container can
// be destroyed by a separate process, any function may return that the container
// was not found. BaseContainer includes methods that are platform agnostic.
type BaseContainer interface {
// Returns the ID of the container
ID() string
// Returns the current status of the container.
Status() (Status, error)
// State returns the current container's state information.
State() (*State, error)
// OCIState returns the current container's state information.
OCIState() (*specs.State, error)
// Returns the current config of the container.
Config() configs.Config
// Returns the PIDs inside this container. The PIDs are in the namespace of the calling process.
//
// Some of the returned PIDs may no longer refer to processes in the Container, unless
// the Container state is PAUSED in which case every PID in the slice is valid.
Processes() ([]int, error)
// Returns statistics for the container.
Stats() (*Stats, error)
// Set resources of container as configured
//
// We can use this to change resources when containers are running.
//
Set(config configs.Config) error
// Start a process inside the container. Returns error if process fails to
// start. You can track process lifecycle with passed Process structure.
Start(process *Process) (err error)
// Run immediately starts the process inside the container. Returns error if process
// fails to start. It does not block waiting for the exec fifo after start returns but
// opens the fifo after start returns.
Run(process *Process) (err error)
// Destroys the container, if its in a valid state, after killing any
// remaining running processes.
//
// Any event registrations are removed before the container is destroyed.
// No error is returned if the container is already destroyed.
//
// Running containers must first be stopped using Signal(..).
// Paused containers must first be resumed using Resume(..).
Destroy() error
// Signal sends the provided signal code to the container's initial process.
//
// If all is specified the signal is sent to all processes in the container
// including the initial process.
Signal(s os.Signal, all bool) error
// Exec signals the container to exec the users process at the end of the init.
Exec() error
}
+97 -92
View File
@@ -36,7 +36,8 @@ import (
const stdioFdCount = 3
type linuxContainer struct {
// Container is a libcontainer container object.
type Container struct {
id string
root string
config *configs.Config
@@ -80,69 +81,44 @@ type State struct {
IntelRdtPath string `json:"intel_rdt_path"`
}
// Container is a libcontainer container object.
//
// Each container is thread-safe within the same process. Since a container can
// be destroyed by a separate process, any function may return that the container
// was not found.
type Container interface {
BaseContainer
// Methods below here are platform specific
// Checkpoint checkpoints the running container's state to disk using the criu(8) utility.
Checkpoint(criuOpts *CriuOpts) error
// Restore restores the checkpointed container to a running state using the criu(8) utility.
Restore(process *Process, criuOpts *CriuOpts) error
// If the Container state is RUNNING or CREATED, sets the Container state to PAUSED and pauses
// the execution of any user processes. Asynchronously, when the container finished being paused the
// state is changed to PAUSED.
// If the Container state is PAUSED, do nothing.
Pause() error
// If the Container state is PAUSED, resumes the execution of any user processes in the
// Container before setting the Container state to RUNNING.
// If the Container state is RUNNING, do nothing.
Resume() error
// NotifyOOM returns a read-only channel signaling when the container receives an OOM notification.
NotifyOOM() (<-chan struct{}, error)
// NotifyMemoryPressure returns a read-only channel signaling when the container reaches a given pressure level
NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error)
}
// ID returns the container's unique ID
func (c *linuxContainer) ID() string {
func (c *Container) ID() string {
return c.id
}
// Config returns the container's configuration
func (c *linuxContainer) Config() configs.Config {
func (c *Container) Config() configs.Config {
return *c.config
}
func (c *linuxContainer) Status() (Status, error) {
// Status returns the current status of the container.
func (c *Container) Status() (Status, error) {
c.m.Lock()
defer c.m.Unlock()
return c.currentStatus()
}
func (c *linuxContainer) State() (*State, error) {
// State returns the current container's state information.
func (c *Container) State() (*State, error) {
c.m.Lock()
defer c.m.Unlock()
return c.currentState()
}
func (c *linuxContainer) OCIState() (*specs.State, error) {
// OCIState returns the current container's state information.
func (c *Container) OCIState() (*specs.State, error) {
c.m.Lock()
defer c.m.Unlock()
return c.currentOCIState()
}
func (c *linuxContainer) Processes() ([]int, error) {
// Processes returns the PIDs inside this container. The PIDs are in the
// namespace of the calling process.
//
// Some of the returned PIDs may no longer refer to processes in the container,
// unless the container state is PAUSED in which case every PID in the slice is
// valid.
func (c *Container) Processes() ([]int, error) {
var pids []int
status, err := c.currentStatus()
if err != nil {
@@ -160,7 +136,8 @@ func (c *linuxContainer) Processes() ([]int, error) {
return pids, nil
}
func (c *linuxContainer) Stats() (*Stats, error) {
// Stats returns statistics for the container.
func (c *Container) Stats() (*Stats, error) {
var (
err error
stats = &Stats{}
@@ -186,7 +163,9 @@ func (c *linuxContainer) Stats() (*Stats, error) {
return stats, nil
}
func (c *linuxContainer) Set(config configs.Config) error {
// Set resources of container as configured. Can be used to change resources
// when the container is running.
func (c *Container) Set(config configs.Config) error {
c.m.Lock()
defer c.m.Unlock()
status, err := c.currentStatus()
@@ -221,7 +200,9 @@ func (c *linuxContainer) Set(config configs.Config) error {
return err
}
func (c *linuxContainer) Start(process *Process) error {
// Start starts a process inside the container. Returns error if process fails
// to start. You can track process lifecycle with passed Process structure.
func (c *Container) Start(process *Process) error {
c.m.Lock()
defer c.m.Unlock()
if c.config.Cgroups.Resources.SkipDevices {
@@ -241,7 +222,10 @@ func (c *linuxContainer) Start(process *Process) error {
return nil
}
func (c *linuxContainer) Run(process *Process) error {
// Run immediately starts the process inside the container. Returns an error if
// the process fails to start. It does not block waiting for the exec fifo
// after start returns but opens the fifo after start returns.
func (c *Container) Run(process *Process) error {
if err := c.Start(process); err != nil {
return err
}
@@ -251,13 +235,14 @@ func (c *linuxContainer) Run(process *Process) error {
return nil
}
func (c *linuxContainer) Exec() error {
// Exec signals the container to exec the users process at the end of the init.
func (c *Container) Exec() error {
c.m.Lock()
defer c.m.Unlock()
return c.exec()
}
func (c *linuxContainer) exec() error {
func (c *Container) exec() error {
path := filepath.Join(c.root, execFifoFilename)
pid := c.initProcess.pid()
blockingFifoOpenCh := awaitFifoOpen(path)
@@ -329,7 +314,7 @@ type openResult struct {
err error
}
func (c *linuxContainer) start(process *Process) (retErr error) {
func (c *Container) start(process *Process) (retErr error) {
parent, err := c.newParentProcess(process)
if err != nil {
return fmt.Errorf("unable to create new parent process: %w", err)
@@ -370,7 +355,7 @@ func (c *linuxContainer) start(process *Process) (retErr error) {
return nil
}
func (c *linuxContainer) Signal(s os.Signal, all bool) error {
func (c *Container) Signal(s os.Signal, all bool) error {
c.m.Lock()
defer c.m.Unlock()
status, err := c.currentStatus()
@@ -402,7 +387,7 @@ func (c *linuxContainer) Signal(s os.Signal, all bool) error {
return ErrNotRunning
}
func (c *linuxContainer) createExecFifo() error {
func (c *Container) createExecFifo() error {
rootuid, err := c.Config().HostRootUID()
if err != nil {
return err
@@ -425,7 +410,7 @@ func (c *linuxContainer) createExecFifo() error {
return os.Chown(fifoName, rootuid, rootgid)
}
func (c *linuxContainer) deleteExecFifo() {
func (c *Container) deleteExecFifo() {
fifoName := filepath.Join(c.root, execFifoFilename)
os.Remove(fifoName)
}
@@ -434,7 +419,7 @@ func (c *linuxContainer) deleteExecFifo() {
// container cannot access the statedir (and the FIFO itself remains
// un-opened). It then adds the FifoFd to the given exec.Cmd as an inherited
// fd, with _LIBCONTAINER_FIFOFD set to its fd number.
func (c *linuxContainer) includeExecFifo(cmd *exec.Cmd) error {
func (c *Container) includeExecFifo(cmd *exec.Cmd) error {
fifoName := filepath.Join(c.root, execFifoFilename)
fifo, err := os.OpenFile(fifoName, unix.O_PATH|unix.O_CLOEXEC, 0)
if err != nil {
@@ -448,7 +433,7 @@ func (c *linuxContainer) includeExecFifo(cmd *exec.Cmd) error {
return nil
}
func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) {
func (c *Container) newParentProcess(p *Process) (parentProcess, error) {
parentInitPipe, childInitPipe, err := utils.NewSockPair("init")
if err != nil {
return nil, fmt.Errorf("unable to create init pipe: %w", err)
@@ -477,7 +462,7 @@ func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) {
return c.newInitProcess(p, cmd, messageSockPair, logFilePair)
}
func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, childLogPipe *os.File) *exec.Cmd {
func (c *Container) commandTemplate(p *Process, childInitPipe *os.File, childLogPipe *os.File) *exec.Cmd {
cmd := exec.Command("/proc/self/exe", "init")
cmd.Args[0] = os.Args[0]
cmd.Stdin = p.Stdin
@@ -519,7 +504,7 @@ func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, chi
// shouldSendMountSources says whether the child process must setup bind mounts with
// the source pre-opened (O_PATH) in the host user namespace.
// See https://github.com/opencontainers/runc/issues/2484
func (c *linuxContainer) shouldSendMountSources() bool {
func (c *Container) shouldSendMountSources() bool {
// Passing the mount sources via SCM_RIGHTS is only necessary when
// both userns and mntns are active.
if !c.config.Namespaces.Contains(configs.NEWUSER) ||
@@ -543,7 +528,7 @@ func (c *linuxContainer) shouldSendMountSources() bool {
return false
}
func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*initProcess, error) {
func (c *Container) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*initProcess, error) {
cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initStandard))
nsMaps := make(map[configs.NamespaceType]string)
for _, ns := range c.config.Namespaces {
@@ -602,7 +587,7 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPa
return init, nil
}
func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*setnsProcess, error) {
func (c *Container) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*setnsProcess, error) {
cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initSetns))
state, err := c.currentState()
if err != nil {
@@ -659,7 +644,7 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockP
return proc, nil
}
func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
func (c *Container) newInitConfig(process *Process) *initConfig {
cfg := &initConfig{
Config: c.config,
Args: process.Args,
@@ -699,13 +684,23 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
return cfg
}
func (c *linuxContainer) Destroy() error {
// Destroy destroys the container, if its in a valid state, after killing any
// remaining running processes.
//
// Any event registrations are removed before the container is destroyed.
// No error is returned if the container is already destroyed.
//
// Running containers must first be stopped using Signal.
// Paused containers must first be resumed using Resume.
func (c *Container) Destroy() error {
c.m.Lock()
defer c.m.Unlock()
return c.state.destroy()
}
func (c *linuxContainer) Pause() error {
// Pause pauses the container, if its state is RUNNING or CREATED, changing
// its state to PAUSED. If the state is already PAUSED, does nothing.
func (c *Container) Pause() error {
c.m.Lock()
defer c.m.Unlock()
status, err := c.currentStatus()
@@ -724,7 +719,11 @@ func (c *linuxContainer) Pause() error {
return ErrNotRunning
}
func (c *linuxContainer) Resume() error {
// Resume resumes the execution of any user processes in the
// container before setting the container state to RUNNING.
// This is only performed if the current state is PAUSED.
// If the Container state is RUNNING, does nothing.
func (c *Container) Resume() error {
c.m.Lock()
defer c.m.Unlock()
status, err := c.currentStatus()
@@ -742,7 +741,9 @@ func (c *linuxContainer) Resume() error {
})
}
func (c *linuxContainer) NotifyOOM() (<-chan struct{}, error) {
// NotifyOOM returns a read-only channel signaling when the container receives
// an OOM notification.
func (c *Container) NotifyOOM() (<-chan struct{}, error) {
// XXX(cyphar): This requires cgroups.
if c.config.RootlessCgroups {
logrus.Warn("getting OOM notifications may fail if you don't have the full access to cgroups")
@@ -754,7 +755,9 @@ func (c *linuxContainer) NotifyOOM() (<-chan struct{}, error) {
return notifyOnOOM(path)
}
func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error) {
// NotifyMemoryPressure returns a read-only channel signaling when the
// container reaches a given pressure level.
func (c *Container) NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error) {
// XXX(cyphar): This requires cgroups.
if c.config.RootlessCgroups {
logrus.Warn("getting memory pressure notifications may fail if you don't have the full access to cgroups")
@@ -764,7 +767,7 @@ func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struc
var criuFeatures *criurpc.CriuFeatures
func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.CriuOpts, criuFeat *criurpc.CriuFeatures) error {
func (c *Container) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.CriuOpts, criuFeat *criurpc.CriuFeatures) error {
t := criurpc.CriuReqType_FEATURE_CHECK
// make sure the features we are looking for are really not from
@@ -824,8 +827,8 @@ func compareCriuVersion(criuVersion int, minVersion int) error {
return nil
}
// checkCriuVersion checks Criu version greater than or equal to minVersion
func (c *linuxContainer) checkCriuVersion(minVersion int) error {
// checkCriuVersion checks CRIU version greater than or equal to minVersion.
func (c *Container) checkCriuVersion(minVersion int) error {
// If the version of criu has already been determined there is no need
// to ask criu for the version again. Use the value from c.criuVersion.
if c.criuVersion != 0 {
@@ -844,7 +847,7 @@ func (c *linuxContainer) checkCriuVersion(minVersion int) error {
const descriptorsFilename = "descriptors.json"
func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount) {
func (c *Container) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount) {
mountDest := strings.TrimPrefix(m.Destination, c.config.Rootfs)
if dest, err := securejoin.SecureJoin(c.config.Rootfs, mountDest); err == nil {
mountDest = dest[len(c.config.Rootfs):]
@@ -856,7 +859,7 @@ func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount
req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
}
func (c *linuxContainer) addMaskPaths(req *criurpc.CriuReq) error {
func (c *Container) addMaskPaths(req *criurpc.CriuReq) error {
for _, path := range c.config.MaskPaths {
fi, err := os.Stat(fmt.Sprintf("/proc/%d/root/%s", c.initProcess.pid(), path))
if err != nil {
@@ -878,7 +881,7 @@ func (c *linuxContainer) addMaskPaths(req *criurpc.CriuReq) error {
return nil
}
func (c *linuxContainer) handleCriuConfigurationFile(rpcOpts *criurpc.CriuOpts) {
func (c *Container) handleCriuConfigurationFile(rpcOpts *criurpc.CriuOpts) {
// CRIU will evaluate a configuration starting with release 3.11.
// Settings in the configuration file will overwrite RPC settings.
// Look for annotations. The annotation 'org.criu.config'
@@ -903,7 +906,7 @@ func (c *linuxContainer) handleCriuConfigurationFile(rpcOpts *criurpc.CriuOpts)
}
}
func (c *linuxContainer) criuSupportsExtNS(t configs.NamespaceType) bool {
func (c *Container) criuSupportsExtNS(t configs.NamespaceType) bool {
var minVersion int
switch t {
case configs.NEWNET:
@@ -923,7 +926,7 @@ func criuNsToKey(t configs.NamespaceType) string {
return "extRoot" + strings.Title(configs.NsName(t)) + "NS" //nolint:staticcheck // SA1019: strings.Title is deprecated
}
func (c *linuxContainer) handleCheckpointingExternalNamespaces(rpcOpts *criurpc.CriuOpts, t configs.NamespaceType) error {
func (c *Container) handleCheckpointingExternalNamespaces(rpcOpts *criurpc.CriuOpts, t configs.NamespaceType) error {
if !c.criuSupportsExtNS(t) {
return nil
}
@@ -945,7 +948,7 @@ func (c *linuxContainer) handleCheckpointingExternalNamespaces(rpcOpts *criurpc.
return nil
}
func (c *linuxContainer) handleRestoringNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File) error {
func (c *Container) handleRestoringNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File) error {
for _, ns := range c.config.Namespaces {
switch ns.Type {
case configs.NEWNET, configs.NEWPID:
@@ -983,7 +986,7 @@ func (c *linuxContainer) handleRestoringNamespaces(rpcOpts *criurpc.CriuOpts, ex
return nil
}
func (c *linuxContainer) handleRestoringExternalNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File, t configs.NamespaceType) error {
func (c *Container) handleRestoringExternalNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File, t configs.NamespaceType) error {
if !c.criuSupportsExtNS(t) {
return nil
}
@@ -1014,7 +1017,7 @@ func (c *linuxContainer) handleRestoringExternalNamespaces(rpcOpts *criurpc.Criu
return nil
}
func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
func (c *Container) Checkpoint(criuOpts *CriuOpts) error {
c.m.Lock()
defer c.m.Unlock()
@@ -1222,7 +1225,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
return nil
}
func (c *linuxContainer) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mount) {
func (c *Container) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mount) {
mountDest := strings.TrimPrefix(m.Destination, c.config.Rootfs)
if dest, err := securejoin.SecureJoin(c.config.Rootfs, mountDest); err == nil {
mountDest = dest[len(c.config.Rootfs):]
@@ -1234,7 +1237,7 @@ func (c *linuxContainer) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mo
req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
}
func (c *linuxContainer) restoreNetwork(req *criurpc.CriuReq, criuOpts *CriuOpts) {
func (c *Container) restoreNetwork(req *criurpc.CriuReq, criuOpts *CriuOpts) {
for _, iface := range c.config.Networks {
switch iface.Type {
case "veth":
@@ -1257,7 +1260,7 @@ func (c *linuxContainer) restoreNetwork(req *criurpc.CriuReq, criuOpts *CriuOpts
// makeCriuRestoreMountpoints makes the actual mountpoints for the
// restore using CRIU. This function is inspired from the code in
// rootfs_linux.go
func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error {
func (c *Container) makeCriuRestoreMountpoints(m *configs.Mount) error {
switch m.Device {
case "cgroup":
// No mount point(s) need to be created:
@@ -1309,7 +1312,7 @@ func isPathInPrefixList(path string, prefix []string) bool {
// runc modifies the rootfs to add mountpoints which do not exist.
// This function also creates missing mountpoints as long as they
// are not on top of a tmpfs, as CRIU will restore tmpfs content anyway.
func (c *linuxContainer) prepareCriuRestoreMounts(mounts []*configs.Mount) error {
func (c *Container) prepareCriuRestoreMounts(mounts []*configs.Mount) error {
// First get a list of a all tmpfs mounts
tmpfs := []string{}
for _, m := range mounts {
@@ -1366,7 +1369,9 @@ func (c *linuxContainer) prepareCriuRestoreMounts(mounts []*configs.Mount) error
return nil
}
func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
// Restore restores the checkpointed container to a running state using the
// criu(8) utility.
func (c *Container) Restore(process *Process, criuOpts *CriuOpts) error {
c.m.Lock()
defer c.m.Unlock()
@@ -1540,7 +1545,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
return err
}
func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
func (c *Container) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
// need to apply cgroups only on restore
if req.GetType() != criurpc.CriuReqType_RESTORE {
return nil
@@ -1577,7 +1582,7 @@ func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
return nil
}
func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts, extraFiles []*os.File) error {
func (c *Container) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts, extraFiles []*os.File) error {
fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_SEQPACKET|unix.SOCK_CLOEXEC, 0)
if err != nil {
return err
@@ -1795,7 +1800,7 @@ func unlockNetwork(config *configs.Config) error {
return nil
}
func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Process, cmd *exec.Cmd, opts *CriuOpts, fds []string, oob []byte) error {
func (c *Container) criuNotifications(resp *criurpc.CriuResp, process *Process, cmd *exec.Cmd, opts *CriuOpts, fds []string, oob []byte) error {
notify := resp.GetNotify()
if notify == nil {
return fmt.Errorf("invalid response: %s", resp.String())
@@ -1893,7 +1898,7 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
return nil
}
func (c *linuxContainer) updateState(process parentProcess) (*State, error) {
func (c *Container) updateState(process parentProcess) (*State, error) {
if process != nil {
c.initProcess = process
}
@@ -1908,7 +1913,7 @@ func (c *linuxContainer) updateState(process parentProcess) (*State, error) {
return state, nil
}
func (c *linuxContainer) saveState(s *State) (retErr error) {
func (c *Container) saveState(s *State) (retErr error) {
tmpFile, err := os.CreateTemp(c.root, "state-")
if err != nil {
return err
@@ -1934,7 +1939,7 @@ func (c *linuxContainer) saveState(s *State) (retErr error) {
return os.Rename(tmpFile.Name(), stateFilePath)
}
func (c *linuxContainer) currentStatus() (Status, error) {
func (c *Container) currentStatus() (Status, error) {
if err := c.refreshState(); err != nil {
return -1, err
}
@@ -1945,7 +1950,7 @@ func (c *linuxContainer) currentStatus() (Status, error) {
// container is what is true. Because consumers of libcontainer can use it
// out of process we need to verify the container's status based on runtime
// information and not rely on our in process info.
func (c *linuxContainer) refreshState() error {
func (c *Container) refreshState() error {
paused, err := c.isPaused()
if err != nil {
return err
@@ -1963,7 +1968,7 @@ func (c *linuxContainer) refreshState() error {
return c.state.transition(&stoppedState{c: c})
}
func (c *linuxContainer) runType() Status {
func (c *Container) runType() Status {
if c.initProcess == nil {
return Stopped
}
@@ -1983,7 +1988,7 @@ func (c *linuxContainer) runType() Status {
return Running
}
func (c *linuxContainer) isPaused() (bool, error) {
func (c *Container) isPaused() (bool, error) {
state, err := c.cgroupManager.GetFreezerState()
if err != nil {
return false, err
@@ -1991,7 +1996,7 @@ func (c *linuxContainer) isPaused() (bool, error) {
return state == configs.Frozen, nil
}
func (c *linuxContainer) currentState() (*State, error) {
func (c *Container) currentState() (*State, error) {
var (
startTime uint64
externalDescriptors []string
@@ -2038,7 +2043,7 @@ func (c *linuxContainer) currentState() (*State, error) {
return state, nil
}
func (c *linuxContainer) currentOCIState() (*specs.State, error) {
func (c *Container) currentOCIState() (*specs.State, error) {
bundle, annotations := utils.Annotations(c.config.Labels)
state := &specs.State{
Version: specs.Version,
@@ -2061,7 +2066,7 @@ func (c *linuxContainer) currentOCIState() (*specs.State, error) {
// orderNamespacePaths sorts namespace paths into a list of paths that we
// can setns in order.
func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceType]string) ([]string, error) {
func (c *Container) orderNamespacePaths(namespaces map[configs.NamespaceType]string) ([]string, error) {
paths := []string{}
for _, ns := range configs.NamespaceTypes() {
@@ -2114,7 +2119,7 @@ type netlinkError struct{ error }
// such as one that uses nsenter package to bootstrap the container's
// init process correctly, i.e. with correct namespaces, uid/gid
// mapping etc.
func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string, it initType) (_ io.Reader, Err error) {
func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string, it initType) (_ io.Reader, Err error) {
// create the netlink message
r := nl.NewNetlinkRequest(int(InitMsg), 0)
+3 -3
View File
@@ -115,7 +115,7 @@ func TestGetContainerPids(t *testing.T) {
if err != nil {
t.Fatalf("can't stat pid %d, got %v", pid, err)
}
container := &linuxContainer{
container := &Container{
id: "myid",
config: &configs.Config{},
cgroupManager: &mockCgroupManager{
@@ -148,7 +148,7 @@ func TestGetContainerState(t *testing.T) {
expectedMemoryPath = "/sys/fs/cgroup/memory/myid"
expectedNetworkPath = fmt.Sprintf("/proc/%d/ns/net", pid)
)
container := &linuxContainer{
container := &Container{
id: "myid",
config: &configs.Config{
Namespaces: []configs.Namespace{
@@ -232,7 +232,7 @@ func TestGetContainerStateAfterUpdate(t *testing.T) {
t.Fatal(err)
}
container := &linuxContainer{
container := &Container{
root: t.TempDir(),
id: "myid",
config: &configs.Config{
+4 -4
View File
@@ -37,7 +37,7 @@ var idRegex = regexp.MustCompile(`^[\w+-\.]+$`)
// The id must not be empty and consist of only the following characters:
// ASCII letters, digits, underscore, plus, minus, period. The id must be
// unique and non-existent for the given root path.
func Create(root, id string, config *configs.Config) (Container, error) {
func Create(root, id string, config *configs.Config) (*Container, error) {
if root == "" {
return nil, errors.New("root not set")
}
@@ -98,7 +98,7 @@ func Create(root, id string, config *configs.Config) (Container, error) {
if err := os.Mkdir(containerRoot, 0o711); err != nil {
return nil, err
}
c := &linuxContainer{
c := &Container{
id: id,
root: containerRoot,
config: config,
@@ -112,7 +112,7 @@ func Create(root, id string, config *configs.Config) (Container, error) {
// Load takes a path to the state directory (root) and an id of an existing
// container, and returns a Container object reconstructed from the saved
// state. This presents a read only view of the container.
func Load(root, id string) (Container, error) {
func Load(root, id string) (*Container, error) {
if root == "" {
return nil, errors.New("root not set")
}
@@ -137,7 +137,7 @@ func Load(root, id string) (Container, error) {
if err != nil {
return nil, err
}
c := &linuxContainer{
c := &Container{
initProcess: r,
initProcessStartTime: state.InitProcessStartTime,
id: id,
+2 -6
View File
@@ -75,12 +75,8 @@ func TestFactoryLoadContainer(t *testing.T) {
if !reflect.DeepEqual(config.Hooks, expectedHooks) {
t.Fatalf("expects hooks %q but received %q", expectedHooks, config.Hooks)
}
lcontainer, ok := container.(*linuxContainer)
if !ok {
t.Fatal("expected linux container on linux based systems")
}
if lcontainer.initProcess.pid() != expectedState.InitProcessPid {
t.Fatalf("expected init pid %d but received %d", expectedState.InitProcessPid, lcontainer.initProcess.pid())
if container.initProcess.pid() != expectedState.InitProcessPid {
t.Fatalf("expected init pid %d but received %d", expectedState.InitProcessPid, container.initProcess.pid())
}
}
+2 -2
View File
@@ -165,7 +165,7 @@ func copyBusybox(dest string) error {
return nil
}
func newContainer(t *testing.T, config *configs.Config) (libcontainer.Container, error) {
func newContainer(t *testing.T, config *configs.Config) (*libcontainer.Container, error) {
name := strings.ReplaceAll(t.Name(), "/", "_") + strconv.FormatInt(-int64(time.Now().Nanosecond()), 35)
root := t.TempDir()
@@ -212,6 +212,6 @@ func runContainer(t *testing.T, config *configs.Config, args ...string) (buffers
return
}
func destroyContainer(container libcontainer.Container) {
func destroyContainer(container *libcontainer.Container) {
_ = container.Destroy()
}
+1 -1
View File
@@ -300,7 +300,7 @@ type initProcess struct {
config *initConfig
manager cgroups.Manager
intelRdtManager *intelrdt.Manager
container *linuxContainer
container *Container
fds []string
process *Process
bootstrapData io.Reader
+8 -8
View File
@@ -35,7 +35,7 @@ type containerState interface {
status() Status
}
func destroy(c *linuxContainer) error {
func destroy(c *Container) error {
if !c.config.Namespaces.Contains(configs.NEWPID) ||
c.config.Namespaces.PathOf(configs.NEWPID) != "" {
if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil {
@@ -59,7 +59,7 @@ func destroy(c *linuxContainer) error {
return err
}
func runPoststopHooks(c *linuxContainer) error {
func runPoststopHooks(c *Container) error {
hooks := c.config.Hooks
if hooks == nil {
return nil
@@ -80,7 +80,7 @@ func runPoststopHooks(c *linuxContainer) error {
// stoppedState represents a container is a stopped/destroyed state.
type stoppedState struct {
c *linuxContainer
c *Container
}
func (b *stoppedState) status() Status {
@@ -104,7 +104,7 @@ func (b *stoppedState) destroy() error {
// runningState represents a container that is currently running.
type runningState struct {
c *linuxContainer
c *Container
}
func (r *runningState) status() Status {
@@ -136,7 +136,7 @@ func (r *runningState) destroy() error {
}
type createdState struct {
c *linuxContainer
c *Container
}
func (i *createdState) status() Status {
@@ -162,7 +162,7 @@ func (i *createdState) destroy() error {
// pausedState represents a container that is currently pause. It cannot be destroyed in a
// paused state and must transition back to running first.
type pausedState struct {
c *linuxContainer
c *Container
}
func (p *pausedState) status() Status {
@@ -195,7 +195,7 @@ func (p *pausedState) destroy() error {
// information that maybe need destroyed when the container is stopped and destroy is called.
type restoredState struct {
imageDir string
c *linuxContainer
c *Container
}
func (r *restoredState) status() Status {
@@ -222,7 +222,7 @@ func (r *restoredState) destroy() error {
// loadedState is used whenever a container is restored, loaded, or setting additional
// processes inside and it should not be destroyed when it is exiting.
type loadedState struct {
c *linuxContainer
c *Container
s Status
}
+5 -5
View File
@@ -53,7 +53,7 @@ func testTransitions(t *testing.T, initialState containerState, valid []containe
func TestStoppedStateTransition(t *testing.T) {
testTransitions(
t,
&stoppedState{c: &linuxContainer{}},
&stoppedState{c: &Container{}},
[]containerState{
&stoppedState{},
&runningState{},
@@ -65,7 +65,7 @@ func TestStoppedStateTransition(t *testing.T) {
func TestPausedStateTransition(t *testing.T) {
testTransitions(
t,
&pausedState{c: &linuxContainer{}},
&pausedState{c: &Container{}},
[]containerState{
&pausedState{},
&runningState{},
@@ -77,7 +77,7 @@ func TestPausedStateTransition(t *testing.T) {
func TestRestoredStateTransition(t *testing.T) {
testTransitions(
t,
&restoredState{c: &linuxContainer{}},
&restoredState{c: &Container{}},
[]containerState{
&stoppedState{},
&runningState{},
@@ -88,7 +88,7 @@ func TestRestoredStateTransition(t *testing.T) {
func TestRunningStateTransition(t *testing.T) {
testTransitions(
t,
&runningState{c: &linuxContainer{}},
&runningState{c: &Container{}},
[]containerState{
&stoppedState{},
&pausedState{},
@@ -100,7 +100,7 @@ func TestRunningStateTransition(t *testing.T) {
func TestCreatedStateTransition(t *testing.T) {
testTransitions(
t,
&createdState{c: &linuxContainer{}},
&createdState{c: &Container{}},
[]containerState{
&stoppedState{},
&pausedState{},
+1 -1
View File
@@ -91,7 +91,7 @@ func notifySocketStart(context *cli.Context, notifySocketHost, id string) (*noti
return notifySocket, nil
}
func (s *notifySocket) waitForContainer(container libcontainer.Container) error {
func (s *notifySocket) waitForContainer(container *libcontainer.Container) error {
state, err := container.State()
if err != nil {
return err
+4 -4
View File
@@ -25,7 +25,7 @@ var errEmptyID = errors.New("container id cannot be empty")
// getContainer returns the specified container instance by loading it from
// a state directory (root).
func getContainer(context *cli.Context) (libcontainer.Container, error) {
func getContainer(context *cli.Context) (*libcontainer.Container, error) {
id := context.Args().First()
if id == "" {
return nil, errEmptyID
@@ -82,7 +82,7 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) {
return lp, nil
}
func destroy(container libcontainer.Container) {
func destroy(container *libcontainer.Container) {
if err := container.Destroy(); err != nil {
logrus.Error(err)
}
@@ -162,7 +162,7 @@ func createPidFile(path string, process *libcontainer.Process) error {
return os.Rename(tmpName, path)
}
func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcontainer.Container, error) {
func createContainer(context *cli.Context, id string, spec *specs.Spec) (*libcontainer.Container, error) {
rootlessCg, err := shouldUseRootlessCgroupManager(context)
if err != nil {
return nil, err
@@ -193,7 +193,7 @@ type runner struct {
preserveFDs int
pidFile string
consoleSocket string
container libcontainer.Container
container *libcontainer.Container
action CtAct
notifySocket *notifySocket
criuOpts *libcontainer.CriuOpts