Add --opt arguments for drivers

In order to handle special configuration for different drivers we
make the Config field a map to string array. This lets
us use it for lxc, by using the "lxc" key for those, and we can
later extend it easily for other backend-specific options.

Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
This commit is contained in:
Alexander Larsson 2014-03-13 17:03:09 +01:00
Родитель be5c65c2a2
Коммит 7a3070a600
11 изменённых файлов: 104 добавлений и 51 удалений

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

@ -3,21 +3,18 @@ package runconfig
import (
"github.com/dotcloud/docker/engine"
"github.com/dotcloud/docker/nat"
"github.com/dotcloud/docker/utils"
)
type HostConfig struct {
Binds []string
ContainerIDFile string
LxcConf []KeyValuePair
LxcConf []utils.KeyValuePair
Privileged bool
PortBindings nat.PortMap
Links []string
PublishAllPorts bool
}
type KeyValuePair struct {
Key string
Value string
DriverOptions map[string][]string
}
func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
@ -28,6 +25,7 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
}
job.GetenvJson("LxcConf", &hostConfig.LxcConf)
job.GetenvJson("PortBindings", &hostConfig.PortBindings)
job.GetenvJson("DriverOptions", &hostConfig.DriverOptions)
if Binds := job.GetenvList("Binds"); Binds != nil {
hostConfig.Binds = Binds
}

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

@ -51,6 +51,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
flDnsSearch = opts.NewListOpts(opts.ValidateDomain)
flVolumesFrom opts.ListOpts
flLxcOpts opts.ListOpts
flDriverOpts opts.ListOpts
flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: Run container in the background, print new container id")
@ -83,7 +84,8 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
cmd.Var(&flDns, []string{"#dns", "-dns"}, "Set custom dns servers")
cmd.Var(&flDnsSearch, []string{"-dns-search"}, "Set custom dns search domains")
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "(lxc exec-driver only) Add custom lxc options --lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
cmd.Var(&flLxcOpts, []string{"#lxc-conf", "#-lxc-conf"}, "(lxc exec-driver only) Add custom lxc options --lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
cmd.Var(&flDriverOpts, []string{"o", "-opt"}, "Add custom driver options")
if err := cmd.Parse(args); err != nil {
return nil, nil, cmd, err
@ -166,7 +168,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
mountLabel = mLabel
}
lxcConf, err := parseLxcConfOpts(flLxcOpts)
lxcConf, err := parseKeyValueOpts(flLxcOpts)
if err != nil {
return nil, nil, cmd, err
}
@ -226,6 +228,11 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
},
}
driverOptions, err := parseDriverOpts(flDriverOpts)
if err != nil {
return nil, nil, cmd, err
}
hostConfig := &HostConfig{
Binds: binds,
ContainerIDFile: *flContainerIDFile,
@ -234,6 +241,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
PortBindings: portBindings,
Links: flLinks.GetAll(),
PublishAllPorts: *flPublishAll,
DriverOptions: driverOptions,
}
if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit {
@ -248,22 +256,31 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
return config, hostConfig, cmd, nil
}
func parseLxcConfOpts(opts opts.ListOpts) ([]KeyValuePair, error) {
out := make([]KeyValuePair, opts.Len())
for i, o := range opts.GetAll() {
k, v, err := parseLxcOpt(o)
if err != nil {
return nil, err
// options will come in the format of name.key=value or name.option
func parseDriverOpts(opts opts.ListOpts) (map[string][]string, error) {
out := make(map[string][]string, len(opts.GetAll()))
for _, o := range opts.GetAll() {
parts := strings.SplitN(o, ".", 2)
if len(parts) < 2 {
return nil, fmt.Errorf("invalid opt format %s", o)
}
out[i] = KeyValuePair{Key: k, Value: v}
values, exists := out[parts[0]]
if !exists {
values = []string{}
}
out[parts[0]] = append(values, parts[1])
}
return out, nil
}
func parseLxcOpt(opt string) (string, string, error) {
parts := strings.SplitN(opt, "=", 2)
if len(parts) != 2 {
return "", "", fmt.Errorf("Unable to parse lxc conf option: %s", opt)
func parseKeyValueOpts(opts opts.ListOpts) ([]utils.KeyValuePair, error) {
out := make([]utils.KeyValuePair, opts.Len())
for i, o := range opts.GetAll() {
k, v, err := utils.ParseKeyValueOpt(o)
if err != nil {
return nil, err
}
out[i] = utils.KeyValuePair{Key: k, Value: v}
}
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
return out, nil
}

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

@ -1,6 +1,7 @@
package runconfig
import (
"github.com/dotcloud/docker/utils"
"testing"
)
@ -8,7 +9,7 @@ func TestParseLxcConfOpt(t *testing.T) {
opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
for _, o := range opts {
k, v, err := parseLxcOpt(o)
k, v, err := utils.ParseKeyValueOpt(o)
if err != nil {
t.FailNow()
}

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

@ -361,9 +361,13 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
func populateCommand(c *Container) {
var (
en *execdriver.Network
driverConfig []string
driverConfig = c.hostConfig.DriverOptions
)
if driverConfig == nil {
driverConfig = make(map[string][]string)
}
en = &execdriver.Network{
Mtu: c.runtime.config.Mtu,
Interface: nil,
@ -379,11 +383,9 @@ func populateCommand(c *Container) {
}
}
if lxcConf := c.hostConfig.LxcConf; lxcConf != nil {
for _, pair := range lxcConf {
driverConfig = append(driverConfig, fmt.Sprintf("%s = %s", pair.Key, pair.Value))
}
}
// TODO: this can be removed after lxc-conf is fully deprecated
mergeLxcConfIntoOptions(c.hostConfig, driverConfig)
resources := &execdriver.Resources{
Memory: c.Config.Memory,
MemorySwap: c.Config.MemorySwap,

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

@ -116,21 +116,21 @@ type Mount struct {
type Command struct {
exec.Cmd `json:"-"`
ID string `json:"id"`
Privileged bool `json:"privileged"`
User string `json:"user"`
Rootfs string `json:"rootfs"` // root fs of the container
InitPath string `json:"initpath"` // dockerinit
Entrypoint string `json:"entrypoint"`
Arguments []string `json:"arguments"`
WorkingDir string `json:"working_dir"`
ConfigPath string `json:"config_path"` // this should be able to be removed when the lxc template is moved into the driver
Context Context `json:"context"` // generic context for specific options (apparmor, selinux)
Tty bool `json:"tty"`
Network *Network `json:"network"`
Config []string `json:"config"` // generic values that specific drivers can consume
Resources *Resources `json:"resources"`
Mounts []Mount `json:"mounts"`
ID string `json:"id"`
Privileged bool `json:"privileged"`
User string `json:"user"`
Rootfs string `json:"rootfs"` // root fs of the container
InitPath string `json:"initpath"` // dockerinit
Entrypoint string `json:"entrypoint"`
Arguments []string `json:"arguments"`
WorkingDir string `json:"working_dir"`
ConfigPath string `json:"config_path"` // this should be able to be removed when the lxc template is moved into the driver
Context Context `json:"context"` // generic context for specific options (apparmor, selinux)
Tty bool `json:"tty"`
Network *Network `json:"network"`
Config map[string][]string `json:"config"` // generic values that specific drivers can consume
Resources *Resources `json:"resources"`
Mounts []Mount `json:"mounts"`
Terminal Terminal `json:"-"` // standard or tty terminal
Console string `json:"-"` // dev/console path

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

@ -123,8 +123,8 @@ lxc.cgroup.cpu.shares = {{.Resources.CpuShares}}
{{end}}
{{end}}
{{if .Config}}
{{range $value := .Config}}
{{if .Config.lxc}}
{{range $value := .Config.lxc}}
{{$value}}
{{end}}
{{end}}

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

@ -75,9 +75,11 @@ func TestCustomLxcConfig(t *testing.T) {
command := &execdriver.Command{
ID: "1",
Privileged: false,
Config: []string{
"lxc.utsname = docker",
"lxc.cgroup.cpuset.cpus = 0,1",
Config: map[string][]string{
"lxc": {
"lxc.utsname = docker",
"lxc.cgroup.cpuset.cpus = 0,1",
},
},
Network: &execdriver.Network{
Mtu: 1500,

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

@ -58,6 +58,7 @@ func createContainer(c *execdriver.Command) *libcontainer.Container {
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") != ""

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

@ -184,10 +184,9 @@ func (d *driver) removeContainerRoot(id string) error {
func (d *driver) validateCommand(c *execdriver.Command) error {
// we need to check the Config of the command to make sure that we
// do not have any of the lxc-conf variables
for _, conf := range c.Config {
if strings.Contains(conf, "lxc") {
return fmt.Errorf("%s is not supported by the native driver", conf)
}
lxc := c.Config["lxc"]
if lxc != nil && len(lxc) > 0 {
return fmt.Errorf("lxc config options are not supported by the native driver")
}
return nil
}

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

@ -1,9 +1,11 @@
package runtime
import (
"fmt"
"github.com/dotcloud/docker/nat"
"github.com/dotcloud/docker/pkg/namesgenerator"
"github.com/dotcloud/docker/runconfig"
"strings"
)
func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostConfig) error {
@ -30,6 +32,24 @@ func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostCon
return nil
}
func mergeLxcConfIntoOptions(hostConfig *runconfig.HostConfig, driverConfig map[string][]string) {
if hostConfig == nil {
return
}
// merge in the lxc conf options into the generic config map
if lxcConf := hostConfig.LxcConf; lxcConf != nil {
lxc := driverConfig["lxc"]
for _, pair := range lxcConf {
// because lxc conf gets the driver name lxc.XXXX we need to trim it off
// and let the lxc driver add it back later if needed
parts := strings.SplitN(pair.Key, ".", 2)
lxc = append(lxc, fmt.Sprintf("%s=%s", parts[1], pair.Value))
}
driverConfig["lxc"] = lxc
}
}
type checker struct {
runtime *Runtime
}

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

@ -25,6 +25,11 @@ import (
"time"
)
type KeyValuePair struct {
Key string
Value string
}
// A common interface to access the Fatal method of
// both testing.B and testing.T.
type Fataler interface {
@ -1071,3 +1076,11 @@ func ReadSymlinkedDirectory(path string) (string, error) {
}
return realPath, nil
}
func ParseKeyValueOpt(opt string) (string, string, error) {
parts := strings.SplitN(opt, "=", 2)
if len(parts) != 2 {
return "", "", fmt.Errorf("Unable to parse key/value option: %s", opt)
}
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
}