diff --git a/daemon/execdriver/lxc/driver.go b/daemon/execdriver/lxc/driver.go index a0ad11cc76..642247c851 100644 --- a/daemon/execdriver/lxc/driver.go +++ b/daemon/execdriver/lxc/driver.go @@ -123,14 +123,6 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba params = append(params, "-w", c.WorkingDir) } - if len(c.CapAdd) > 0 { - params = append(params, fmt.Sprintf("-cap-add=%s", strings.Join(c.CapAdd, ":"))) - } - - if len(c.CapDrop) > 0 { - params = append(params, fmt.Sprintf("-cap-drop=%s", strings.Join(c.CapDrop, ":"))) - } - params = append(params, "--", c.ProcessConfig.Entrypoint) params = append(params, c.ProcessConfig.Arguments...) diff --git a/daemon/execdriver/lxc/init.go b/daemon/execdriver/lxc/init.go index 680f53e1a4..e99502667d 100644 --- a/daemon/execdriver/lxc/init.go +++ b/daemon/execdriver/lxc/init.go @@ -6,7 +6,6 @@ import ( "fmt" "io/ioutil" "log" - "net" "os" "os/exec" "runtime" @@ -14,7 +13,6 @@ import ( "syscall" "github.com/docker/docker/pkg/reexec" - "github.com/docker/libcontainer/netlink" ) // Args provided to the init function for a driver @@ -59,12 +57,7 @@ func setupNamespace(args *InitArgs) error { if err := setupEnv(args); err != nil { return err } - if err := setupHostname(args); err != nil { - return err - } - if err := setupNetworking(args); err != nil { - return err - } + if err := finalizeNamespace(args); err != nil { return err } @@ -138,59 +131,6 @@ func setupEnv(args *InitArgs) error { return nil } -func setupHostname(args *InitArgs) error { - hostname := getEnv(args, "HOSTNAME") - if hostname == "" { - return nil - } - return setHostname(hostname) -} - -// Setup networking -func setupNetworking(args *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.String(), "eth0"); err != nil { - return fmt.Errorf("Unable to set up networking: %v", err) - } - } - - return nil -} - // Setup working directory func setupWorkingDirectory(args *InitArgs) error { if args.WorkDir == "" { diff --git a/daemon/execdriver/lxc/lxc_init_linux.go b/daemon/execdriver/lxc/lxc_init_linux.go index 625caa1608..78bdd11fb9 100644 --- a/daemon/execdriver/lxc/lxc_init_linux.go +++ b/daemon/execdriver/lxc/lxc_init_linux.go @@ -2,74 +2,19 @@ package lxc import ( "fmt" - "strings" - "syscall" - - "github.com/docker/docker/daemon/execdriver" - "github.com/docker/docker/daemon/execdriver/native/template" "github.com/docker/libcontainer/namespaces" - "github.com/docker/libcontainer/security/capabilities" - "github.com/docker/libcontainer/system" "github.com/docker/libcontainer/utils" ) -func setHostname(hostname string) error { - return syscall.Sethostname([]byte(hostname)) -} - func finalizeNamespace(args *InitArgs) error { if err := utils.CloseExecFrom(3); err != nil { return err } - // We use the native drivers default template so that things like caps are consistent - // across both drivers - container := template.New() - - if !args.Privileged { - // drop capabilities in bounding set before changing user - if err := capabilities.DropBoundingSet(container.Capabilities); err != nil { - return fmt.Errorf("drop bounding set %s", err) - } - - // preserve existing capabilities while we change users - if err := system.SetKeepCaps(); err != nil { - return fmt.Errorf("set keep caps %s", err) - } - } - if err := namespaces.SetupUser(args.User); err != nil { return fmt.Errorf("setup user %s", err) } - if !args.Privileged { - if err := system.ClearKeepCaps(); err != nil { - return fmt.Errorf("clear keep caps %s", err) - } - - var ( - adds []string - drops []string - ) - - if args.CapAdd != "" { - adds = strings.Split(args.CapAdd, ":") - } - if args.CapDrop != "" { - drops = strings.Split(args.CapDrop, ":") - } - - caps, err := execdriver.TweakCapabilities(container.Capabilities, adds, drops) - if err != nil { - return err - } - - // drop all other capabilities - if err := capabilities.DropCapabilities(caps); err != nil { - return fmt.Errorf("drop capabilities %s", err) - } - } - if err := setupWorkingDirectory(args); err != nil { return err } diff --git a/daemon/execdriver/lxc/lxc_init_unsupported.go b/daemon/execdriver/lxc/lxc_init_unsupported.go index 6a5904a4d8..97bc8a984c 100644 --- a/daemon/execdriver/lxc/lxc_init_unsupported.go +++ b/daemon/execdriver/lxc/lxc_init_unsupported.go @@ -2,10 +2,6 @@ package lxc -func setHostname(hostname string) error { - panic("Not supported on darwin") -} - func finalizeNamespace(args *InitArgs) error { panic("Not supported on darwin") } diff --git a/daemon/execdriver/lxc/lxc_template.go b/daemon/execdriver/lxc/lxc_template.go index d3fd85b7ab..9402c0697c 100644 --- a/daemon/execdriver/lxc/lxc_template.go +++ b/daemon/execdriver/lxc/lxc_template.go @@ -2,6 +2,7 @@ package lxc import ( "github.com/docker/docker/daemon/execdriver" + nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template" "github.com/docker/libcontainer/label" "os" "strings" @@ -15,6 +16,13 @@ lxc.network.type = veth lxc.network.link = {{.Network.Interface.Bridge}} lxc.network.name = eth0 lxc.network.mtu = {{.Network.Mtu}} +{{if .Network.Interface.IPAddress}} +lxc.network.ipv4 = {{.Network.Interface.IPAddress}}/{{.Network.Interface.IPPrefixLen}} +{{end}} +{{if .Network.Interface.Gateway}} +lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}} +{{end}} +lxc.network.flags = up {{else if .Network.HostNetworking}} lxc.network.type = none {{else}} @@ -78,6 +86,18 @@ lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabS {{end}} {{end}} +{{if .ProcessConfig.Env}} +lxc.utsname = {{getHostname .ProcessConfig.Env}} +{{end}} + +{{if .ProcessConfig.Privileged}} +# No cap values are needed, as lxc is starting in privileged mode +{{else}} +{{range $value := keepCapabilities .CapAdd .CapDrop}} +lxc.cap.keep = {{$value}} +{{end}} +{{end}} + {{if .ProcessConfig.Privileged}} {{if .AppArmor}} lxc.aa_profile = unconfined @@ -118,6 +138,19 @@ func escapeFstabSpaces(field string) string { return strings.Replace(field, " ", "\\040", -1) } +func keepCapabilities(adds []string, drops []string) []string { + container := nativeTemplate.New() + caps, err := execdriver.TweakCapabilities(container.Capabilities, adds, drops) + var newCaps []string + for _, cap := range caps { + newCaps = append(newCaps, strings.ToLower(cap)) + } + if err != nil { + return []string{} + } + return newCaps +} + func isDirectory(source string) string { f, err := os.Stat(source) if err != nil { @@ -152,6 +185,16 @@ func getLabel(c map[string][]string, name string) string { return "" } +func getHostname(env []string) string { + for _, kv := range env { + parts := strings.SplitN(kv, "=", 2) + if parts[0] == "HOSTNAME" && len(parts) == 2 { + return parts[1] + } + } + return "" +} + func init() { var err error funcMap := template.FuncMap{ @@ -159,6 +202,8 @@ func init() { "escapeFstabSpaces": escapeFstabSpaces, "formatMountLabel": label.FormatMountLabel, "isDirectory": isDirectory, + "keepCapabilities": keepCapabilities, + "getHostname": getHostname, } LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate) if err != nil { diff --git a/daemon/execdriver/lxc/lxc_template_unit_test.go b/daemon/execdriver/lxc/lxc_template_unit_test.go index e76d5e9d03..77435114fd 100644 --- a/daemon/execdriver/lxc/lxc_template_unit_test.go +++ b/daemon/execdriver/lxc/lxc_template_unit_test.go @@ -14,6 +14,7 @@ import ( "time" "github.com/docker/docker/daemon/execdriver" + nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template" "github.com/docker/libcontainer/devices" ) @@ -104,6 +105,10 @@ func TestCustomLxcConfig(t *testing.T) { } func grepFile(t *testing.T, path string, pattern string) { + grepFileWithReverse(t, path, pattern, false) +} + +func grepFileWithReverse(t *testing.T, path string, pattern string, inverseGrep bool) { f, err := os.Open(path) if err != nil { t.Fatal(err) @@ -117,9 +122,15 @@ func grepFile(t *testing.T, path string, pattern string) { for err == nil { line, err = r.ReadString('\n') if strings.Contains(line, pattern) == true { + if inverseGrep { + t.Fatalf("grepFile: pattern \"%s\" found in \"%s\"", pattern, path) + } return } } + if inverseGrep { + return + } t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path) } @@ -228,3 +239,64 @@ func TestCustomLxcConfigMounts(t *testing.T) { grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,ro,create=%s 0 0", tempDir, "/"+tempDir, "dir")) grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,rw,create=%s 0 0", tempFile.Name(), "/"+tempFile.Name(), "file")) } + +func TestCustomLxcConfigMisc(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) + } + processConfig := execdriver.ProcessConfig{ + Privileged: false, + } + + processConfig.Env = []string{"HOSTNAME=testhost"} + command := &execdriver.Command{ + ID: "1", + LxcConfig: []string{ + "lxc.cgroup.cpuset.cpus = 0,1", + }, + Network: &execdriver.Network{ + Mtu: 1500, + Interface: &execdriver.NetworkInterface{ + Gateway: "10.10.10.1", + IPAddress: "10.10.10.10", + IPPrefixLen: 24, + Bridge: "docker0", + }, + }, + ProcessConfig: processConfig, + CapAdd: []string{"net_admin", "syslog"}, + CapDrop: []string{"kill", "mknod"}, + } + + p, err := driver.generateLXCConfig(command) + if err != nil { + t.Fatal(err) + } + // network + grepFile(t, p, "lxc.network.type = veth") + grepFile(t, p, "lxc.network.link = docker0") + grepFile(t, p, "lxc.network.name = eth0") + grepFile(t, p, "lxc.network.ipv4 = 10.10.10.10/24") + grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1") + grepFile(t, p, "lxc.network.flags = up") + + // hostname + grepFile(t, p, "lxc.utsname = testhost") + grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1") + container := nativeTemplate.New() + for _, cap := range container.Capabilities { + cap = strings.ToLower(cap) + if cap != "mknod" && cap != "kill" { + grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", cap)) + } + } + grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = kill"), true) + grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = mknod"), true) +}