mirror of https://github.com/docker/docs.git
Merge pull request #1560 from dotcloud/439-allow-lxc-args
Add lxc-conf flag to allow custom lxc options
This commit is contained in:
commit
a3510c99f1
27
container.go
27
container.go
|
@ -86,6 +86,7 @@ type Config struct {
|
||||||
type HostConfig struct {
|
type HostConfig struct {
|
||||||
Binds []string
|
Binds []string
|
||||||
ContainerIDFile string
|
ContainerIDFile string
|
||||||
|
LxcConf []KeyValuePair
|
||||||
}
|
}
|
||||||
|
|
||||||
type BindMap struct {
|
type BindMap struct {
|
||||||
|
@ -98,6 +99,11 @@ var (
|
||||||
ErrInvaidWorikingDirectory = errors.New("The working directory is invalid. It needs to be an absolute path.")
|
ErrInvaidWorikingDirectory = errors.New("The working directory is invalid. It needs to be an absolute path.")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type KeyValuePair struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, *flag.FlagSet, error) {
|
func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, *flag.FlagSet, error) {
|
||||||
cmd := Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container")
|
cmd := Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container")
|
||||||
if len(args) > 0 && args[0] != "--help" {
|
if len(args) > 0 && args[0] != "--help" {
|
||||||
|
@ -140,6 +146,9 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
|
||||||
flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
|
flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
|
||||||
flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
|
flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
|
||||||
|
|
||||||
|
var flLxcOpts ListOpts
|
||||||
|
cmd.Var(&flLxcOpts, "lxc-conf", "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
|
||||||
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil, nil, cmd, err
|
return nil, nil, cmd, err
|
||||||
}
|
}
|
||||||
|
@ -187,6 +196,12 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
|
||||||
entrypoint = []string{*flEntrypoint}
|
entrypoint = []string{*flEntrypoint}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lxcConf []KeyValuePair
|
||||||
|
lxcConf, err := parseLxcConfOpts(flLxcOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, cmd, err
|
||||||
|
}
|
||||||
|
|
||||||
config := &Config{
|
config := &Config{
|
||||||
Hostname: *flHostname,
|
Hostname: *flHostname,
|
||||||
PortSpecs: flPorts,
|
PortSpecs: flPorts,
|
||||||
|
@ -212,6 +227,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
|
||||||
hostConfig := &HostConfig{
|
hostConfig := &HostConfig{
|
||||||
Binds: binds,
|
Binds: binds,
|
||||||
ContainerIDFile: *flContainerIDFile,
|
ContainerIDFile: *flContainerIDFile,
|
||||||
|
LxcConf: lxcConf,
|
||||||
}
|
}
|
||||||
|
|
||||||
if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
|
if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
|
||||||
|
@ -315,7 +331,7 @@ func (container *Container) SaveHostConfig(hostConfig *HostConfig) (err error) {
|
||||||
return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
|
return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) generateLXCConfig() error {
|
func (container *Container) generateLXCConfig(hostConfig *HostConfig) error {
|
||||||
fo, err := os.Create(container.lxcConfigPath())
|
fo, err := os.Create(container.lxcConfigPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -324,6 +340,11 @@ func (container *Container) generateLXCConfig() error {
|
||||||
if err := LxcTemplateCompiled.Execute(fo, container); err != nil {
|
if err := LxcTemplateCompiled.Execute(fo, container); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if hostConfig != nil {
|
||||||
|
if err := LxcHostConfigTemplateCompiled.Execute(fo, hostConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,7 +541,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||||
container.State.Lock()
|
container.State.Lock()
|
||||||
defer container.State.Unlock()
|
defer container.State.Unlock()
|
||||||
|
|
||||||
if len(hostConfig.Binds) == 0 {
|
if len(hostConfig.Binds) == 0 && len(hostConfig.LxcConf) == 0 {
|
||||||
hostConfig, _ = container.ReadHostConfig()
|
hostConfig, _ = container.ReadHostConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,7 +666,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.generateLXCConfig(); err != nil {
|
if err := container.generateLXCConfig(hostConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1070,7 +1070,7 @@ func TestLXCConfig(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer runtime.Destroy(container)
|
defer runtime.Destroy(container)
|
||||||
container.generateLXCConfig()
|
container.generateLXCConfig(nil)
|
||||||
grepFile(t, container.lxcConfigPath(), "lxc.utsname = foobar")
|
grepFile(t, container.lxcConfigPath(), "lxc.utsname = foobar")
|
||||||
grepFile(t, container.lxcConfigPath(),
|
grepFile(t, container.lxcConfigPath(),
|
||||||
fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
|
fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
|
||||||
|
@ -1078,6 +1078,36 @@ func TestLXCConfig(t *testing.T) {
|
||||||
fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2))
|
fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCustomLxcConfig(t *testing.T) {
|
||||||
|
runtime := mkRuntime(t)
|
||||||
|
defer nuke(runtime)
|
||||||
|
container, err := NewBuilder(runtime).Create(&Config{
|
||||||
|
Image: GetTestImage(runtime).ID,
|
||||||
|
Cmd: []string{"/bin/true"},
|
||||||
|
|
||||||
|
Hostname: "foobar",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer runtime.Destroy(container)
|
||||||
|
hostConfig := &HostConfig{LxcConf: []KeyValuePair{
|
||||||
|
{
|
||||||
|
Key: "lxc.utsname",
|
||||||
|
Value: "docker",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "lxc.cgroup.cpuset.cpus",
|
||||||
|
Value: "0,1",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
container.generateLXCConfig(hostConfig)
|
||||||
|
grepFile(t, container.lxcConfigPath(), "lxc.utsname = docker")
|
||||||
|
grepFile(t, container.lxcConfigPath(), "lxc.cgroup.cpuset.cpus = 0,1")
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkRunSequencial(b *testing.B) {
|
func BenchmarkRunSequencial(b *testing.B) {
|
||||||
runtime := mkRuntime(b)
|
runtime := mkRuntime(b)
|
||||||
defer nuke(runtime)
|
defer nuke(runtime)
|
||||||
|
|
|
@ -356,7 +356,8 @@ Start a container
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"Binds":["/tmp:/tmp"]
|
"Binds":["/tmp:/tmp"],
|
||||||
|
"LxcConf":{"lxc.utsname":"docker"}
|
||||||
}
|
}
|
||||||
|
|
||||||
**Example response**:
|
**Example response**:
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
-volumes-from="": Mount all volumes from the given container.
|
-volumes-from="": Mount all volumes from the given container.
|
||||||
-entrypoint="": Overwrite the default entrypoint set by the image.
|
-entrypoint="": Overwrite the default entrypoint set by the image.
|
||||||
-w="": Working directory inside the container
|
-w="": Working directory inside the container
|
||||||
|
-lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -121,7 +121,16 @@ lxc.cgroup.cpu.shares = {{.Config.CpuShares}}
|
||||||
{{end}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const LxcHostConfigTemplate = `
|
||||||
|
{{if .LxcConf}}
|
||||||
|
{{range $pair := .LxcConf}}
|
||||||
|
{{$pair.Key}} = {{$pair.Value}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
|
||||||
var LxcTemplateCompiled *template.Template
|
var LxcTemplateCompiled *template.Template
|
||||||
|
var LxcHostConfigTemplateCompiled *template.Template
|
||||||
|
|
||||||
func getMemorySwap(config *Config) int64 {
|
func getMemorySwap(config *Config) int64 {
|
||||||
// By default, MemorySwap is set to twice the size of RAM.
|
// By default, MemorySwap is set to twice the size of RAM.
|
||||||
|
@ -141,4 +150,8 @@ func init() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
LxcHostConfigTemplateCompiled, err = template.New("lxc-hostconfig").Funcs(funcMap).Parse(LxcHostConfigTemplate)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
21
utils.go
21
utils.go
|
@ -1,6 +1,7 @@
|
||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -146,3 +147,23 @@ func MergeConfig(userConf, imageConf *Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseLxcConfOpts(opts ListOpts) ([]KeyValuePair, error) {
|
||||||
|
out := make([]KeyValuePair, len(opts))
|
||||||
|
for i, o := range opts {
|
||||||
|
k, v, err := parseLxcOpt(o)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out[i] = KeyValuePair{Key: k, Value: v}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
|
||||||
|
}
|
||||||
|
|
|
@ -301,3 +301,20 @@ func TestMergeConfigPublicPortNotHonored(t *testing.T) {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseLxcConfOpt(t *testing.T) {
|
||||||
|
opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
|
||||||
|
|
||||||
|
for _, o := range opts {
|
||||||
|
k, v, err := parseLxcOpt(o)
|
||||||
|
if err != nil {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if k != "lxc.utsname" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if v != "docker" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue