From 4b5bf88a08a1fb3d2542f7a0f213d3d90aadf3db Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Sun, 21 Jun 2015 19:28:36 -0700 Subject: [PATCH] Remove nsinit Signed-off-by: Michael Crosby --- nsinit/Makefile | 2 - nsinit/README.md | 128 ----------------- nsinit/checkpoint.go | 67 --------- nsinit/config.go | 323 ------------------------------------------- nsinit/exec.go | 124 ----------------- nsinit/init.go | 28 ---- nsinit/main.go | 49 ------- nsinit/oom.go | 29 ---- nsinit/pause.go | 40 ------ nsinit/restore.go | 120 ---------------- nsinit/security.go | 272 ------------------------------------ nsinit/state.go | 31 ----- nsinit/stats.go | 31 ----- nsinit/tty.go | 94 ------------- nsinit/utils.go | 79 ----------- 15 files changed, 1417 deletions(-) delete mode 100644 nsinit/Makefile delete mode 100644 nsinit/README.md delete mode 100644 nsinit/checkpoint.go delete mode 100644 nsinit/config.go delete mode 100644 nsinit/exec.go delete mode 100644 nsinit/init.go delete mode 100644 nsinit/main.go delete mode 100644 nsinit/oom.go delete mode 100644 nsinit/pause.go delete mode 100644 nsinit/restore.go delete mode 100644 nsinit/security.go delete mode 100644 nsinit/state.go delete mode 100644 nsinit/stats.go delete mode 100644 nsinit/tty.go delete mode 100644 nsinit/utils.go diff --git a/nsinit/Makefile b/nsinit/Makefile deleted file mode 100644 index 57adf154..00000000 --- a/nsinit/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - go build -o nsinit . diff --git a/nsinit/README.md b/nsinit/README.md deleted file mode 100644 index 4e3a8fd9..00000000 --- a/nsinit/README.md +++ /dev/null @@ -1,128 +0,0 @@ -## nsinit - -`nsinit` is a cli application which demonstrates the use of libcontainer. -It is able to spawn new containers or join existing containers. - -### How to build? - -First add the `libcontainer/vendor` into your GOPATH. It's because libcontainer -vendors all its dependencies, so it can be built predictably. - -``` -export GOPATH=$GOPATH:/your/path/to/libcontainer/vendor -``` - -Then get into the nsinit folder and get the imported file. Use `make` command -to make the nsinit binary. - -``` -cd libcontainer/nsinit -go get -make -``` - -We have finished compiling the nsinit package, but a root filesystem must be -provided for use along with a container configuration file. - -Choose a proper place to run your container. For example we use `/busybox`. - -``` -mkdir /busybox -curl -sSL 'https://github.com/jpetazzo/docker-busybox/raw/buildroot-2014.11/rootfs.tar' | tar -xC /busybox -``` - -Then you may need to write a configuration file named `container.json` in the -`/busybox` folder. Environment, networking, and different capabilities for -the container are specified in this file. The configuration is used for each -process executed inside the container. - -See the `sample_configs` folder for examples of what the container configuration -should look like. - -``` -cp libcontainer/sample_configs/minimal.json /busybox/container.json -cd /busybox -``` - -You can customize `container.json` per your needs. After that, nsinit is -ready to work. - -To execute `/bin/bash` in the current directory as a container just run the -following **as root**: - -```bash -nsinit exec --tty --config container.json /bin/bash -``` - -If you wish to spawn another process inside the container while your current -bash session is running, run the same command again to get another bash shell -(or change the command). If the original process (PID 1) dies, all other -processes spawned inside the container will be killed and the namespace will -be removed. - -You can identify if a process is running in a container by looking to see if -`state.json` is in the root of the directory. - -You may also specify an alternate root directory from where the `container.json` -file is read and where the `state.json` file will be saved. - -### How to use? - -Currently nsinit has 9 commands. Type `nsinit -h` to list all of them. -And for every alternative command, you can also use `--help` to get more -detailed help documents. For example, `nsinit config --help`. - -`nsinit` cli application is implemented using [cli.go](https://github.com/codegangsta/cli). -Lots of details are handled in cli.go, so the implementation of `nsinit` itself -is very clean and clear. - -* **config** -It will generate a standard configuration file for a container. By default, it -will generate as the template file in [config.go](https://github.com/docker/libcontainer/blob/f28dff5539855bac2adbc5699f57f84349605b5f/nsinit/config.go#L234). -It will modify the template if you have specified some configuration by options. -* **exec** -Starts a container and execute a new command inside it. Besides common options, it -has some special options as below. - - `--tty,-t`: allocate a TTY to the container. - - `--config`: you can specify a configuration file. By default, it will use - template configuration. - - `--id`: specify the ID for a container. By default, the id is "nsinit". - - `--user,-u`: set the user, uid, and/or gid for the process. By default the - value is "root". - - `--cwd`: set the current working dir. - - `--env`: set environment variables for the process. -* **init** -It's an internal command that is called inside the container's namespaces to -initialize the namespace and exec the user's process. It should not be called -externally. -* **oom** -Display oom notifications for a container, you should specify container id. -* **pause** -Pause the container's processes, you should specify container id. It will use -cgroup freeze subsystem to help. -* **unpause** -Unpause the container's processes. Same with `pause`. -* **stats** -Display statistics for the container, it will mainly show cgroup and network -statistics. -* **state** -Get the container's current state. You can also read the state from `state.json` -in your container_id folder. -* **checkpoint** -Checkpoint a running container. You can read [this](http://criu.org/Advanced_usage) -for more detailed information about options. - - `--id`: specify the ID for a container. By default, the id is "nsinit". - - `--image-path`: path for saving criu image files. You must specify this option. - - `--work-path`: path for saving work files and logs. By default it will - generate a folder named "criu.work" in root directory. - - `--leave-running`: leave the process running after checkpointing. - - `--tcp-established`: allow open tcp connections. - - `--ext-unix-sk`: allow external unix sockets. - - `--shell-job`: allow shell jobs. - - `--page-server`: ADDRESS:PORT of the page server. The dump image can be - sent to a criu page server if we have a page server. -* **restore** -Restore a container from a previous checkpoint. Options are almost the same -with checkpoint and `--image-path` must be specified. -* **help, h** -Shows a list of commands or help for one command. diff --git a/nsinit/checkpoint.go b/nsinit/checkpoint.go deleted file mode 100644 index 794e7571..00000000 --- a/nsinit/checkpoint.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - "fmt" - "github.com/codegangsta/cli" - "github.com/docker/libcontainer" - "strconv" - "strings" -) - -var checkpointCommand = cli.Command{ - Name: "checkpoint", - Usage: "checkpoint a running container", - Flags: []cli.Flag{ - cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"}, - cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"}, - cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"}, - cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"}, - cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"}, - cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"}, - cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"}, - cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"}, - }, - Action: func(context *cli.Context) { - imagePath := context.String("image-path") - if imagePath == "" { - fatal(fmt.Errorf("The --image-path option isn't specified")) - } - - container, err := getContainer(context) - if err != nil { - fatal(err) - } - - // these are the mandatory criu options for a container - criuOpts := &libcontainer.CriuOpts{ - ImagesDirectory: imagePath, - WorkDirectory: context.String("work-path"), - LeaveRunning: context.Bool("leave-running"), - TcpEstablished: context.Bool("tcp-established"), - ExternalUnixConnections: context.Bool("ext-unix-sk"), - ShellJob: context.Bool("shell-job"), - } - - // xxx following criu opts are optional - // The dump image can be sent to a criu page server - if psOpt := context.String("page-server"); psOpt != "" { - addressPort := strings.Split(psOpt, ":") - if len(addressPort) != 2 { - fatal(fmt.Errorf("Use --page-server ADDRESS:PORT to specify page server")) - } - - port_int, err := strconv.Atoi(addressPort[1]) - if err != nil { - fatal(fmt.Errorf("Invalid port number")) - } - criuOpts.PageServer = libcontainer.CriuPageServerInfo{ - Address: addressPort[0], - Port: int32(port_int), - } - } - - if err := container.Checkpoint(criuOpts); err != nil { - fatal(err) - } - }, -} diff --git a/nsinit/config.go b/nsinit/config.go deleted file mode 100644 index 4aea1022..00000000 --- a/nsinit/config.go +++ /dev/null @@ -1,323 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "io" - "math" - "os" - "path/filepath" - "strings" - "syscall" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" - "github.com/docker/libcontainer/configs" - "github.com/docker/libcontainer/utils" -) - -const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV - -var createFlags = []cli.Flag{ - cli.BoolFlag{Name: "cgroup", Usage: "mount the cgroup data for the container"}, - cli.BoolFlag{Name: "read-only", Usage: "set the container's rootfs as read-only"}, - cli.IntFlag{Name: "cpushares", Usage: "set the cpushares for the container"}, - cli.IntFlag{Name: "memory-limit", Usage: "set the memory limit for the container"}, - cli.IntFlag{Name: "memory-swap", Usage: "set the memory swap limit for the container"}, - cli.IntFlag{Name: "memory-swappiness", Usage: "set the memory swappiness value (0-100 inclusive) for the container"}, - cli.IntFlag{Name: "parent-death-signal", Usage: "set the signal that will be delivered to the process in case the parent dies"}, - cli.IntFlag{Name: "userns-root-uid", Usage: "set the user namespace root uid"}, - cli.IntFlag{Name: "veth-mtu", Usage: "veth mtu"}, - cli.StringFlag{Name: "apparmor-profile", Usage: "set the apparmor profile"}, - cli.StringFlag{Name: "cpuset-cpus", Usage: "set the cpuset cpus"}, - cli.StringFlag{Name: "cpuset-mems", Usage: "set the cpuset mems"}, - cli.StringFlag{Name: "hostname", Value: "nsinit", Usage: "hostname value for the container"}, - cli.StringFlag{Name: "ipc", Value: "", Usage: "ipc namespace"}, - cli.StringFlag{Name: "mnt", Value: "", Usage: "mount namespace"}, - cli.StringFlag{Name: "mount-label", Usage: "set the mount label"}, - cli.StringFlag{Name: "net", Value: "", Usage: "network namespace"}, - cli.StringFlag{Name: "pid", Value: "", Usage: "pid namespace"}, - cli.StringFlag{Name: "process-label", Usage: "set the process label"}, - cli.StringFlag{Name: "rootfs", Usage: "set the rootfs"}, - cli.StringFlag{Name: "security", Value: "", Usage: "set the security profile (high, medium, low)"}, - cli.StringFlag{Name: "uts", Value: "", Usage: "uts namespace"}, - cli.StringFlag{Name: "veth-address", Usage: "veth ip address"}, - cli.StringFlag{Name: "veth-bridge", Usage: "veth bridge"}, - cli.StringFlag{Name: "veth-gateway", Usage: "veth gateway address"}, - cli.StringSliceFlag{Name: "bind", Value: &cli.StringSlice{}, Usage: "add bind mounts to the container"}, - cli.StringSliceFlag{Name: "sysctl", Value: &cli.StringSlice{}, Usage: "set system properties in the container"}, - cli.StringSliceFlag{Name: "tmpfs", Value: &cli.StringSlice{}, Usage: "add tmpfs mounts to the container"}, - cli.StringSliceFlag{Name: "groups", Value: &cli.StringSlice{}, Usage: "add additional groups"}, -} - -var configCommand = cli.Command{ - Name: "config", - Usage: "generate a standard configuration file for a container", - Flags: append([]cli.Flag{ - cli.StringFlag{Name: "file,f", Value: "stdout", Usage: "write the configuration to the specified file"}, - }, createFlags...), - Action: func(context *cli.Context) { - template := getTemplate() - modify(template, context) - data, err := json.MarshalIndent(template, "", "\t") - if err != nil { - fatal(err) - } - var f *os.File - filePath := context.String("file") - switch filePath { - case "stdout", "": - f = os.Stdout - default: - if f, err = os.Create(filePath); err != nil { - fatal(err) - } - defer f.Close() - } - if _, err := io.Copy(f, bytes.NewBuffer(data)); err != nil { - fatal(err) - } - }, -} - -func modify(config *configs.Config, context *cli.Context) { - config.ParentDeathSignal = context.Int("parent-death-signal") - config.Readonlyfs = context.Bool("read-only") - config.Cgroups.CpusetCpus = context.String("cpuset-cpus") - config.Cgroups.CpusetMems = context.String("cpuset-mems") - config.Cgroups.CpuShares = int64(context.Int("cpushares")) - config.Cgroups.Memory = int64(context.Int("memory-limit")) - config.Cgroups.MemorySwap = int64(context.Int("memory-swap")) - config.Cgroups.MemorySwappiness = int64(context.Int("memory-swappiness")) - config.AppArmorProfile = context.String("apparmor-profile") - config.ProcessLabel = context.String("process-label") - config.MountLabel = context.String("mount-label") - - rootfs := context.String("rootfs") - if rootfs != "" { - config.Rootfs = rootfs - } - - userns_uid := context.Int("userns-root-uid") - if userns_uid != 0 { - config.Namespaces.Add(configs.NEWUSER, "") - config.UidMappings = []configs.IDMap{ - {ContainerID: 0, HostID: userns_uid, Size: 1}, - {ContainerID: 1, HostID: 1, Size: userns_uid - 1}, - {ContainerID: userns_uid + 1, HostID: userns_uid + 1, Size: math.MaxInt32 - userns_uid}, - } - config.GidMappings = []configs.IDMap{ - {ContainerID: 0, HostID: userns_uid, Size: 1}, - {ContainerID: 1, HostID: 1, Size: userns_uid - 1}, - {ContainerID: userns_uid + 1, HostID: userns_uid + 1, Size: math.MaxInt32 - userns_uid}, - } - for _, node := range config.Devices { - node.Uid = uint32(userns_uid) - node.Gid = uint32(userns_uid) - } - } - - config.SystemProperties = make(map[string]string) - for _, sysProp := range context.StringSlice("sysctl") { - parts := strings.SplitN(sysProp, "=", 2) - if len(parts) != 2 { - logrus.Fatalf("invalid system property %s", sysProp) - } - config.SystemProperties[parts[0]] = parts[1] - } - - for _, group := range context.StringSlice("groups") { - config.AdditionalGroups = append(config.AdditionalGroups, group) - } - - for _, rawBind := range context.StringSlice("bind") { - mount := &configs.Mount{ - Device: "bind", - Flags: syscall.MS_BIND | syscall.MS_REC, - } - parts := strings.SplitN(rawBind, ":", 3) - switch len(parts) { - default: - logrus.Fatalf("invalid bind mount %s", rawBind) - case 2: - mount.Source, mount.Destination = parts[0], parts[1] - case 3: - mount.Source, mount.Destination = parts[0], parts[1] - switch parts[2] { - case "ro": - mount.Flags |= syscall.MS_RDONLY - case "rw": - default: - logrus.Fatalf("invalid bind mount mode %s", parts[2]) - } - } - config.Mounts = append(config.Mounts, mount) - } - for _, tmpfs := range context.StringSlice("tmpfs") { - config.Mounts = append(config.Mounts, &configs.Mount{ - Device: "tmpfs", - Destination: tmpfs, - Flags: syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV, - }) - } - for flag, value := range map[string]configs.NamespaceType{ - "net": configs.NEWNET, - "mnt": configs.NEWNS, - "pid": configs.NEWPID, - "ipc": configs.NEWIPC, - "uts": configs.NEWUTS, - } { - switch v := context.String(flag); v { - case "host": - config.Namespaces.Remove(value) - case "", "private": - if !config.Namespaces.Contains(value) { - config.Namespaces.Add(value, "") - } - if flag == "net" { - config.Networks = []*configs.Network{ - { - Type: "loopback", - Address: "127.0.0.1/0", - Gateway: "localhost", - }, - } - } - if flag == "uts" { - config.Hostname = context.String("hostname") - } - default: - config.Namespaces.Remove(value) - config.Namespaces.Add(value, v) - } - } - if bridge := context.String("veth-bridge"); bridge != "" { - hostName, err := utils.GenerateRandomName("veth", 7) - if err != nil { - logrus.Fatal(err) - } - network := &configs.Network{ - Type: "veth", - Name: "eth0", - Bridge: bridge, - Address: context.String("veth-address"), - Gateway: context.String("veth-gateway"), - Mtu: context.Int("veth-mtu"), - HostInterfaceName: hostName, - } - config.Networks = append(config.Networks, network) - } - if context.Bool("cgroup") { - config.Mounts = append(config.Mounts, &configs.Mount{ - Destination: "/sys/fs/cgroup", - Device: "cgroup", - }) - } - modifySecurityProfile(context, config) -} - -func modifySecurityProfile(context *cli.Context, config *configs.Config) { - profileName := context.String("security") - if profileName == "" { - return - } - profile := profiles[profileName] - if profile == nil { - logrus.Fatalf("invalid profile name %q", profileName) - } - config.Rlimits = profile.Rlimits - config.Capabilities = profile.Capabilities - config.Seccomp = profile.Seccomp - config.AppArmorProfile = profile.ApparmorProfile - config.MountLabel = profile.MountLabel - config.ProcessLabel = profile.ProcessLabel -} - -func getTemplate() *configs.Config { - cwd, err := os.Getwd() - if err != nil { - panic(err) - } - return &configs.Config{ - Rootfs: cwd, - ParentDeathSignal: int(syscall.SIGKILL), - Capabilities: []string{ - "CHOWN", - "DAC_OVERRIDE", - "FSETID", - "FOWNER", - "MKNOD", - "NET_RAW", - "SETGID", - "SETUID", - "SETFCAP", - "SETPCAP", - "NET_BIND_SERVICE", - "SYS_CHROOT", - "KILL", - "AUDIT_WRITE", - }, - Namespaces: configs.Namespaces([]configs.Namespace{ - {Type: configs.NEWNS}, - {Type: configs.NEWUTS}, - {Type: configs.NEWIPC}, - {Type: configs.NEWPID}, - {Type: configs.NEWNET}, - }), - Cgroups: &configs.Cgroup{ - Name: filepath.Base(cwd), - Parent: "nsinit", - AllowAllDevices: false, - AllowedDevices: configs.DefaultAllowedDevices, - MemorySwappiness: -1, - }, - Devices: configs.DefaultAutoCreatedDevices, - MaskPaths: []string{ - "/proc/kcore", - }, - ReadonlyPaths: []string{ - "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", - }, - Mounts: []*configs.Mount{ - { - Source: "proc", - Destination: "/proc", - Device: "proc", - Flags: defaultMountFlags, - }, - { - Source: "tmpfs", - Destination: "/dev", - Device: "tmpfs", - Flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, - Data: "mode=755", - }, - { - Source: "devpts", - Destination: "/dev/pts", - Device: "devpts", - Flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, - Data: "newinstance,ptmxmode=0666,mode=0620,gid=5", - }, - { - Device: "tmpfs", - Source: "shm", - Destination: "/dev/shm", - Data: "mode=1777,size=65536k", - Flags: defaultMountFlags, - }, - { - Source: "mqueue", - Destination: "/dev/mqueue", - Device: "mqueue", - Flags: defaultMountFlags, - }, - { - Source: "sysfs", - Destination: "/sys", - Device: "sysfs", - Flags: defaultMountFlags | syscall.MS_RDONLY, - }, - }, - } -} diff --git a/nsinit/exec.go b/nsinit/exec.go deleted file mode 100644 index 223493af..00000000 --- a/nsinit/exec.go +++ /dev/null @@ -1,124 +0,0 @@ -package main - -import ( - "os" - "os/exec" - "os/signal" - "syscall" - - "github.com/codegangsta/cli" - "github.com/docker/libcontainer" - "github.com/docker/libcontainer/utils" -) - -var standardEnvironment = &cli.StringSlice{ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "HOSTNAME=nsinit", - "TERM=xterm", -} - -var execCommand = cli.Command{ - Name: "exec", - Usage: "execute a new command inside a container", - Action: execAction, - Flags: append([]cli.Flag{ - cli.BoolFlag{Name: "tty,t", Usage: "allocate a TTY to the container"}, - cli.BoolFlag{Name: "systemd", Usage: "Use systemd for managing cgroups, if available"}, - cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"}, - cli.StringFlag{Name: "config", Value: "", Usage: "path to the configuration file"}, - cli.StringFlag{Name: "user,u", Value: "root", Usage: "set the user, uid, and/or gid for the process"}, - cli.StringFlag{Name: "cwd", Value: "", Usage: "set the current working dir"}, - cli.StringSliceFlag{Name: "env", Value: standardEnvironment, Usage: "set environment variables for the process"}, - }, createFlags...), -} - -func execAction(context *cli.Context) { - factory, err := loadFactory(context) - if err != nil { - fatal(err) - } - config, err := loadConfig(context) - if err != nil { - fatal(err) - } - created := false - container, err := factory.Load(context.String("id")) - if err != nil { - created = true - if container, err = factory.Create(context.String("id"), config); err != nil { - fatal(err) - } - } - process := &libcontainer.Process{ - Args: context.Args(), - Env: context.StringSlice("env"), - User: context.String("user"), - Cwd: context.String("cwd"), - Stdin: os.Stdin, - Stdout: os.Stdout, - Stderr: os.Stderr, - } - rootuid, err := config.HostUID() - if err != nil { - fatal(err) - } - tty, err := newTty(context, process, rootuid) - if err != nil { - fatal(err) - } - if err := tty.attach(process); err != nil { - fatal(err) - } - go handleSignals(process, tty) - err = container.Start(process) - if err != nil { - tty.Close() - if created { - container.Destroy() - } - fatal(err) - } - - status, err := process.Wait() - if err != nil { - exitError, ok := err.(*exec.ExitError) - if ok { - status = exitError.ProcessState - } else { - tty.Close() - if created { - container.Destroy() - } - fatal(err) - } - } - if created { - status, err := container.Status() - if err != nil { - tty.Close() - fatal(err) - } - if status != libcontainer.Checkpointed { - if err := container.Destroy(); err != nil { - tty.Close() - fatal(err) - } - } - } - tty.Close() - os.Exit(utils.ExitStatus(status.Sys().(syscall.WaitStatus))) -} - -func handleSignals(container *libcontainer.Process, tty *tty) { - sigc := make(chan os.Signal, 10) - signal.Notify(sigc) - tty.resize() - for sig := range sigc { - switch sig { - case syscall.SIGWINCH: - tty.resize() - default: - container.Signal(sig) - } - } -} diff --git a/nsinit/init.go b/nsinit/init.go deleted file mode 100644 index 24058d44..00000000 --- a/nsinit/init.go +++ /dev/null @@ -1,28 +0,0 @@ -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") - }, -} diff --git a/nsinit/main.go b/nsinit/main.go deleted file mode 100644 index c787acc4..00000000 --- a/nsinit/main.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "os" - - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "nsinit" - app.Version = "2" - app.Author = "libcontainer maintainers" - app.Flags = []cli.Flag{ - cli.BoolFlag{Name: "debug", Usage: "enable debug output in the logs"}, - cli.StringFlag{Name: "root", Value: "/var/run/nsinit", Usage: "root directory for containers"}, - cli.StringFlag{Name: "log-file", Usage: "set the log file to output logs to"}, - cli.StringFlag{Name: "criu", Value: "criu", Usage: "path to the criu binary for checkpoint and restore"}, - } - app.Commands = []cli.Command{ - checkpointCommand, - configCommand, - execCommand, - initCommand, - oomCommand, - pauseCommand, - stateCommand, - statsCommand, - unpauseCommand, - restoreCommand, - } - app.Before = func(context *cli.Context) error { - if context.GlobalBool("debug") { - logrus.SetLevel(logrus.DebugLevel) - } - if path := context.GlobalString("log-file"); path != "" { - f, err := os.Create(path) - if err != nil { - return err - } - logrus.SetOutput(f) - } - return nil - } - if err := app.Run(os.Args); err != nil { - logrus.Fatal(err) - } -} diff --git a/nsinit/oom.go b/nsinit/oom.go deleted file mode 100644 index e92c558d..00000000 --- a/nsinit/oom.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" -) - -var oomCommand = cli.Command{ - Name: "oom", - Usage: "display oom notifications for a container", - Flags: []cli.Flag{ - cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"}, - }, - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - logrus.Fatal(err) - } - n, err := container.NotifyOOM() - if err != nil { - logrus.Fatal(err) - } - for x := range n { - // hack for calm down go1.4 gofmt - _ = x - logrus.Printf("OOM notification received") - } - }, -} diff --git a/nsinit/pause.go b/nsinit/pause.go deleted file mode 100644 index 7b0cc326..00000000 --- a/nsinit/pause.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "github.com/Sirupsen/logrus" - "github.com/codegangsta/cli" -) - -var pauseCommand = cli.Command{ - Name: "pause", - Usage: "pause the container's processes", - Flags: []cli.Flag{ - cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"}, - }, - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - logrus.Fatal(err) - } - if err = container.Pause(); err != nil { - logrus.Fatal(err) - } - }, -} - -var unpauseCommand = cli.Command{ - Name: "unpause", - Usage: "unpause the container's processes", - Flags: []cli.Flag{ - cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"}, - }, - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - logrus.Fatal(err) - } - if err = container.Resume(); err != nil { - logrus.Fatal(err) - } - }, -} diff --git a/nsinit/restore.go b/nsinit/restore.go deleted file mode 100644 index 693288c5..00000000 --- a/nsinit/restore.go +++ /dev/null @@ -1,120 +0,0 @@ -package main - -import ( - "fmt" - "os" - "os/exec" - "syscall" - - "github.com/codegangsta/cli" - "github.com/docker/libcontainer" - "github.com/docker/libcontainer/utils" -) - -var restoreCommand = cli.Command{ - Name: "restore", - Usage: "restore a container from a previous checkpoint", - Flags: []cli.Flag{ - cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"}, - cli.StringFlag{Name: "image-path", Value: "", Usage: "path to criu image files for restoring"}, - cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"}, - cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"}, - cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"}, - cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"}, - }, - Action: func(context *cli.Context) { - imagePath := context.String("image-path") - if imagePath == "" { - fatal(fmt.Errorf("The --image-path option isn't specified")) - } - - var ( - container libcontainer.Container - err error - ) - - factory, err := loadFactory(context) - if err != nil { - fatal(err) - } - - config, err := loadConfig(context) - if err != nil { - fatal(err) - } - - created := false - container, err = factory.Load(context.String("id")) - if err != nil { - created = true - if container, err = factory.Create(context.String("id"), config); err != nil { - fatal(err) - } - } - - process := &libcontainer.Process{ - Stdin: os.Stdin, - Stdout: os.Stdout, - Stderr: os.Stderr, - } - //rootuid, err := config.HostUID() - //if err != nil { - //fatal(err) - //} - rootuid := 0 // XXX - tty, err := newTty(context, process, rootuid) - if err != nil { - fatal(err) - } - if err := tty.attach(process); err != nil { - fatal(err) - } - go handleSignals(process, tty) - - err = container.Restore(process, &libcontainer.CriuOpts{ - ImagesDirectory: imagePath, - WorkDirectory: context.String("work-path"), - TcpEstablished: context.Bool("tcp-established"), - ExternalUnixConnections: context.Bool("ext-unix-sk"), - ShellJob: context.Bool("shell-job"), - }) - if err != nil { - tty.Close() - if created { - container.Destroy() - } - fatal(err) - } - - status, err := process.Wait() - if err != nil { - exitError, ok := err.(*exec.ExitError) - if ok { - status = exitError.ProcessState - } else { - tty.Close() - if created { - container.Destroy() - } - fatal(err) - } - } - - if created { - status, err := container.Status() - if err != nil { - tty.Close() - fatal(err) - } - if status != libcontainer.Checkpointed { - if err := container.Destroy(); err != nil { - tty.Close() - fatal(err) - } - } - } - - tty.Close() - os.Exit(utils.ExitStatus(status.Sys().(syscall.WaitStatus))) - }, -} diff --git a/nsinit/security.go b/nsinit/security.go deleted file mode 100644 index 7835c4b9..00000000 --- a/nsinit/security.go +++ /dev/null @@ -1,272 +0,0 @@ -package main - -import ( - "syscall" - - "github.com/docker/libcontainer/configs" - "github.com/docker/libcontainer/system" -) - -var profiles = map[string]*securityProfile{ - "high": highProfile, - "medium": mediumProfile, - "low": lowProfile, -} - -type securityProfile struct { - Capabilities []string `json:"capabilities"` - ApparmorProfile string `json:"apparmor_profile"` - MountLabel string `json:"mount_label"` - ProcessLabel string `json:"process_label"` - Rlimits []configs.Rlimit `json:"rlimits"` - Seccomp *configs.Seccomp `json:"seccomp"` -} - -// this should be a runtime config that is not able to do things like apt-get or yum install. -var highProfile = &securityProfile{ - Capabilities: []string{ - "NET_BIND_SERVICE", - "KILL", - "AUDIT_WRITE", - }, - Rlimits: []configs.Rlimit{ - { - Type: syscall.RLIMIT_NOFILE, - Hard: 1024, - Soft: 1024, - }, - }, - // http://man7.org/linux/man-pages/man2/syscalls.2.html - Seccomp: &configs.Seccomp{ - Syscalls: []*configs.Syscall{ - { - Value: syscall.SYS_CAPSET, // http://man7.org/linux/man-pages/man2/capset.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_UNSHARE, // http://man7.org/linux/man-pages/man2/unshare.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: int(system.SysSetns()), - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_MOUNT, // http://man7.org/linux/man-pages/man2/mount.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_UMOUNT2, // http://man7.org/linux/man-pages/man2/umount.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CREATE_MODULE, // http://man7.org/linux/man-pages/man2/create_module.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_DELETE_MODULE, // http://man7.org/linux/man-pages/man2/delete_module.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CHMOD, // http://man7.org/linux/man-pages/man2/chmod.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CHOWN, // http://man7.org/linux/man-pages/man2/chown.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_LINK, // http://man7.org/linux/man-pages/man2/link.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_LINKAT, // http://man7.org/linux/man-pages/man2/linkat.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_UNLINK, // http://man7.org/linux/man-pages/man2/unlink.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_UNLINKAT, // http://man7.org/linux/man-pages/man2/unlinkat.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CHROOT, // http://man7.org/linux/man-pages/man2/chroot.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_KEXEC_LOAD, // http://man7.org/linux/man-pages/man2/kexec_load.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_SETDOMAINNAME, // http://man7.org/linux/man-pages/man2/setdomainname.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_SETHOSTNAME, // http://man7.org/linux/man-pages/man2/sethostname.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CLONE, // http://man7.org/linux/man-pages/man2/clone.2.html - Action: configs.Action(syscall.EPERM), - Args: []*configs.Arg{ - { - Index: 0, // the glibc wrapper has the flags at arg2 but the raw syscall has flags at arg0 - Value: syscall.CLONE_NEWUSER, - Op: configs.MaskEqualTo, - }, - }, - }, - }, - }, -} - -// This is a medium level profile that should be able to do things like installing from -// apt-get or yum. -var mediumProfile = &securityProfile{ - Capabilities: []string{ - "CHOWN", - "DAC_OVERRIDE", - "FSETID", - "FOWNER", - "SETGID", - "SETUID", - "SETFCAP", - "SETPCAP", - "NET_BIND_SERVICE", - "KILL", - "AUDIT_WRITE", - }, - Rlimits: []configs.Rlimit{ - { - Type: syscall.RLIMIT_NOFILE, - Hard: 1024, - Soft: 1024, - }, - }, - // http://man7.org/linux/man-pages/man2/syscalls.2.html - Seccomp: &configs.Seccomp{ - Syscalls: []*configs.Syscall{ - { - Value: syscall.SYS_UNSHARE, // http://man7.org/linux/man-pages/man2/unshare.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: int(system.SysSetns()), - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_MOUNT, // http://man7.org/linux/man-pages/man2/mount.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_UMOUNT2, // http://man7.org/linux/man-pages/man2/umount.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CHROOT, // http://man7.org/linux/man-pages/man2/chroot.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CREATE_MODULE, // http://man7.org/linux/man-pages/man2/create_module.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_DELETE_MODULE, // http://man7.org/linux/man-pages/man2/delete_module.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_KEXEC_LOAD, // http://man7.org/linux/man-pages/man2/kexec_load.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_SETDOMAINNAME, // http://man7.org/linux/man-pages/man2/setdomainname.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_SETHOSTNAME, // http://man7.org/linux/man-pages/man2/sethostname.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CLONE, // http://man7.org/linux/man-pages/man2/clone.2.html - Action: configs.Action(syscall.EPERM), - Args: []*configs.Arg{ - { - Index: 0, // the glibc wrapper has the flags at arg2 but the raw syscall has flags at arg0 - Value: syscall.CLONE_NEWUSER, - Op: configs.MaskEqualTo, - }, - }, - }, - }, - }, -} - -var lowProfile = &securityProfile{ - Capabilities: []string{ - "CHOWN", - "DAC_OVERRIDE", - "FSETID", - "FOWNER", - "SETGID", - "SETUID", - "SYS_CHROOT", - "SETFCAP", - "SETPCAP", - "NET_BIND_SERVICE", - "KILL", - "AUDIT_WRITE", - }, - Rlimits: []configs.Rlimit{ - { - Type: syscall.RLIMIT_NOFILE, - Hard: 1024, - Soft: 1024, - }, - }, - // http://man7.org/linux/man-pages/man2/syscalls.2.html - Seccomp: &configs.Seccomp{ - Syscalls: []*configs.Syscall{ - { - Value: syscall.SYS_UNSHARE, // http://man7.org/linux/man-pages/man2/unshare.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: int(system.SysSetns()), - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_MOUNT, // http://man7.org/linux/man-pages/man2/mount.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_UMOUNT2, // http://man7.org/linux/man-pages/man2/umount.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CREATE_MODULE, // http://man7.org/linux/man-pages/man2/create_module.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_DELETE_MODULE, // http://man7.org/linux/man-pages/man2/delete_module.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_KEXEC_LOAD, // http://man7.org/linux/man-pages/man2/kexec_load.2.html - Action: configs.Action(syscall.EPERM), - }, - { - Value: syscall.SYS_CLONE, // http://man7.org/linux/man-pages/man2/clone.2.html - Action: configs.Action(syscall.EPERM), - Args: []*configs.Arg{ - { - Index: 0, // the glibc wrapper has the flags at arg2 but the raw syscall has flags at arg0 - Value: syscall.CLONE_NEWUSER, - Op: configs.MaskEqualTo, - }, - }, - }, - }, - }, -} diff --git a/nsinit/state.go b/nsinit/state.go deleted file mode 100644 index 46981bb7..00000000 --- a/nsinit/state.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - - "github.com/codegangsta/cli" -) - -var stateCommand = cli.Command{ - Name: "state", - Usage: "get the container's current state", - Flags: []cli.Flag{ - cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"}, - }, - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - fatal(err) - } - state, err := container.State() - if err != nil { - fatal(err) - } - data, err := json.MarshalIndent(state, "", "\t") - if err != nil { - fatal(err) - } - fmt.Printf("%s", data) - }, -} diff --git a/nsinit/stats.go b/nsinit/stats.go deleted file mode 100644 index 49087fa2..00000000 --- a/nsinit/stats.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - - "github.com/codegangsta/cli" -) - -var statsCommand = cli.Command{ - Name: "stats", - Usage: "display statistics for the container", - Flags: []cli.Flag{ - cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"}, - }, - Action: func(context *cli.Context) { - container, err := getContainer(context) - if err != nil { - fatal(err) - } - stats, err := container.Stats() - if err != nil { - fatal(err) - } - data, err := json.MarshalIndent(stats, "", "\t") - if err != nil { - fatal(err) - } - fmt.Printf("%s", data) - }, -} diff --git a/nsinit/tty.go b/nsinit/tty.go deleted file mode 100644 index 1cec2192..00000000 --- a/nsinit/tty.go +++ /dev/null @@ -1,94 +0,0 @@ -package main - -import ( - "io" - "os" - - "github.com/codegangsta/cli" - "github.com/docker/docker/pkg/term" - "github.com/docker/libcontainer" -) - -func newTty(context *cli.Context, p *libcontainer.Process, rootuid int) (*tty, error) { - if context.Bool("tty") { - console, err := p.NewConsole(rootuid) - if err != nil { - return nil, err - } - return &tty{ - console: console, - closers: []io.Closer{ - console, - }, - }, nil - } - return &tty{}, nil -} - -type tty struct { - console libcontainer.Console - state *term.State - closers []io.Closer -} - -func (t *tty) Close() error { - for _, c := range t.closers { - c.Close() - } - if t.state != nil { - term.RestoreTerminal(os.Stdin.Fd(), t.state) - } - return nil -} - -func (t *tty) attach(process *libcontainer.Process) error { - if t.console != nil { - go io.Copy(t.console, os.Stdin) - go io.Copy(os.Stdout, t.console) - state, err := term.SetRawTerminal(os.Stdin.Fd()) - if err != nil { - return err - } - t.state = state - process.Stderr = nil - process.Stdout = nil - process.Stdin = nil - } else { - // setup standard pipes so that the TTY of the calling nsinit process - // is not inherited by the container. - r, w, err := os.Pipe() - if err != nil { - return err - } - go io.Copy(w, os.Stdin) - t.closers = append(t.closers, w) - process.Stdin = r - if r, w, err = os.Pipe(); err != nil { - return err - } - go io.Copy(os.Stdout, r) - process.Stdout = w - t.closers = append(t.closers, r) - if r, w, err = os.Pipe(); err != nil { - return err - } - go io.Copy(os.Stderr, r) - process.Stderr = w - t.closers = append(t.closers, r) - } - return nil -} - -func (t *tty) setupPipe() { -} - -func (t *tty) resize() error { - if t.console == nil { - return nil - } - ws, err := term.GetWinsize(os.Stdin.Fd()) - if err != nil { - return err - } - return term.SetWinsize(t.console.Fd(), ws) -} diff --git a/nsinit/utils.go b/nsinit/utils.go deleted file mode 100644 index 7717d86c..00000000 --- a/nsinit/utils.go +++ /dev/null @@ -1,79 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - - "github.com/Sirupsen/logrus" - - "github.com/codegangsta/cli" - "github.com/docker/libcontainer" - "github.com/docker/libcontainer/cgroups/systemd" - "github.com/docker/libcontainer/configs" -) - -func loadConfig(context *cli.Context) (*configs.Config, error) { - if path := context.String("config"); path != "" { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - var config *configs.Config - if err := json.NewDecoder(f).Decode(&config); err != nil { - return nil, err - } - return config, nil - } - config := getTemplate() - modify(config, context) - return config, 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.") - } - } - 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 getContainer(context *cli.Context) (libcontainer.Container, error) { - factory, err := loadFactory(context) - if err != nil { - return nil, err - } - container, err := factory.Load(context.String("id")) - if err != nil { - return nil, err - } - return container, nil -} - -func fatal(err error) { - if lerr, ok := err.(libcontainer.Error); ok { - lerr.Detail(os.Stderr) - os.Exit(1) - } - fmt.Fprintln(os.Stderr, err) - os.Exit(1) -} - -func fatalf(t string, v ...interface{}) { - fmt.Fprintf(os.Stderr, t, v...) - os.Exit(1) -}