Factor out the native driver config options

Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
Michael Crosby 2014-03-21 08:10:07 +00:00
Родитель be5538d8a8
Коммит 7c726669cb
8 изменённых файлов: 207 добавлений и 130 удалений

Просмотреть файл

@ -364,6 +364,10 @@ func populateCommand(c *Container) {
driverConfig = c.hostConfig.PluginOptions
)
if driverConfig == nil {
driverConfig = make(map[string][]string)
}
en = &execdriver.Network{
Mtu: c.runtime.config.Mtu,
Interface: nil,

Просмотреть файл

@ -0,0 +1,27 @@
package configuration
import (
"fmt"
"github.com/dotcloud/docker/pkg/libcontainer"
"strings"
)
// i.e: cap +MKNOD cap -NET_ADMIN
func parseCapOpt(container *libcontainer.Container, opts []string) error {
var (
value = strings.TrimSpace(opts[0])
c = container.CapabilitiesMask.Get(value[1:])
)
if c == nil {
return fmt.Errorf("%s is not a valid capability", value[1:])
}
switch value[0] {
case '-':
c.Enabled = false
case '+':
c.Enabled = true
default:
return fmt.Errorf("%c is not a valid modifier for capabilities", value[0])
}
return nil
}

Просмотреть файл

@ -0,0 +1,35 @@
package configuration
import (
"fmt"
"github.com/dotcloud/docker/pkg/libcontainer"
"os/exec"
"path/filepath"
"strings"
)
// i.e: net join <name>
func parseNetOpt(container *libcontainer.Container, running map[string]*exec.Cmd, opts []string) error {
opt := strings.TrimSpace(opts[1])
switch opt {
case "join":
var (
id = strings.TrimSpace(opts[2])
cmd = running[id]
)
if cmd == nil || cmd.Process == nil {
return fmt.Errorf("%s is not a valid running container to join", id)
}
nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
container.Networks = append(container.Networks, &libcontainer.Network{
Type: "netns",
Context: libcontainer.Context{
"nspath": nspath,
},
})
default:
return fmt.Errorf("%s is not a valid network option", opt)
}
return nil
}

Просмотреть файл

@ -0,0 +1,26 @@
package configuration
import (
"fmt"
"github.com/dotcloud/docker/pkg/libcontainer"
"strings"
)
func parseNsOpt(container *libcontainer.Container, opts []string) error {
var (
value = strings.TrimSpace(opts[0])
ns = container.Namespaces.Get(value[1:])
)
if ns == nil {
return fmt.Errorf("%s is not a valid namespace", value[1:])
}
switch value[0] {
case '-':
ns.Enabled = false
case '+':
ns.Enabled = true
default:
return fmt.Errorf("%c is not a valid modifier for namespaces", value[0])
}
return nil
}

Просмотреть файл

@ -0,0 +1,37 @@
package configuration
import (
"fmt"
"github.com/dotcloud/docker/pkg/libcontainer"
"os/exec"
"strings"
)
// configureCustomOptions takes string commands from the user and allows modification of the
// container's default configuration.
//
// format: <key> <...value>
// i.e: cgroup devices.allow *:*
func ParseConfiguration(container *libcontainer.Container, running map[string]*exec.Cmd, opts []string) error {
for _, opt := range opts {
var (
err error
parts = strings.Split(strings.TrimSpace(opt), " ")
)
switch parts[0] {
case "cap":
err = parseCapOpt(container, parts[1:])
case "ns":
err = parseNsOpt(container, parts[1:])
case "net":
err = parseNetOpt(container, running, parts[1:])
default:
return fmt.Errorf("%s is not a valid configuration option for the native driver", parts[0])
}
if err != nil {
return err
}
}
return nil
}

Просмотреть файл

@ -0,0 +1,70 @@
package native
import (
"fmt"
"github.com/dotcloud/docker/pkg/libcontainer"
"github.com/dotcloud/docker/runtime/execdriver"
"github.com/dotcloud/docker/runtime/execdriver/native/configuration"
"os"
)
// createContainer populates and configures the container type with the
// data provided by the execdriver.Command
func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Container, error) {
container := getDefaultTemplate()
container.Hostname = getEnv("HOSTNAME", c.Env)
container.Tty = c.Tty
container.User = c.User
container.WorkingDir = c.WorkingDir
container.Env = c.Env
loopbackNetwork := libcontainer.Network{
Mtu: c.Network.Mtu,
Address: fmt.Sprintf("%s/%d", "127.0.0.1", 0),
Gateway: "localhost",
Type: "loopback",
Context: libcontainer.Context{},
}
container.Networks = []*libcontainer.Network{
&loopbackNetwork,
}
if c.Network.Interface != nil {
vethNetwork := libcontainer.Network{
Mtu: c.Network.Mtu,
Address: fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
Gateway: c.Network.Interface.Gateway,
Type: "veth",
Context: libcontainer.Context{
"prefix": "veth",
"bridge": c.Network.Interface.Bridge,
},
}
container.Networks = append(container.Networks, &vethNetwork)
}
container.Cgroups.Name = c.ID
if c.Privileged {
container.CapabilitiesMask = nil
container.Cgroups.DeviceAccess = true
container.Context["apparmor_profile"] = "unconfined"
}
if c.Resources != nil {
container.Cgroups.CpuShares = c.Resources.CpuShares
container.Cgroups.Memory = c.Resources.Memory
container.Cgroups.MemorySwap = c.Resources.MemorySwap
}
// check to see if we are running in ramdisk to disable pivot root
container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
for _, m := range c.Mounts {
container.Mounts = append(container.Mounts, libcontainer.Mount{m.Source, m.Destination, m.Writable, m.Private})
}
if err := configuration.ParseConfiguration(container, d.activeContainers, c.Config["native"]); err != nil {
return nil, err
}
return container, nil
}

Просмотреть файл

@ -1,136 +1,10 @@
package native
import (
"fmt"
"github.com/dotcloud/docker/pkg/cgroups"
"github.com/dotcloud/docker/pkg/libcontainer"
"github.com/dotcloud/docker/runtime/execdriver"
"os"
"path/filepath"
"strings"
)
// createContainer populates and configures the container type with the
// data provided by the execdriver.Command
func (d *driver) createContainer(c *execdriver.Command) *libcontainer.Container {
container := getDefaultTemplate()
container.Hostname = getEnv("HOSTNAME", c.Env)
container.Tty = c.Tty
container.User = c.User
container.WorkingDir = c.WorkingDir
container.Env = c.Env
loopbackNetwork := libcontainer.Network{
Mtu: c.Network.Mtu,
Address: fmt.Sprintf("%s/%d", "127.0.0.1", 0),
Gateway: "localhost",
Type: "loopback",
Context: libcontainer.Context{},
}
container.Networks = []*libcontainer.Network{
&loopbackNetwork,
}
if c.Network.Interface != nil {
vethNetwork := libcontainer.Network{
Mtu: c.Network.Mtu,
Address: fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
Gateway: c.Network.Interface.Gateway,
Type: "veth",
Context: libcontainer.Context{
"prefix": "veth",
"bridge": c.Network.Interface.Bridge,
},
}
container.Networks = append(container.Networks, &vethNetwork)
}
container.Cgroups.Name = c.ID
if c.Privileged {
container.CapabilitiesMask = nil
container.Cgroups.DeviceAccess = true
container.Context["apparmor_profile"] = "unconfined"
}
if c.Resources != nil {
container.Cgroups.CpuShares = c.Resources.CpuShares
container.Cgroups.Memory = c.Resources.Memory
container.Cgroups.MemorySwap = c.Resources.MemorySwap
}
// check to see if we are running in ramdisk to disable pivot root
container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
for _, m := range c.Mounts {
container.Mounts = append(container.Mounts, libcontainer.Mount{m.Source, m.Destination, m.Writable, m.Private})
}
d.configureCustomOptions(container, c.Config["native"])
return container
}
// configureCustomOptions takes string commands from the user and allows modification of the
// container's default configuration.
//
// format: <key> <value>
// i.e: cap +MKNOD cap -NET_ADMIN
// i.e: cgroup devices.allow *:*
// i.e: net join <name>
func (d *driver) configureCustomOptions(container *libcontainer.Container, opts []string) {
for _, opt := range opts {
var (
parts = strings.Split(strings.TrimSpace(opt), " ")
value = strings.TrimSpace(parts[1])
)
switch parts[0] {
case "cap":
c := container.CapabilitiesMask.Get(value[1:])
if c == nil {
continue
}
switch value[0] {
case '-':
c.Enabled = false
case '+':
c.Enabled = true
default:
// do error here
}
case "ns":
ns := container.Namespaces.Get(value[1:])
switch value[0] {
case '-':
ns.Enabled = false
case '+':
ns.Enabled = true
default:
// error
}
case "net":
switch strings.TrimSpace(parts[1]) {
case "join":
var (
id = strings.TrimSpace(parts[2])
cmd = d.activeContainers[id]
nspath = filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
)
container.Networks = append(container.Networks, &libcontainer.Network{
Type: "netns",
Context: libcontainer.Context{
"nspath": nspath,
},
})
default:
// error
}
default:
// error not defined
}
}
}
// getDefaultTemplate returns the docker default for
// the libcontainer configuration file
func getDefaultTemplate() *libcontainer.Container {

Просмотреть файл

@ -59,7 +59,7 @@ func init() {
type driver struct {
root string
initPath string
activeContainers map[string]*execdriver.Command
activeContainers map[string]*exec.Cmd
}
func NewDriver(root, initPath string) (*driver, error) {
@ -72,16 +72,20 @@ func NewDriver(root, initPath string) (*driver, error) {
return &driver{
root: root,
initPath: initPath,
activeContainers: make(map[string]*execdriver.Command),
activeContainers: make(map[string]*exec.Cmd),
}, nil
}
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
d.activeContainers[c.ID] = c
// take the Command and populate the libcontainer.Container from it
container, err := d.createContainer(c)
if err != nil {
return -1, err
}
d.activeContainers[c.ID] = &c.Cmd
var (
term nsinit.Terminal
container = d.createContainer(c)
factory = &dockerCommandFactory{c: c, driver: d}
stateWriter = &dockerStateWriter{
callback: startCallback,