136 lines
3.4 KiB
Go
136 lines
3.4 KiB
Go
|
// Package container allows for running a process in a container.
|
||
|
package container
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path/filepath"
|
||
|
|
||
|
"github.com/coreos/go-systemd/activation"
|
||
|
"github.com/opencontainers/runc/libcontainer"
|
||
|
"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
|
||
|
"github.com/opencontainers/runc/libcontainer/specconv"
|
||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||
|
)
|
||
|
|
||
|
// Container defines the behavior and settings for a container object.
|
||
|
type Container struct {
|
||
|
ID string
|
||
|
Spec *specs.Spec
|
||
|
PIDFile string
|
||
|
ConsoleSocket string
|
||
|
Root string
|
||
|
Detach bool
|
||
|
UseSystemdCgroup bool
|
||
|
NoPivotRoot bool
|
||
|
NoNewKeyring bool
|
||
|
Rootless bool
|
||
|
}
|
||
|
|
||
|
// Run starts the container. It returns the exit status or -1 and an
|
||
|
// error. Signals sent to the current process will be forwarded to container.
|
||
|
func (c *Container) Run() (int, error) {
|
||
|
var err error
|
||
|
|
||
|
// Convert pid-file to an absolute path so we can write to the
|
||
|
// right file after chdir to bundle.
|
||
|
if c.PIDFile != "" {
|
||
|
c.PIDFile, err = filepath.Abs(c.PIDFile)
|
||
|
if err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Get the absolute path to the root.
|
||
|
c.Root, err = filepath.Abs(c.Root)
|
||
|
if err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
|
||
|
notifySocket := newNotifySocket(c.ID, c.Root)
|
||
|
if notifySocket != nil {
|
||
|
// Setup the spec for the notify socket.
|
||
|
notifySocket.setupSpec(c.Spec)
|
||
|
}
|
||
|
|
||
|
// Create the libcontainer config.
|
||
|
config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{
|
||
|
CgroupName: c.ID,
|
||
|
UseSystemdCgroup: c.UseSystemdCgroup,
|
||
|
NoPivotRoot: c.NoPivotRoot,
|
||
|
NoNewKeyring: c.NoNewKeyring,
|
||
|
Spec: c.Spec,
|
||
|
Rootless: c.Rootless,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
|
||
|
// Setup the cgroups manager. Default is cgroupfs.
|
||
|
cgroupManager := libcontainer.Cgroupfs
|
||
|
if c.UseSystemdCgroup {
|
||
|
if systemd.UseSystemd() {
|
||
|
cgroupManager = libcontainer.SystemdCgroups
|
||
|
} else {
|
||
|
return -1, fmt.Errorf("systemd cgroup flag passed, but systemd support for managing cgroups is not available")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We resolve the paths for {newuidmap,newgidmap} from the context of runc,
|
||
|
// to avoid doing a path lookup in the nsexec context. TODO: The binary
|
||
|
// names are not currently configurable.
|
||
|
newuidmap, err := exec.LookPath("newuidmap")
|
||
|
if err != nil {
|
||
|
newuidmap = ""
|
||
|
}
|
||
|
newgidmap, err := exec.LookPath("newgidmap")
|
||
|
if err != nil {
|
||
|
newgidmap = ""
|
||
|
}
|
||
|
|
||
|
// Create the new libcontainer factory.
|
||
|
factory, err := libcontainer.New(c.Root, cgroupManager, nil, nil,
|
||
|
libcontainer.NewuidmapPath(newuidmap),
|
||
|
libcontainer.NewgidmapPath(newgidmap))
|
||
|
if err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
|
||
|
// Create the factory.
|
||
|
container, err := factory.Create(c.ID, config)
|
||
|
if err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
|
||
|
if notifySocket != nil {
|
||
|
// Setup the socket for the notify socket.
|
||
|
err := notifySocket.setupSocket()
|
||
|
if err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Support on-demand socket activation by passing file descriptors into
|
||
|
// the container init process.
|
||
|
listenFDs := []*os.File{}
|
||
|
if os.Getenv("LISTEN_FDS") != "" {
|
||
|
listenFDs = activation.Files(false)
|
||
|
}
|
||
|
|
||
|
// Initialize the runner.
|
||
|
r := &runner{
|
||
|
enableSubreaper: true,
|
||
|
shouldDestroy: true,
|
||
|
container: container,
|
||
|
listenFDs: listenFDs,
|
||
|
notifySocket: notifySocket,
|
||
|
consoleSocket: c.ConsoleSocket,
|
||
|
detach: c.Detach,
|
||
|
pidFile: c.PIDFile,
|
||
|
}
|
||
|
|
||
|
// Run the process.
|
||
|
return r.run(c.Spec.Process)
|
||
|
}
|