func TestMain(m *testing.M) { var ( err error ret int = 0 ) log.SetOutput(os.Stderr) log.SetLevel(log.InfoLevel) factory, err = libcontainer.New(".", libcontainer.Cgroupfs) if err != nil { log.Error(err) os.Exit(1) } if systemd.UseSystemd() { systemdFactory, err = libcontainer.New(".", libcontainer.SystemdCgroups) if err != nil { log.Error(err) os.Exit(1) } } ret = m.Run() os.Exit(ret) }
func NewDriver(root, initPath string) (*driver, error) { meminfo, err := sysinfo.ReadMemInfo() if err != nil { return nil, err } if err := os.MkdirAll(root, 0700); err != nil { return nil, err } // native driver root is at docker_root/execdriver/native. Put apparmor at docker_root if err := apparmor.InstallDefaultProfile(); err != nil { return nil, err } cgm := libcontainer.Cgroupfs if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } f, err := libcontainer.New( root, cgm, libcontainer.InitPath(reexec.Self(), DriverName), ) if err != nil { return nil, err } return &driver{ root: root, initPath: initPath, activeContainers: make(map[string]libcontainer.Container), machineMemory: meminfo.MemTotal, factory: f, }, nil }
func loadFactory(context *cli.Context) (libcontainer.Factory, error) { cgm := libcontainer.Cgroupfs if context.Bool("systemd") { if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } else { logrus.Warn("systemd cgroup flag passed, but systemd support for managing cgroups is not available.") } } return libcontainer.New(context.GlobalString("root"), cgm) }
func initializer() { runtime.GOMAXPROCS(1) runtime.LockOSThread() factory, err := libcontainer.New("") if err != nil { fatal(err) } if err := factory.StartInitialization(); err != nil { fatal(err) } panic("unreachable") }
func TestProcessEnv(t *testing.T) { if testing.Short() { return } root, err := newTestRoot() ok(t, err) defer os.RemoveAll(root) rootfs, err := newRootfs() ok(t, err) defer remove(rootfs) config := newTemplateConfig(rootfs) factory, err := libcontainer.New(root, libcontainer.Cgroupfs) ok(t, err) container, err := factory.Create("test", config) ok(t, err) defer container.Destroy() var stdout bytes.Buffer pconfig := libcontainer.Process{ Args: []string{"sh", "-c", "env"}, Env: []string{ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOSTNAME=integration", "TERM=xterm", "FOO=BAR", }, Stdin: nil, Stdout: &stdout, } err = container.Start(&pconfig) ok(t, err) // Wait for process waitProcess(&pconfig, t) outputEnv := string(stdout.Bytes()) // Check that the environment has the key/value pair we added if !strings.Contains(outputEnv, "FOO=BAR") { t.Fatal("Environment doesn't have the expected FOO=BAR key/value pair: ", outputEnv) } // Make sure that HOME is set if !strings.Contains(outputEnv, "HOME=/root") { t.Fatal("Environment doesn't have HOME set: ", outputEnv) } }
// init runs the libcontainer initialization code because of the busybox style needs // to work around the go runtime and the issues with forking func init() { if len(os.Args) < 2 || os.Args[1] != "init" { return } runtime.GOMAXPROCS(1) runtime.LockOSThread() factory, err := libcontainer.New("") if err != nil { log.Fatalf("unable to initialize for container: %s", err) } if err := factory.StartInitialization(); err != nil { log.Fatal(err) } }
func newContainer(config *configs.Config) (libcontainer.Container, error) { cgm := libcontainer.Cgroupfs if config.Cgroups != nil && config.Cgroups.Slice == "system.slice" { cgm = libcontainer.SystemdCgroups } factory, err := libcontainer.New(".", libcontainer.InitArgs(os.Args[0], "init", "--"), cgm, ) if err != nil { return nil, err } return factory.Create("testCT", config) }
func TestAdditionalGroups(t *testing.T) { if testing.Short() { return } root, err := newTestRoot() ok(t, err) defer os.RemoveAll(root) rootfs, err := newRootfs() ok(t, err) defer remove(rootfs) config := newTemplateConfig(rootfs) config.AdditionalGroups = []string{"plugdev", "audio"} factory, err := libcontainer.New(root, libcontainer.Cgroupfs) ok(t, err) container, err := factory.Create("test", config) ok(t, err) defer container.Destroy() var stdout bytes.Buffer pconfig := libcontainer.Process{ Args: []string{"sh", "-c", "id", "-Gn"}, Env: standardEnvironment, Stdin: nil, Stdout: &stdout, } err = container.Start(&pconfig) ok(t, err) // Wait for process waitProcess(&pconfig, t) outputGroups := string(stdout.Bytes()) // Check that the groups output has the groups that we specified if !strings.Contains(outputGroups, "audio") { t.Fatalf("Listed groups do not contain the audio group as expected: %v", outputGroups) } if !strings.Contains(outputGroups, "plugdev") { t.Fatalf("Listed groups do not contain the plugdev group as expected: %v", outputGroups) } }
func loadFactory(context *cli.Context) (libcontainer.Factory, error) { cgm := libcontainer.Cgroupfs if context.Bool("systemd") { if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } else { logrus.Warn("systemd cgroup flag passed, but systemd support for managing cgroups is not available.") } } root := context.GlobalString("root") abs, err := filepath.Abs(root) if err != nil { return nil, err } return libcontainer.New(abs, cgm, func(l *libcontainer.LinuxFactory) error { l.CriuPath = context.GlobalString("criu") return nil }) }
func TestContainerState(t *testing.T) { if testing.Short() { return } root, err := newTestRoot() if err != nil { t.Fatal(err) } defer os.RemoveAll(root) rootfs, err := newRootfs() if err != nil { t.Fatal(err) } defer remove(rootfs) l, err := os.Readlink("/proc/1/ns/ipc") if err != nil { t.Fatal(err) } config := newTemplateConfig(rootfs) config.Namespaces = configs.Namespaces([]configs.Namespace{ {Type: configs.NEWNS}, {Type: configs.NEWUTS}, // host for IPC //{Type: configs.NEWIPC}, {Type: configs.NEWPID}, {Type: configs.NEWNET}, }) factory, err := libcontainer.New(root, libcontainer.Cgroupfs) if err != nil { t.Fatal(err) } container, err := factory.Create("test", config) if err != nil { t.Fatal(err) } defer container.Destroy() stdinR, stdinW, err := os.Pipe() if err != nil { t.Fatal(err) } p := &libcontainer.Process{ Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, } err = container.Start(p) if err != nil { t.Fatal(err) } stdinR.Close() defer p.Signal(os.Kill) st, err := container.State() if err != nil { t.Fatal(err) } l1, err := os.Readlink(st.NamespacePaths[configs.NEWIPC]) if err != nil { t.Fatal(err) } if l1 != l { t.Fatal("Container using non-host ipc namespace") } stdinW.Close() p.Wait() }
func testFreeze(t *testing.T, systemd bool) { if testing.Short() { return } root, err := newTestRoot() if err != nil { t.Fatal(err) } defer os.RemoveAll(root) rootfs, err := newRootfs() if err != nil { t.Fatal(err) } defer remove(rootfs) config := newTemplateConfig(rootfs) if systemd { config.Cgroups.Slice = "system.slice" } factory, err := libcontainer.New(root, libcontainer.Cgroupfs) if err != nil { t.Fatal(err) } container, err := factory.Create("test", config) if err != nil { t.Fatal(err) } defer container.Destroy() stdinR, stdinW, err := os.Pipe() if err != nil { t.Fatal(err) } pconfig := libcontainer.Process{ Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, } err = container.Start(&pconfig) stdinR.Close() defer stdinW.Close() if err != nil { t.Fatal(err) } pid, err := pconfig.Pid() if err != nil { t.Fatal(err) } process, err := os.FindProcess(pid) if err != nil { t.Fatal(err) } if err := container.Pause(); err != nil { t.Fatal(err) } state, err := container.Status() if err != nil { t.Fatal(err) } if err := container.Resume(); err != nil { t.Fatal(err) } if state != libcontainer.Paused { t.Fatal("Unexpected state: ", state) } stdinW.Close() s, err := process.Wait() if err != nil { t.Fatal(err) } if !s.Success() { t.Fatal(s.String()) } }
func TestProcessCaps(t *testing.T) { if testing.Short() { return } root, err := newTestRoot() if err != nil { t.Fatal(err) } defer os.RemoveAll(root) rootfs, err := newRootfs() if err != nil { t.Fatal(err) } defer remove(rootfs) config := newTemplateConfig(rootfs) factory, err := libcontainer.New(root, libcontainer.Cgroupfs) if err != nil { t.Fatal(err) } container, err := factory.Create("test", config) if err != nil { t.Fatal(err) } defer container.Destroy() processCaps := append(config.Capabilities, "NET_ADMIN") var stdout bytes.Buffer pconfig := libcontainer.Process{ Args: []string{"sh", "-c", "cat /proc/self/status"}, Env: standardEnvironment, Capabilities: processCaps, Stdin: nil, Stdout: &stdout, } err = container.Start(&pconfig) if err != nil { t.Fatal(err) } // Wait for process waitProcess(&pconfig, t) outputStatus := string(stdout.Bytes()) if err != nil { t.Fatal(err) } lines := strings.Split(outputStatus, "\n") effectiveCapsLine := "" for _, l := range lines { line := strings.TrimSpace(l) if strings.Contains(line, "CapEff:") { effectiveCapsLine = line break } } if effectiveCapsLine == "" { t.Fatal("Couldn't find effective caps: ", outputStatus) } parts := strings.Split(effectiveCapsLine, ":") effectiveCapsStr := strings.TrimSpace(parts[1]) effectiveCaps, err := strconv.ParseUint(effectiveCapsStr, 16, 64) if err != nil { t.Fatal("Could not parse effective caps", err) } var netAdminMask uint64 var netAdminBit uint netAdminBit = 12 // from capability.h netAdminMask = 1 << netAdminBit if effectiveCaps&netAdminMask != netAdminMask { t.Fatal("CAP_NET_ADMIN is not set as expected") } }
func TestEnter(t *testing.T) { if testing.Short() { return } root, err := newTestRoot() if err != nil { t.Fatal(err) } defer os.RemoveAll(root) rootfs, err := newRootfs() if err != nil { t.Fatal(err) } defer remove(rootfs) config := newTemplateConfig(rootfs) factory, err := libcontainer.New(root, libcontainer.Cgroupfs) if err != nil { t.Fatal(err) } container, err := factory.Create("test", config) if err != nil { t.Fatal(err) } defer container.Destroy() // Execute a first process in the container stdinR, stdinW, err := os.Pipe() if err != nil { t.Fatal(err) } var stdout, stdout2 bytes.Buffer pconfig := libcontainer.Process{ Args: []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"}, Env: standardEnvironment, Stdin: stdinR, Stdout: &stdout, } err = container.Start(&pconfig) stdinR.Close() defer stdinW.Close() if err != nil { t.Fatal(err) } pid, err := pconfig.Pid() if err != nil { t.Fatal(err) } // Execute another process in the container stdinR2, stdinW2, err := os.Pipe() if err != nil { t.Fatal(err) } pconfig2 := libcontainer.Process{ Env: standardEnvironment, } pconfig2.Args = []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"} pconfig2.Stdin = stdinR2 pconfig2.Stdout = &stdout2 err = container.Start(&pconfig2) stdinR2.Close() defer stdinW2.Close() if err != nil { t.Fatal(err) } pid2, err := pconfig2.Pid() if err != nil { t.Fatal(err) } processes, err := container.Processes() if err != nil { t.Fatal(err) } n := 0 for i := range processes { if processes[i] == pid || processes[i] == pid2 { n++ } } if n != 2 { t.Fatal("unexpected number of processes", processes, pid, pid2) } // Wait processes stdinW2.Close() waitProcess(&pconfig2, t) stdinW.Close() waitProcess(&pconfig, t) // Check that both processes live in the same pidns pidns := string(stdout.Bytes()) if err != nil { t.Fatal(err) } pidns2 := string(stdout2.Bytes()) if err != nil { t.Fatal(err) } if pidns != pidns2 { t.Fatal("The second process isn't in the required pid namespace", pidns, pidns2) } }
func TestCheckpoint(t *testing.T) { if testing.Short() { return } root, err := newTestRoot() if err != nil { t.Fatal(err) } defer os.RemoveAll(root) rootfs, err := newRootfs() if err != nil { t.Fatal(err) } defer remove(rootfs) config := newTemplateConfig(rootfs) factory, err := libcontainer.New(root, libcontainer.Cgroupfs) if err != nil { t.Fatal(err) } container, err := factory.Create("test", config) if err != nil { t.Fatal(err) } defer container.Destroy() stdinR, stdinW, err := os.Pipe() if err != nil { t.Fatal(err) } var stdout bytes.Buffer pconfig := libcontainer.Process{ Args: []string{"cat"}, Env: standardEnvironment, Stdin: stdinR, Stdout: &stdout, } err = container.Start(&pconfig) stdinR.Close() defer stdinW.Close() if err != nil { t.Fatal(err) } pid, err := pconfig.Pid() if err != nil { t.Fatal(err) } process, err := os.FindProcess(pid) if err != nil { t.Fatal(err) } imagesDir, err := ioutil.TempDir("", "criu") if err != nil { t.Fatal(err) } defer os.RemoveAll(imagesDir) checkpointOpts := &libcontainer.CriuOpts{ ImagesDirectory: imagesDir, WorkDirectory: imagesDir, } if err := container.Checkpoint(checkpointOpts); err != nil { t.Fatal(err) } state, err := container.Status() if err != nil { t.Fatal(err) } if state != libcontainer.Checkpointed { t.Fatal("Unexpected state: ", state) } stdinW.Close() _, err = process.Wait() if err != nil { t.Fatal(err) } // reload the container container, err = factory.Load("test") if err != nil { t.Fatal(err) } restoreStdinR, restoreStdinW, err := os.Pipe() if err != nil { t.Fatal(err) } restoreProcessConfig := &libcontainer.Process{ Stdin: restoreStdinR, Stdout: &stdout, } err = container.Restore(restoreProcessConfig, &libcontainer.CriuOpts{ ImagesDirectory: imagesDir, }) restoreStdinR.Close() defer restoreStdinW.Close() state, err = container.Status() if err != nil { t.Fatal(err) } if state != libcontainer.Running { t.Fatal("Unexpected state: ", state) } pid, err = restoreProcessConfig.Pid() if err != nil { t.Fatal(err) } process, err = os.FindProcess(pid) if err != nil { t.Fatal(err) } _, err = restoreStdinW.WriteString("Hello!") if err != nil { t.Fatal(err) } restoreStdinW.Close() s, err := process.Wait() if err != nil { t.Fatal(err) } if !s.Success() { t.Fatal(s.String(), pid) } output := string(stdout.Bytes()) if !strings.Contains(output, "Hello!") { t.Fatal("Did not restore the pipe correctly:", output) } }
func loadFactory(context *cli.Context) (libcontainer.Factory, error) { return libcontainer.New(context.GlobalString("root"), libcontainer.Cgroupfs) }
func TestPassExtraFiles(t *testing.T) { if testing.Short() { return } rootfs, err := newRootfs() if err != nil { t.Fatal(err) } defer remove(rootfs) config := newTemplateConfig(rootfs) factory, err := libcontainer.New(rootfs, libcontainer.Cgroupfs) if err != nil { t.Fatal(err) } container, err := factory.Create("test", config) if err != nil { t.Fatal(err) } defer container.Destroy() var stdout bytes.Buffer pipeout1, pipein1, err := os.Pipe() pipeout2, pipein2, err := os.Pipe() process := libcontainer.Process{ Args: []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"}, Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}, ExtraFiles: []*os.File{pipein1, pipein2}, Stdin: nil, Stdout: &stdout, } err = container.Start(&process) if err != nil { t.Fatal(err) } waitProcess(&process, t) out := string(stdout.Bytes()) // fd 5 is the directory handle for /proc/$$/fd if out != "0 1 2 3 4 5" { t.Fatalf("expected to have the file descriptors '0 1 2 3 4 5' passed to init, got '%s'", out) } var buf = []byte{0} _, err = pipeout1.Read(buf) if err != nil { t.Fatal(err) } out1 := string(buf) if out1 != "1" { t.Fatalf("expected first pipe to receive '1', got '%s'", out1) } _, err = pipeout2.Read(buf) if err != nil { t.Fatal(err) } out2 := string(buf) if out2 != "2" { t.Fatalf("expected second pipe to receive '2', got '%s'", out2) } }
func NewDriver(root, initPath string, options []string) (*driver, error) { meminfo, err := sysinfo.ReadMemInfo() if err != nil { return nil, err } if err := sysinfo.MkdirAll(root, 0700); err != nil { return nil, err } // native driver root is at docker_root/execdriver/native. Put apparmor at docker_root if err := apparmor.InstallDefaultProfile(); err != nil { return nil, err } // choose cgroup manager // this makes sure there are no breaking changes to people // who upgrade from versions without native.cgroupdriver opt cgm := libcontainer.Cgroupfs if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } // parse the options for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "native.cgroupdriver": // override the default if they set options switch val { case "systemd": if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } else { // warn them that they chose the wrong driver logrus.Warn("You cannot use systemd as native.cgroupdriver, using cgroupfs instead") } case "cgroupfs": cgm = libcontainer.Cgroupfs default: return nil, fmt.Errorf("Unknown native.cgroupdriver given %q. try cgroupfs or systemd", val) } default: return nil, fmt.Errorf("Unknown option %s\n", key) } } logrus.Debugf("Using %v as native.cgroupdriver", cgm) f, err := libcontainer.New( root, cgm, libcontainer.InitPath(reexec.Self(), DriverName), ) if err != nil { return nil, err } return &driver{ root: root, initPath: initPath, activeContainers: make(map[string]libcontainer.Container), machineMemory: meminfo.MemTotal, factory: f, }, nil }
package main import ( "runtime" "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/docker/libcontainer" _ "github.com/docker/libcontainer/nsenter" ) var initCommand = cli.Command{ Name: "init", Usage: "runs the init process inside the namespace", Action: func(context *cli.Context) { logrus.SetLevel(logrus.DebugLevel) runtime.GOMAXPROCS(1) runtime.LockOSThread() factory, err := libcontainer.New("") if err != nil { fatal(err) } if err := factory.StartInitialization(); err != nil { fatal(err) } panic("This line should never been executed") }, }