mirror of https://github.com/docker/docs.git
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:
parent
be5c65c2a2
commit
7a3070a600
|
@ -3,21 +3,18 @@ package runconfig
|
||||||
import (
|
import (
|
||||||
"github.com/dotcloud/docker/engine"
|
"github.com/dotcloud/docker/engine"
|
||||||
"github.com/dotcloud/docker/nat"
|
"github.com/dotcloud/docker/nat"
|
||||||
|
"github.com/dotcloud/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HostConfig struct {
|
type HostConfig struct {
|
||||||
Binds []string
|
Binds []string
|
||||||
ContainerIDFile string
|
ContainerIDFile string
|
||||||
LxcConf []KeyValuePair
|
LxcConf []utils.KeyValuePair
|
||||||
Privileged bool
|
Privileged bool
|
||||||
PortBindings nat.PortMap
|
PortBindings nat.PortMap
|
||||||
Links []string
|
Links []string
|
||||||
PublishAllPorts bool
|
PublishAllPorts bool
|
||||||
}
|
DriverOptions map[string][]string
|
||||||
|
|
||||||
type KeyValuePair struct {
|
|
||||||
Key string
|
|
||||||
Value string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
||||||
|
@ -28,6 +25,7 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
||||||
}
|
}
|
||||||
job.GetenvJson("LxcConf", &hostConfig.LxcConf)
|
job.GetenvJson("LxcConf", &hostConfig.LxcConf)
|
||||||
job.GetenvJson("PortBindings", &hostConfig.PortBindings)
|
job.GetenvJson("PortBindings", &hostConfig.PortBindings)
|
||||||
|
job.GetenvJson("DriverOptions", &hostConfig.DriverOptions)
|
||||||
if Binds := job.GetenvList("Binds"); Binds != nil {
|
if Binds := job.GetenvList("Binds"); Binds != nil {
|
||||||
hostConfig.Binds = Binds
|
hostConfig.Binds = Binds
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
||||||
flDnsSearch = opts.NewListOpts(opts.ValidateDomain)
|
flDnsSearch = opts.NewListOpts(opts.ValidateDomain)
|
||||||
flVolumesFrom opts.ListOpts
|
flVolumesFrom opts.ListOpts
|
||||||
flLxcOpts 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)")
|
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")
|
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(&flDns, []string{"#dns", "-dns"}, "Set custom dns servers")
|
||||||
cmd.Var(&flDnsSearch, []string{"-dns-search"}, "Set custom dns search domains")
|
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(&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 {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil, nil, cmd, err
|
return nil, nil, cmd, err
|
||||||
|
@ -166,7 +168,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
||||||
mountLabel = mLabel
|
mountLabel = mLabel
|
||||||
}
|
}
|
||||||
|
|
||||||
lxcConf, err := parseLxcConfOpts(flLxcOpts)
|
lxcConf, err := parseKeyValueOpts(flLxcOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, cmd, err
|
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{
|
hostConfig := &HostConfig{
|
||||||
Binds: binds,
|
Binds: binds,
|
||||||
ContainerIDFile: *flContainerIDFile,
|
ContainerIDFile: *flContainerIDFile,
|
||||||
|
@ -234,6 +241,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
||||||
PortBindings: portBindings,
|
PortBindings: portBindings,
|
||||||
Links: flLinks.GetAll(),
|
Links: flLinks.GetAll(),
|
||||||
PublishAllPorts: *flPublishAll,
|
PublishAllPorts: *flPublishAll,
|
||||||
|
DriverOptions: driverOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit {
|
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
|
return config, hostConfig, cmd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLxcConfOpts(opts opts.ListOpts) ([]KeyValuePair, error) {
|
// options will come in the format of name.key=value or name.option
|
||||||
out := make([]KeyValuePair, opts.Len())
|
func parseDriverOpts(opts opts.ListOpts) (map[string][]string, error) {
|
||||||
for i, o := range opts.GetAll() {
|
out := make(map[string][]string, len(opts.GetAll()))
|
||||||
k, v, err := parseLxcOpt(o)
|
for _, o := range opts.GetAll() {
|
||||||
if err != nil {
|
parts := strings.SplitN(o, ".", 2)
|
||||||
return nil, err
|
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
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLxcOpt(opt string) (string, string, error) {
|
func parseKeyValueOpts(opts opts.ListOpts) ([]utils.KeyValuePair, error) {
|
||||||
parts := strings.SplitN(opt, "=", 2)
|
out := make([]utils.KeyValuePair, opts.Len())
|
||||||
if len(parts) != 2 {
|
for i, o := range opts.GetAll() {
|
||||||
return "", "", fmt.Errorf("Unable to parse lxc conf option: %s", opt)
|
k, v, err := utils.ParseKeyValueOpt(o)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
|
out[i] = utils.KeyValuePair{Key: k, Value: v}
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package runconfig
|
package runconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/dotcloud/docker/utils"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ func TestParseLxcConfOpt(t *testing.T) {
|
||||||
opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
|
opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
|
||||||
|
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
k, v, err := parseLxcOpt(o)
|
k, v, err := utils.ParseKeyValueOpt(o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
|
@ -361,9 +361,13 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
func populateCommand(c *Container) {
|
func populateCommand(c *Container) {
|
||||||
var (
|
var (
|
||||||
en *execdriver.Network
|
en *execdriver.Network
|
||||||
driverConfig []string
|
driverConfig = c.hostConfig.DriverOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if driverConfig == nil {
|
||||||
|
driverConfig = make(map[string][]string)
|
||||||
|
}
|
||||||
|
|
||||||
en = &execdriver.Network{
|
en = &execdriver.Network{
|
||||||
Mtu: c.runtime.config.Mtu,
|
Mtu: c.runtime.config.Mtu,
|
||||||
Interface: nil,
|
Interface: nil,
|
||||||
|
@ -379,11 +383,9 @@ func populateCommand(c *Container) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if lxcConf := c.hostConfig.LxcConf; lxcConf != nil {
|
// TODO: this can be removed after lxc-conf is fully deprecated
|
||||||
for _, pair := range lxcConf {
|
mergeLxcConfIntoOptions(c.hostConfig, driverConfig)
|
||||||
driverConfig = append(driverConfig, fmt.Sprintf("%s = %s", pair.Key, pair.Value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resources := &execdriver.Resources{
|
resources := &execdriver.Resources{
|
||||||
Memory: c.Config.Memory,
|
Memory: c.Config.Memory,
|
||||||
MemorySwap: c.Config.MemorySwap,
|
MemorySwap: c.Config.MemorySwap,
|
||||||
|
|
|
@ -128,7 +128,7 @@ type Command struct {
|
||||||
Context Context `json:"context"` // generic context for specific options (apparmor, selinux)
|
Context Context `json:"context"` // generic context for specific options (apparmor, selinux)
|
||||||
Tty bool `json:"tty"`
|
Tty bool `json:"tty"`
|
||||||
Network *Network `json:"network"`
|
Network *Network `json:"network"`
|
||||||
Config []string `json:"config"` // generic values that specific drivers can consume
|
Config map[string][]string `json:"config"` // generic values that specific drivers can consume
|
||||||
Resources *Resources `json:"resources"`
|
Resources *Resources `json:"resources"`
|
||||||
Mounts []Mount `json:"mounts"`
|
Mounts []Mount `json:"mounts"`
|
||||||
|
|
||||||
|
|
|
@ -123,8 +123,8 @@ lxc.cgroup.cpu.shares = {{.Resources.CpuShares}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .Config}}
|
{{if .Config.lxc}}
|
||||||
{{range $value := .Config}}
|
{{range $value := .Config.lxc}}
|
||||||
{{$value}}
|
{{$value}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -75,10 +75,12 @@ func TestCustomLxcConfig(t *testing.T) {
|
||||||
command := &execdriver.Command{
|
command := &execdriver.Command{
|
||||||
ID: "1",
|
ID: "1",
|
||||||
Privileged: false,
|
Privileged: false,
|
||||||
Config: []string{
|
Config: map[string][]string{
|
||||||
|
"lxc": {
|
||||||
"lxc.utsname = docker",
|
"lxc.utsname = docker",
|
||||||
"lxc.cgroup.cpuset.cpus = 0,1",
|
"lxc.cgroup.cpuset.cpus = 0,1",
|
||||||
},
|
},
|
||||||
|
},
|
||||||
Network: &execdriver.Network{
|
Network: &execdriver.Network{
|
||||||
Mtu: 1500,
|
Mtu: 1500,
|
||||||
Interface: nil,
|
Interface: nil,
|
||||||
|
|
|
@ -58,6 +58,7 @@ func createContainer(c *execdriver.Command) *libcontainer.Container {
|
||||||
container.Cgroups.Memory = c.Resources.Memory
|
container.Cgroups.Memory = c.Resources.Memory
|
||||||
container.Cgroups.MemorySwap = c.Resources.MemorySwap
|
container.Cgroups.MemorySwap = c.Resources.MemorySwap
|
||||||
}
|
}
|
||||||
|
|
||||||
// check to see if we are running in ramdisk to disable pivot root
|
// check to see if we are running in ramdisk to disable pivot root
|
||||||
container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
|
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 {
|
func (d *driver) validateCommand(c *execdriver.Command) error {
|
||||||
// we need to check the Config of the command to make sure that we
|
// we need to check the Config of the command to make sure that we
|
||||||
// do not have any of the lxc-conf variables
|
// do not have any of the lxc-conf variables
|
||||||
for _, conf := range c.Config {
|
lxc := c.Config["lxc"]
|
||||||
if strings.Contains(conf, "lxc") {
|
if lxc != nil && len(lxc) > 0 {
|
||||||
return fmt.Errorf("%s is not supported by the native driver", conf)
|
return fmt.Errorf("lxc config options are not supported by the native driver")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/dotcloud/docker/nat"
|
"github.com/dotcloud/docker/nat"
|
||||||
"github.com/dotcloud/docker/pkg/namesgenerator"
|
"github.com/dotcloud/docker/pkg/namesgenerator"
|
||||||
"github.com/dotcloud/docker/runconfig"
|
"github.com/dotcloud/docker/runconfig"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostConfig) error {
|
func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostConfig) error {
|
||||||
|
@ -30,6 +32,24 @@ func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostCon
|
||||||
return nil
|
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 {
|
type checker struct {
|
||||||
runtime *Runtime
|
runtime *Runtime
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type KeyValuePair struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
// A common interface to access the Fatal method of
|
// A common interface to access the Fatal method of
|
||||||
// both testing.B and testing.T.
|
// both testing.B and testing.T.
|
||||||
type Fataler interface {
|
type Fataler interface {
|
||||||
|
@ -1071,3 +1076,11 @@ func ReadSymlinkedDirectory(path string) (string, error) {
|
||||||
}
|
}
|
||||||
return realPath, nil
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue