diff options
Diffstat (limited to 'execdriver/lxc')
-rw-r--r-- | execdriver/lxc/driver.go | 389 | ||||
-rw-r--r-- | execdriver/lxc/info.go | 50 | ||||
-rw-r--r-- | execdriver/lxc/info_test.go | 36 | ||||
-rw-r--r-- | execdriver/lxc/init.go | 146 | ||||
-rw-r--r-- | execdriver/lxc/lxc_init_linux.go | 11 | ||||
-rw-r--r-- | execdriver/lxc/lxc_init_unsupported.go | 7 | ||||
-rw-r--r-- | execdriver/lxc/lxc_template.go | 147 | ||||
-rw-r--r-- | execdriver/lxc/lxc_template_unit_test.go | 125 |
8 files changed, 0 insertions, 911 deletions
diff --git a/execdriver/lxc/driver.go b/execdriver/lxc/driver.go deleted file mode 100644 index 765a52ee43..0000000000 --- a/execdriver/lxc/driver.go +++ /dev/null @@ -1,389 +0,0 @@ -package lxc - -import ( - "fmt" - "github.com/dotcloud/docker/execdriver" - "github.com/dotcloud/docker/pkg/cgroups" - "github.com/dotcloud/docker/utils" - "io/ioutil" - "log" - "os" - "os/exec" - "path" - "path/filepath" - "strconv" - "strings" - "syscall" - "time" -) - -const DriverName = "lxc" - -func init() { - execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error { - if err := setupHostname(args); err != nil { - return err - } - - if err := setupNetworking(args); err != nil { - return err - } - - if err := setupCapabilities(args); err != nil { - return err - } - - if err := setupWorkingDirectory(args); err != nil { - return err - } - - if err := changeUser(args); err != nil { - return err - } - - path, err := exec.LookPath(args.Args[0]) - if err != nil { - log.Printf("Unable to locate %v", args.Args[0]) - os.Exit(127) - } - if err := syscall.Exec(path, args.Args, os.Environ()); err != nil { - return fmt.Errorf("dockerinit unable to execute %s - %s", path, err) - } - panic("Unreachable") - }) -} - -type driver struct { - root string // root path for the driver to use - apparmor bool - sharedRoot bool -} - -func NewDriver(root string, apparmor bool) (*driver, error) { - // setup unconfined symlink - if err := linkLxcStart(root); err != nil { - return nil, err - } - return &driver{ - apparmor: apparmor, - root: root, - sharedRoot: rootIsShared(), - }, nil -} - -func (d *driver) Name() string { - version := d.version() - return fmt.Sprintf("%s-%s", DriverName, version) -} - -func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { - if err := execdriver.SetTerminal(c, pipes); err != nil { - return -1, err - } - configPath, err := d.generateLXCConfig(c) - if err != nil { - return -1, err - } - params := []string{ - "lxc-start", - "-n", c.ID, - "-f", configPath, - "--", - c.InitPath, - "-driver", - DriverName, - } - - if c.Network != nil { - params = append(params, - "-g", c.Network.Gateway, - "-i", fmt.Sprintf("%s/%d", c.Network.IPAddress, c.Network.IPPrefixLen), - "-mtu", strconv.Itoa(c.Network.Mtu), - ) - } - - if c.User != "" { - params = append(params, "-u", c.User) - } - - if c.Privileged { - if d.apparmor { - params[0] = path.Join(d.root, "lxc-start-unconfined") - - } - params = append(params, "-privileged") - } - - if c.WorkingDir != "" { - params = append(params, "-w", c.WorkingDir) - } - - params = append(params, "--", c.Entrypoint) - params = append(params, c.Arguments...) - - if d.sharedRoot { - // lxc-start really needs / to be non-shared, or all kinds of stuff break - // when lxc-start unmount things and those unmounts propagate to the main - // mount namespace. - // What we really want is to clone into a new namespace and then - // mount / MS_REC|MS_SLAVE, but since we can't really clone or fork - // without exec in go we have to do this horrible shell hack... - shellString := - "mount --make-rslave /; exec " + - utils.ShellQuoteArguments(params) - - params = []string{ - "unshare", "-m", "--", "/bin/sh", "-c", shellString, - } - } - - var ( - name = params[0] - arg = params[1:] - ) - aname, err := exec.LookPath(name) - if err != nil { - aname = name - } - c.Path = aname - c.Args = append([]string{name}, arg...) - - if err := c.Start(); err != nil { - return -1, err - } - - var ( - waitErr error - waitLock = make(chan struct{}) - ) - go func() { - if err := c.Wait(); err != nil { - if _, ok := err.(*exec.ExitError); !ok { // Do not propagate the error if it's simply a status code != 0 - waitErr = err - } - } - close(waitLock) - }() - - // Poll lxc for RUNNING status - pid, err := d.waitForStart(c, waitLock) - if err != nil { - return -1, err - } - c.ContainerPid = pid - - if startCallback != nil { - startCallback(c) - } - - <-waitLock - - return getExitCode(c), waitErr -} - -/// Return the exit code of the process -// if the process has not exited -1 will be returned -func getExitCode(c *execdriver.Command) int { - if c.ProcessState == nil { - return -1 - } - return c.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() -} - -func (d *driver) Kill(c *execdriver.Command, sig int) error { - return KillLxc(c.ID, sig) -} - -func (d *driver) version() string { - var ( - version string - output []byte - err error - ) - if _, errPath := exec.LookPath("lxc-version"); errPath == nil { - output, err = exec.Command("lxc-version").CombinedOutput() - } else { - output, err = exec.Command("lxc-start", "--version").CombinedOutput() - } - if err == nil { - version = strings.TrimSpace(string(output)) - if parts := strings.SplitN(version, ":", 2); len(parts) == 2 { - version = strings.TrimSpace(parts[1]) - } - } - return version -} - -func KillLxc(id string, sig int) error { - var ( - err error - output []byte - ) - _, err = exec.LookPath("lxc-kill") - if err == nil { - output, err = exec.Command("lxc-kill", "-n", id, strconv.Itoa(sig)).CombinedOutput() - } else { - output, err = exec.Command("lxc-stop", "-k", "-n", id, strconv.Itoa(sig)).CombinedOutput() - } - if err != nil { - return fmt.Errorf("Err: %s Output: %s", err, output) - } - return nil -} - -// wait for the process to start and return the pid for the process -func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) (int, error) { - var ( - err error - output []byte - ) - // We wait for the container to be fully running. - // Timeout after 5 seconds. In case of broken pipe, just retry. - // Note: The container can run and finish correctly before - // the end of this loop - for now := time.Now(); time.Since(now) < 5*time.Second; { - select { - case <-waitLock: - // If the process dies while waiting for it, just return - return -1, nil - default: - } - - output, err = d.getInfo(c.ID) - if err != nil { - output, err = d.getInfo(c.ID) - if err != nil { - return -1, err - } - } - info, err := parseLxcInfo(string(output)) - if err != nil { - return -1, err - } - if info.Running { - return info.Pid, nil - } - time.Sleep(50 * time.Millisecond) - } - return -1, execdriver.ErrNotRunning -} - -func (d *driver) getInfo(id string) ([]byte, error) { - return exec.Command("lxc-info", "-n", id).CombinedOutput() -} - -type info struct { - ID string - driver *driver -} - -func (i *info) IsRunning() bool { - var running bool - - output, err := i.driver.getInfo(i.ID) - if err != nil { - utils.Errorf("Error getting info for lxc container %s: %s (%s)", i.ID, err, output) - return false - } - if strings.Contains(string(output), "RUNNING") { - running = true - } - return running -} - -func (d *driver) Info(id string) execdriver.Info { - return &info{ - ID: id, - driver: d, - } -} - -func (d *driver) GetPidsForContainer(id string) ([]int, error) { - pids := []int{} - - // cpu is chosen because it is the only non optional subsystem in cgroups - subsystem := "cpu" - cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem) - if err != nil { - return pids, err - } - - cgroupDir, err := cgroups.GetThisCgroupDir(subsystem) - if err != nil { - return pids, err - } - - filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks") - if _, err := os.Stat(filename); os.IsNotExist(err) { - // With more recent lxc versions use, cgroup will be in lxc/ - filename = filepath.Join(cgroupRoot, cgroupDir, "lxc", id, "tasks") - } - - output, err := ioutil.ReadFile(filename) - if err != nil { - return pids, err - } - for _, p := range strings.Split(string(output), "\n") { - if len(p) == 0 { - continue - } - pid, err := strconv.Atoi(p) - if err != nil { - return pids, fmt.Errorf("Invalid pid '%s': %s", p, err) - } - pids = append(pids, pid) - } - return pids, nil -} - -func linkLxcStart(root string) error { - sourcePath, err := exec.LookPath("lxc-start") - if err != nil { - return err - } - targetPath := path.Join(root, "lxc-start-unconfined") - - if _, err := os.Lstat(targetPath); err != nil && !os.IsNotExist(err) { - return err - } else if err == nil { - if err := os.Remove(targetPath); err != nil { - return err - } - } - return os.Symlink(sourcePath, targetPath) -} - -// TODO: This can be moved to the mountinfo reader in the mount pkg -func rootIsShared() bool { - if data, err := ioutil.ReadFile("/proc/self/mountinfo"); err == nil { - for _, line := range strings.Split(string(data), "\n") { - cols := strings.Split(line, " ") - if len(cols) >= 6 && cols[4] == "/" { - return strings.HasPrefix(cols[6], "shared") - } - } - } - - // No idea, probably safe to assume so - return true -} - -func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) { - root := path.Join(d.root, "containers", c.ID, "config.lxc") - fo, err := os.Create(root) - if err != nil { - return "", err - } - defer fo.Close() - - if err := LxcTemplateCompiled.Execute(fo, struct { - *execdriver.Command - AppArmor bool - }{ - Command: c, - AppArmor: d.apparmor, - }); err != nil { - return "", err - } - return root, nil -} diff --git a/execdriver/lxc/info.go b/execdriver/lxc/info.go deleted file mode 100644 index 3b2ea0d07f..0000000000 --- a/execdriver/lxc/info.go +++ /dev/null @@ -1,50 +0,0 @@ -package lxc - -import ( - "bufio" - "errors" - "strconv" - "strings" -) - -var ( - ErrCannotParse = errors.New("cannot parse raw input") -) - -type lxcInfo struct { - Running bool - Pid int -} - -func parseLxcInfo(raw string) (*lxcInfo, error) { - if raw == "" { - return nil, ErrCannotParse - } - var ( - err error - s = bufio.NewScanner(strings.NewReader(raw)) - info = &lxcInfo{} - ) - for s.Scan() { - text := s.Text() - - if s.Err() != nil { - return nil, s.Err() - } - - parts := strings.Split(text, ":") - if len(parts) < 2 { - continue - } - switch strings.TrimSpace(parts[0]) { - case "state": - info.Running = strings.TrimSpace(parts[1]) == "RUNNING" - case "pid": - info.Pid, err = strconv.Atoi(strings.TrimSpace(parts[1])) - if err != nil { - return nil, err - } - } - } - return info, nil -} diff --git a/execdriver/lxc/info_test.go b/execdriver/lxc/info_test.go deleted file mode 100644 index edafc02511..0000000000 --- a/execdriver/lxc/info_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package lxc - -import ( - "testing" -) - -func TestParseRunningInfo(t *testing.T) { - raw := ` - state: RUNNING - pid: 50` - - info, err := parseLxcInfo(raw) - if err != nil { - t.Fatal(err) - } - if !info.Running { - t.Fatal("info should return a running state") - } - if info.Pid != 50 { - t.Fatalf("info should have pid 50 got %d", info.Pid) - } -} - -func TestEmptyInfo(t *testing.T) { - _, err := parseLxcInfo("") - if err == nil { - t.Fatal("error should not be nil") - } -} - -func TestBadInfo(t *testing.T) { - _, err := parseLxcInfo("state") - if err != nil { - t.Fatal(err) - } -} diff --git a/execdriver/lxc/init.go b/execdriver/lxc/init.go deleted file mode 100644 index e138915212..0000000000 --- a/execdriver/lxc/init.go +++ /dev/null @@ -1,146 +0,0 @@ -package lxc - -import ( - "fmt" - "github.com/dotcloud/docker/execdriver" - "github.com/dotcloud/docker/pkg/netlink" - "github.com/dotcloud/docker/pkg/user" - "github.com/syndtr/gocapability/capability" - "net" - "os" - "strings" - "syscall" -) - -func setupHostname(args *execdriver.InitArgs) error { - hostname := getEnv(args, "HOSTNAME") - if hostname == "" { - return nil - } - return setHostname(hostname) -} - -// Setup networking -func setupNetworking(args *execdriver.InitArgs) error { - if args.Ip != "" { - // eth0 - iface, err := net.InterfaceByName("eth0") - if err != nil { - return fmt.Errorf("Unable to set up networking: %v", err) - } - ip, ipNet, err := net.ParseCIDR(args.Ip) - if err != nil { - return fmt.Errorf("Unable to set up networking: %v", err) - } - if err := netlink.NetworkLinkAddIp(iface, ip, ipNet); err != nil { - return fmt.Errorf("Unable to set up networking: %v", err) - } - if err := netlink.NetworkSetMTU(iface, args.Mtu); err != nil { - return fmt.Errorf("Unable to set MTU: %v", err) - } - if err := netlink.NetworkLinkUp(iface); err != nil { - return fmt.Errorf("Unable to set up networking: %v", err) - } - - // loopback - iface, err = net.InterfaceByName("lo") - if err != nil { - return fmt.Errorf("Unable to set up networking: %v", err) - } - if err := netlink.NetworkLinkUp(iface); err != nil { - return fmt.Errorf("Unable to set up networking: %v", err) - } - } - if args.Gateway != "" { - gw := net.ParseIP(args.Gateway) - if gw == nil { - return fmt.Errorf("Unable to set up networking, %s is not a valid gateway IP", args.Gateway) - } - - if err := netlink.AddDefaultGw(gw); err != nil { - return fmt.Errorf("Unable to set up networking: %v", err) - } - } - - return nil -} - -// Setup working directory -func setupWorkingDirectory(args *execdriver.InitArgs) error { - if args.WorkDir == "" { - return nil - } - if err := syscall.Chdir(args.WorkDir); err != nil { - return fmt.Errorf("Unable to change dir to %v: %v", args.WorkDir, err) - } - return nil -} - -// Takes care of dropping privileges to the desired user -func changeUser(args *execdriver.InitArgs) error { - uid, gid, suppGids, err := user.GetUserGroupSupplementary( - args.User, - syscall.Getuid(), syscall.Getgid(), - ) - if err != nil { - return err - } - - if err := syscall.Setgroups(suppGids); err != nil { - return fmt.Errorf("Setgroups failed: %v", err) - } - if err := syscall.Setgid(gid); err != nil { - return fmt.Errorf("Setgid failed: %v", err) - } - if err := syscall.Setuid(uid); err != nil { - return fmt.Errorf("Setuid failed: %v", err) - } - - return nil -} - -func setupCapabilities(args *execdriver.InitArgs) error { - if args.Privileged { - return nil - } - - drop := []capability.Cap{ - capability.CAP_SETPCAP, - capability.CAP_SYS_MODULE, - capability.CAP_SYS_RAWIO, - capability.CAP_SYS_PACCT, - capability.CAP_SYS_ADMIN, - capability.CAP_SYS_NICE, - capability.CAP_SYS_RESOURCE, - capability.CAP_SYS_TIME, - capability.CAP_SYS_TTY_CONFIG, - capability.CAP_MKNOD, - capability.CAP_AUDIT_WRITE, - capability.CAP_AUDIT_CONTROL, - capability.CAP_MAC_OVERRIDE, - capability.CAP_MAC_ADMIN, - capability.CAP_NET_ADMIN, - } - - c, err := capability.NewPid(os.Getpid()) - if err != nil { - return err - } - - c.Unset(capability.CAPS|capability.BOUNDS, drop...) - - if err := c.Apply(capability.CAPS | capability.BOUNDS); err != nil { - return err - } - return nil -} - -func getEnv(args *execdriver.InitArgs, key string) string { - for _, kv := range args.Env { - parts := strings.SplitN(kv, "=", 2) - if parts[0] == key && len(parts) == 2 { - return parts[1] - } - } - return "" -} diff --git a/execdriver/lxc/lxc_init_linux.go b/execdriver/lxc/lxc_init_linux.go deleted file mode 100644 index 7288f5877b..0000000000 --- a/execdriver/lxc/lxc_init_linux.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build amd64 - -package lxc - -import ( - "syscall" -) - -func setHostname(hostname string) error { - return syscall.Sethostname([]byte(hostname)) -} diff --git a/execdriver/lxc/lxc_init_unsupported.go b/execdriver/lxc/lxc_init_unsupported.go deleted file mode 100644 index d68cb91a1e..0000000000 --- a/execdriver/lxc/lxc_init_unsupported.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !linux !amd64 - -package lxc - -func setHostname(hostname string) error { - panic("Not supported on darwin") -} diff --git a/execdriver/lxc/lxc_template.go b/execdriver/lxc/lxc_template.go deleted file mode 100644 index 1181396a18..0000000000 --- a/execdriver/lxc/lxc_template.go +++ /dev/null @@ -1,147 +0,0 @@ -package lxc - -import ( - "github.com/dotcloud/docker/execdriver" - "strings" - "text/template" -) - -const LxcTemplate = ` -{{if .Network}} -# network configuration -lxc.network.type = veth -lxc.network.link = {{.Network.Bridge}} -lxc.network.name = eth0 -lxc.network.mtu = {{.Network.Mtu}} -{{else}} -# network is disabled (-n=false) -lxc.network.type = empty -lxc.network.flags = up -{{end}} - -# root filesystem -{{$ROOTFS := .Rootfs}} -lxc.rootfs = {{$ROOTFS}} - -# use a dedicated pts for the container (and limit the number of pseudo terminal -# available) -lxc.pts = 1024 - -# disable the main console -lxc.console = none - -# no controlling tty at all -lxc.tty = 1 - -{{if .Privileged}} -lxc.cgroup.devices.allow = a -{{else}} -# no implicit access to devices -lxc.cgroup.devices.deny = a - -# /dev/null and zero -lxc.cgroup.devices.allow = c 1:3 rwm -lxc.cgroup.devices.allow = c 1:5 rwm - -# consoles -lxc.cgroup.devices.allow = c 5:1 rwm -lxc.cgroup.devices.allow = c 5:0 rwm -lxc.cgroup.devices.allow = c 4:0 rwm -lxc.cgroup.devices.allow = c 4:1 rwm - -# /dev/urandom,/dev/random -lxc.cgroup.devices.allow = c 1:9 rwm -lxc.cgroup.devices.allow = c 1:8 rwm - -# /dev/pts/ - pts namespaces are "coming soon" -lxc.cgroup.devices.allow = c 136:* rwm -lxc.cgroup.devices.allow = c 5:2 rwm - -# tuntap -lxc.cgroup.devices.allow = c 10:200 rwm - -# fuse -#lxc.cgroup.devices.allow = c 10:229 rwm - -# rtc -#lxc.cgroup.devices.allow = c 254:0 rwm -{{end}} - -# standard mount point -# Use mnt.putold as per https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/986385 -lxc.pivotdir = lxc_putold - -# NOTICE: These mounts must be applied within the namespace - -# WARNING: procfs is a known attack vector and should probably be disabled -# if your userspace allows it. eg. see http://blog.zx2c4.com/749 -lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0 - -# WARNING: sysfs is a known attack vector and should probably be disabled -# if your userspace allows it. eg. see http://bit.ly/T9CkqJ -lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0 - -{{if .Tty}} -lxc.mount.entry = {{.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw 0 0 -{{end}} - -lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0 -lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0 - -{{if .Privileged}} -{{if .AppArmor}} -lxc.aa_profile = unconfined -{{else}} -#lxc.aa_profile = unconfined -{{end}} -{{end}} - -# limits -{{if .Resources}} -{{if .Resources.Memory}} -lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}} -lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.Memory}} -{{with $memSwap := getMemorySwap .Resources}} -lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}} -{{end}} -{{end}} -{{if .Resources.CpuShares}} -lxc.cgroup.cpu.shares = {{.Resources.CpuShares}} -{{end}} -{{end}} - -{{if .Config}} -{{range $value := .Config}} -{{$value}} -{{end}} -{{end}} -` - -var LxcTemplateCompiled *template.Template - -// Escape spaces in strings according to the fstab documentation, which is the -// format for "lxc.mount.entry" lines in lxc.conf. See also "man 5 fstab". -func escapeFstabSpaces(field string) string { - return strings.Replace(field, " ", "\\040", -1) -} - -func getMemorySwap(v *execdriver.Resources) int64 { - // By default, MemorySwap is set to twice the size of RAM. - // If you want to omit MemorySwap, set it to `-1'. - if v.MemorySwap < 0 { - return 0 - } - return v.Memory * 2 -} - -func init() { - var err error - funcMap := template.FuncMap{ - "getMemorySwap": getMemorySwap, - "escapeFstabSpaces": escapeFstabSpaces, - } - LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate) - if err != nil { - panic(err) - } -} diff --git a/execdriver/lxc/lxc_template_unit_test.go b/execdriver/lxc/lxc_template_unit_test.go deleted file mode 100644 index 99d6e636f5..0000000000 --- a/execdriver/lxc/lxc_template_unit_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package lxc - -import ( - "bufio" - "fmt" - "github.com/dotcloud/docker/execdriver" - "io/ioutil" - "math/rand" - "os" - "path" - "strings" - "testing" - "time" -) - -func TestLXCConfig(t *testing.T) { - root, err := ioutil.TempDir("", "TestLXCConfig") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(root) - - os.MkdirAll(path.Join(root, "containers", "1"), 0777) - - // Memory is allocated randomly for testing - rand.Seed(time.Now().UTC().UnixNano()) - var ( - memMin = 33554432 - memMax = 536870912 - mem = memMin + rand.Intn(memMax-memMin) - cpuMin = 100 - cpuMax = 10000 - cpu = cpuMin + rand.Intn(cpuMax-cpuMin) - ) - - driver, err := NewDriver(root, false) - if err != nil { - t.Fatal(err) - } - command := &execdriver.Command{ - ID: "1", - Resources: &execdriver.Resources{ - Memory: int64(mem), - CpuShares: int64(cpu), - }, - } - p, err := driver.generateLXCConfig(command) - if err != nil { - t.Fatal(err) - } - grepFile(t, p, - fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem)) - - grepFile(t, p, - fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2)) -} - -func TestCustomLxcConfig(t *testing.T) { - root, err := ioutil.TempDir("", "TestCustomLxcConfig") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(root) - - os.MkdirAll(path.Join(root, "containers", "1"), 0777) - - driver, err := NewDriver(root, false) - if err != nil { - t.Fatal(err) - } - command := &execdriver.Command{ - ID: "1", - Privileged: false, - Config: []string{ - "lxc.utsname = docker", - "lxc.cgroup.cpuset.cpus = 0,1", - }, - } - - p, err := driver.generateLXCConfig(command) - if err != nil { - t.Fatal(err) - } - - grepFile(t, p, "lxc.utsname = docker") - grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1") -} - -func grepFile(t *testing.T, path string, pattern string) { - f, err := os.Open(path) - if err != nil { - t.Fatal(err) - } - defer f.Close() - r := bufio.NewReader(f) - var ( - line string - ) - err = nil - for err == nil { - line, err = r.ReadString('\n') - if strings.Contains(line, pattern) == true { - return - } - } - t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path) -} - -func TestEscapeFstabSpaces(t *testing.T) { - var testInputs = map[string]string{ - " ": "\\040", - "": "", - "/double space": "/double\\040\\040space", - "/some long test string": "/some\\040long\\040test\\040string", - "/var/lib/docker": "/var/lib/docker", - " leading": "\\040leading", - "trailing ": "trailing\\040", - } - for in, exp := range testInputs { - if out := escapeFstabSpaces(in); exp != out { - t.Logf("Expected %s got %s", exp, out) - t.Fail() - } - } -} |