binctr/container/container.go
Jess Frazelle 7743701943 add container lib
Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
2018-03-19 22:54:29 -04:00

135 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)
}