mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #4085 from shykes/separate-config-hostconfig
Move canonical run configuration objects to a sub-package
This commit is contained in:
commit
d3c084beee
23 changed files with 731 additions and 674 deletions
11
buildfile.go
11
buildfile.go
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/dotcloud/docker/archive"
|
||||
"github.com/dotcloud/docker/auth"
|
||||
"github.com/dotcloud/docker/registry"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -38,7 +39,7 @@ type buildFile struct {
|
|||
|
||||
image string
|
||||
maintainer string
|
||||
config *Config
|
||||
config *runconfig.Config
|
||||
|
||||
contextPath string
|
||||
context *utils.TarSum
|
||||
|
@ -101,7 +102,7 @@ func (b *buildFile) CmdFrom(name string) error {
|
|||
}
|
||||
}
|
||||
b.image = image.ID
|
||||
b.config = &Config{}
|
||||
b.config = &runconfig.Config{}
|
||||
if image.Config != nil {
|
||||
b.config = image.Config
|
||||
}
|
||||
|
@ -158,14 +159,14 @@ func (b *buildFile) CmdRun(args string) error {
|
|||
if b.image == "" {
|
||||
return fmt.Errorf("Please provide a source image with `from` prior to run")
|
||||
}
|
||||
config, _, _, err := ParseRun(append([]string{b.image}, b.buildCmdFromJson(args)...), nil)
|
||||
config, _, _, err := runconfig.Parse(append([]string{b.image}, b.buildCmdFromJson(args)...), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := b.config.Cmd
|
||||
b.config.Cmd = nil
|
||||
MergeConfig(b.config, config)
|
||||
runconfig.Merge(b.config, config)
|
||||
|
||||
defer func(cmd []string) { b.config.Cmd = cmd }(cmd)
|
||||
|
||||
|
@ -742,7 +743,7 @@ func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeC
|
|||
return &buildFile{
|
||||
runtime: srv.runtime,
|
||||
srv: srv,
|
||||
config: &Config{},
|
||||
config: &runconfig.Config{},
|
||||
outStream: outStream,
|
||||
errStream: errStream,
|
||||
tmpContainers: make(map[string]struct{}),
|
||||
|
|
212
commands.go
212
commands.go
|
@ -15,10 +15,9 @@ import (
|
|||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
flag "github.com/dotcloud/docker/pkg/mflag"
|
||||
"github.com/dotcloud/docker/pkg/opts"
|
||||
"github.com/dotcloud/docker/pkg/sysinfo"
|
||||
"github.com/dotcloud/docker/pkg/term"
|
||||
"github.com/dotcloud/docker/registry"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -1449,11 +1448,11 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
|
|||
v.Set("comment", *flComment)
|
||||
v.Set("author", *flAuthor)
|
||||
var (
|
||||
config *Config
|
||||
config *runconfig.Config
|
||||
env engine.Env
|
||||
)
|
||||
if *flConfig != "" {
|
||||
config = &Config{}
|
||||
config = &runconfig.Config{}
|
||||
if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1743,210 +1742,9 @@ func (cli *DockerCli) CmdTag(args ...string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//FIXME Only used in tests
|
||||
func ParseRun(args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
||||
cmd := flag.NewFlagSet("run", flag.ContinueOnError)
|
||||
cmd.SetOutput(ioutil.Discard)
|
||||
cmd.Usage = nil
|
||||
return parseRun(cmd, args, sysInfo)
|
||||
}
|
||||
|
||||
func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
||||
var (
|
||||
// FIXME: use utils.ListOpts for attach and volumes?
|
||||
flAttach = opts.NewListOpts(opts.ValidateAttach)
|
||||
flVolumes = opts.NewListOpts(opts.ValidatePath)
|
||||
flLinks = opts.NewListOpts(opts.ValidateLink)
|
||||
flEnv = opts.NewListOpts(opts.ValidateEnv)
|
||||
|
||||
flPublish opts.ListOpts
|
||||
flExpose opts.ListOpts
|
||||
flDns opts.ListOpts
|
||||
flVolumesFrom opts.ListOpts
|
||||
flLxcOpts 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")
|
||||
flNetwork = cmd.Bool([]string{"n", "-networking"}, true, "Enable networking for this container")
|
||||
flPrivileged = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
|
||||
flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to the host interfaces")
|
||||
flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep stdin open even if not attached")
|
||||
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-tty")
|
||||
flContainerIDFile = cmd.String([]string{"#cidfile", "-cidfile"}, "", "Write the container ID to the file")
|
||||
flEntrypoint = cmd.String([]string{"#entrypoint", "-entrypoint"}, "", "Overwrite the default entrypoint of the image")
|
||||
flHostname = cmd.String([]string{"h", "-hostname"}, "", "Container host name")
|
||||
flMemoryString = cmd.String([]string{"m", "-memory"}, "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")
|
||||
flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID")
|
||||
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
||||
flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
|
||||
|
||||
// For documentation purpose
|
||||
_ = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
|
||||
_ = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
|
||||
)
|
||||
|
||||
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to stdin, stdout or stderr.")
|
||||
cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
|
||||
cmd.Var(&flLinks, []string{"#link", "-link"}, "Add link to another container (name:alias)")
|
||||
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
||||
|
||||
cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", nat.PortSpecTemplateFormat))
|
||||
cmd.Var(&flExpose, []string{"#expose", "-expose"}, "Expose a port from the container without publishing it to your host")
|
||||
cmd.Var(&flDns, []string{"#dns", "-dns"}, "Set custom dns servers")
|
||||
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
|
||||
cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
|
||||
// Check if the kernel supports memory limit cgroup.
|
||||
if sysInfo != nil && *flMemoryString != "" && !sysInfo.MemoryLimit {
|
||||
*flMemoryString = ""
|
||||
}
|
||||
|
||||
// Validate input params
|
||||
if *flDetach && flAttach.Len() > 0 {
|
||||
return nil, nil, cmd, ErrConflictAttachDetach
|
||||
}
|
||||
if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) {
|
||||
return nil, nil, cmd, ErrInvalidWorikingDirectory
|
||||
}
|
||||
if *flDetach && *flAutoRemove {
|
||||
return nil, nil, cmd, ErrConflictDetachAutoRemove
|
||||
}
|
||||
|
||||
// If neither -d or -a are set, attach to everything by default
|
||||
if flAttach.Len() == 0 && !*flDetach {
|
||||
if !*flDetach {
|
||||
flAttach.Set("stdout")
|
||||
flAttach.Set("stderr")
|
||||
if *flStdin {
|
||||
flAttach.Set("stdin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var flMemory int64
|
||||
if *flMemoryString != "" {
|
||||
parsedMemory, err := utils.RAMInBytes(*flMemoryString)
|
||||
if err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
flMemory = parsedMemory
|
||||
}
|
||||
|
||||
var binds []string
|
||||
// add any bind targets to the list of container volumes
|
||||
for bind := range flVolumes.GetMap() {
|
||||
if arr := strings.Split(bind, ":"); len(arr) > 1 {
|
||||
if arr[0] == "/" {
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid bind mount: source can't be '/'")
|
||||
}
|
||||
dstDir := arr[1]
|
||||
flVolumes.Set(dstDir)
|
||||
binds = append(binds, bind)
|
||||
flVolumes.Delete(bind)
|
||||
} else if bind == "/" {
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid volume: path can't be '/'")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
parsedArgs = cmd.Args()
|
||||
runCmd []string
|
||||
entrypoint []string
|
||||
image string
|
||||
)
|
||||
if len(parsedArgs) >= 1 {
|
||||
image = cmd.Arg(0)
|
||||
}
|
||||
if len(parsedArgs) > 1 {
|
||||
runCmd = parsedArgs[1:]
|
||||
}
|
||||
if *flEntrypoint != "" {
|
||||
entrypoint = []string{*flEntrypoint}
|
||||
}
|
||||
|
||||
lxcConf, err := parseLxcConfOpts(flLxcOpts)
|
||||
if err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
|
||||
var (
|
||||
domainname string
|
||||
hostname = *flHostname
|
||||
parts = strings.SplitN(hostname, ".", 2)
|
||||
)
|
||||
if len(parts) > 1 {
|
||||
hostname = parts[0]
|
||||
domainname = parts[1]
|
||||
}
|
||||
|
||||
ports, portBindings, err := nat.ParsePortSpecs(flPublish.GetAll())
|
||||
if err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
|
||||
// Merge in exposed ports to the map of published ports
|
||||
for _, e := range flExpose.GetAll() {
|
||||
if strings.Contains(e, ":") {
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid port format for --expose: %s", e)
|
||||
}
|
||||
p := nat.NewPort(nat.SplitProtoPort(e))
|
||||
if _, exists := ports[p]; !exists {
|
||||
ports[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
config := &Config{
|
||||
Hostname: hostname,
|
||||
Domainname: domainname,
|
||||
PortSpecs: nil, // Deprecated
|
||||
ExposedPorts: ports,
|
||||
User: *flUser,
|
||||
Tty: *flTty,
|
||||
NetworkDisabled: !*flNetwork,
|
||||
OpenStdin: *flStdin,
|
||||
Memory: flMemory,
|
||||
CpuShares: *flCpuShares,
|
||||
AttachStdin: flAttach.Get("stdin"),
|
||||
AttachStdout: flAttach.Get("stdout"),
|
||||
AttachStderr: flAttach.Get("stderr"),
|
||||
Env: flEnv.GetAll(),
|
||||
Cmd: runCmd,
|
||||
Dns: flDns.GetAll(),
|
||||
Image: image,
|
||||
Volumes: flVolumes.GetMap(),
|
||||
VolumesFrom: strings.Join(flVolumesFrom.GetAll(), ","),
|
||||
Entrypoint: entrypoint,
|
||||
WorkingDir: *flWorkingDir,
|
||||
}
|
||||
|
||||
hostConfig := &HostConfig{
|
||||
Binds: binds,
|
||||
ContainerIDFile: *flContainerIDFile,
|
||||
LxcConf: lxcConf,
|
||||
Privileged: *flPrivileged,
|
||||
PortBindings: portBindings,
|
||||
Links: flLinks.GetAll(),
|
||||
PublishAllPorts: *flPublishAll,
|
||||
}
|
||||
|
||||
if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit {
|
||||
//fmt.Fprintf(stdout, "WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
||||
config.MemorySwap = -1
|
||||
}
|
||||
|
||||
// When allocating stdin in attached mode, close stdin at client disconnect
|
||||
if config.OpenStdin && config.AttachStdin {
|
||||
config.StdinOnce = true
|
||||
}
|
||||
return config, hostConfig, cmd, nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) CmdRun(args ...string) error {
|
||||
config, hostConfig, cmd, err := parseRun(cli.Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container"), args, nil)
|
||||
// FIXME: just use runconfig.Parse already
|
||||
config, hostConfig, cmd, err := runconfig.ParseSubcommand(cli.Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container"), args, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func parse(t *testing.T, args string) (*Config, *HostConfig, error) {
|
||||
config, hostConfig, _, err := ParseRun(strings.Split(args+" ubuntu bash", " "), nil)
|
||||
func parse(t *testing.T, args string) (*runconfig.Config, *runconfig.HostConfig, error) {
|
||||
config, hostConfig, _, err := runconfig.Parse(strings.Split(args+" ubuntu bash", " "), nil)
|
||||
return config, hostConfig, err
|
||||
}
|
||||
|
||||
func mustParse(t *testing.T, args string) (*Config, *HostConfig) {
|
||||
func mustParse(t *testing.T, args string) (*runconfig.Config, *runconfig.HostConfig) {
|
||||
config, hostConfig, err := parse(t, args)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
117
container.go
117
container.go
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/pkg/mount"
|
||||
"github.com/dotcloud/docker/pkg/term"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"github.com/kr/pty"
|
||||
"io"
|
||||
|
@ -42,7 +43,7 @@ type Container struct {
|
|||
Path string
|
||||
Args []string
|
||||
|
||||
Config *Config
|
||||
Config *runconfig.Config
|
||||
State State
|
||||
Image string
|
||||
|
||||
|
@ -68,109 +69,11 @@ type Container struct {
|
|||
// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
|
||||
// Easier than migrating older container configs :)
|
||||
VolumesRW map[string]bool
|
||||
hostConfig *HostConfig
|
||||
hostConfig *runconfig.HostConfig
|
||||
|
||||
activeLinks map[string]*Link
|
||||
}
|
||||
|
||||
// Note: the Config structure should hold only portable information about the container.
|
||||
// Here, "portable" means "independent from the host we are running on".
|
||||
// Non-portable information *should* appear in HostConfig.
|
||||
type Config struct {
|
||||
Hostname string
|
||||
Domainname string
|
||||
User string
|
||||
Memory int64 // Memory limit (in bytes)
|
||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
|
||||
CpuShares int64 // CPU shares (relative weight vs. other containers)
|
||||
AttachStdin bool
|
||||
AttachStdout bool
|
||||
AttachStderr bool
|
||||
PortSpecs []string // Deprecated - Can be in the format of 8080/tcp
|
||||
ExposedPorts map[nat.Port]struct{}
|
||||
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
||||
OpenStdin bool // Open stdin
|
||||
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
||||
Env []string
|
||||
Cmd []string
|
||||
Dns []string
|
||||
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
||||
Volumes map[string]struct{}
|
||||
VolumesFrom string
|
||||
WorkingDir string
|
||||
Entrypoint []string
|
||||
NetworkDisabled bool
|
||||
OnBuild []string
|
||||
}
|
||||
|
||||
func ContainerConfigFromJob(job *engine.Job) *Config {
|
||||
config := &Config{
|
||||
Hostname: job.Getenv("Hostname"),
|
||||
Domainname: job.Getenv("Domainname"),
|
||||
User: job.Getenv("User"),
|
||||
Memory: job.GetenvInt64("Memory"),
|
||||
MemorySwap: job.GetenvInt64("MemorySwap"),
|
||||
CpuShares: job.GetenvInt64("CpuShares"),
|
||||
AttachStdin: job.GetenvBool("AttachStdin"),
|
||||
AttachStdout: job.GetenvBool("AttachStdout"),
|
||||
AttachStderr: job.GetenvBool("AttachStderr"),
|
||||
Tty: job.GetenvBool("Tty"),
|
||||
OpenStdin: job.GetenvBool("OpenStdin"),
|
||||
StdinOnce: job.GetenvBool("StdinOnce"),
|
||||
Image: job.Getenv("Image"),
|
||||
VolumesFrom: job.Getenv("VolumesFrom"),
|
||||
WorkingDir: job.Getenv("WorkingDir"),
|
||||
NetworkDisabled: job.GetenvBool("NetworkDisabled"),
|
||||
}
|
||||
job.GetenvJson("ExposedPorts", &config.ExposedPorts)
|
||||
job.GetenvJson("Volumes", &config.Volumes)
|
||||
if PortSpecs := job.GetenvList("PortSpecs"); PortSpecs != nil {
|
||||
config.PortSpecs = PortSpecs
|
||||
}
|
||||
if Env := job.GetenvList("Env"); Env != nil {
|
||||
config.Env = Env
|
||||
}
|
||||
if Cmd := job.GetenvList("Cmd"); Cmd != nil {
|
||||
config.Cmd = Cmd
|
||||
}
|
||||
if Dns := job.GetenvList("Dns"); Dns != nil {
|
||||
config.Dns = Dns
|
||||
}
|
||||
if Entrypoint := job.GetenvList("Entrypoint"); Entrypoint != nil {
|
||||
config.Entrypoint = Entrypoint
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
type HostConfig struct {
|
||||
Binds []string
|
||||
ContainerIDFile string
|
||||
LxcConf []KeyValuePair
|
||||
Privileged bool
|
||||
PortBindings nat.PortMap
|
||||
Links []string
|
||||
PublishAllPorts bool
|
||||
}
|
||||
|
||||
func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
||||
hostConfig := &HostConfig{
|
||||
ContainerIDFile: job.Getenv("ContainerIDFile"),
|
||||
Privileged: job.GetenvBool("Privileged"),
|
||||
PublishAllPorts: job.GetenvBool("PublishAllPorts"),
|
||||
}
|
||||
job.GetenvJson("LxcConf", &hostConfig.LxcConf)
|
||||
job.GetenvJson("PortBindings", &hostConfig.PortBindings)
|
||||
if Binds := job.GetenvList("Binds"); Binds != nil {
|
||||
hostConfig.Binds = Binds
|
||||
}
|
||||
if Links := job.GetenvList("Links"); Links != nil {
|
||||
hostConfig.Links = Links
|
||||
}
|
||||
|
||||
return hostConfig
|
||||
}
|
||||
|
||||
type BindMap struct {
|
||||
SrcPath string
|
||||
DstPath string
|
||||
|
@ -178,18 +81,10 @@ type BindMap struct {
|
|||
}
|
||||
|
||||
var (
|
||||
ErrContainerStart = errors.New("The container failed to start. Unknown error")
|
||||
ErrContainerStartTimeout = errors.New("The container failed to start due to timed out.")
|
||||
ErrInvalidWorikingDirectory = errors.New("The working directory is invalid. It needs to be an absolute path.")
|
||||
ErrConflictAttachDetach = errors.New("Conflicting options: -a and -d")
|
||||
ErrConflictDetachAutoRemove = errors.New("Conflicting options: -rm and -d")
|
||||
ErrContainerStart = errors.New("The container failed to start. Unknown error")
|
||||
ErrContainerStartTimeout = errors.New("The container failed to start due to timed out.")
|
||||
)
|
||||
|
||||
type KeyValuePair struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// FIXME: move deprecated port stuff to nat to clean up the core.
|
||||
type PortMapping map[string]string // Deprecated
|
||||
|
||||
|
@ -292,7 +187,7 @@ func (container *Container) ToDisk() (err error) {
|
|||
}
|
||||
|
||||
func (container *Container) readHostConfig() error {
|
||||
container.hostConfig = &HostConfig{}
|
||||
container.hostConfig = &runconfig.HostConfig{}
|
||||
// If the hostconfig file does not exist, do not read it.
|
||||
// (We still have to initialize container.hostConfig,
|
||||
// but that's OK, since we just did that above.)
|
||||
|
|
|
@ -5,23 +5,6 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkOptsPrivateOnly(t *testing.T) {
|
||||
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::80"})
|
||||
if err != nil {
|
||||
|
|
3
graph.go
3
graph.go
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/dotcloud/docker/archive"
|
||||
"github.com/dotcloud/docker/dockerversion"
|
||||
"github.com/dotcloud/docker/graphdriver"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -126,7 +127,7 @@ func (graph *Graph) Get(name string) (*Image, error) {
|
|||
}
|
||||
|
||||
// Create creates a new image and registers it in the graph.
|
||||
func (graph *Graph) Create(layerData archive.Archive, container *Container, comment, author string, config *Config) (*Image, error) {
|
||||
func (graph *Graph) Create(layerData archive.Archive, container *Container, comment, author string, config *runconfig.Config) (*Image, error) {
|
||||
img := &Image{
|
||||
ID: GenerateID(),
|
||||
Comment: comment,
|
||||
|
|
23
image.go
23
image.go
|
@ -7,6 +7,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/dotcloud/docker/archive"
|
||||
"github.com/dotcloud/docker/graphdriver"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -18,17 +19,17 @@ import (
|
|||
)
|
||||
|
||||
type Image struct {
|
||||
ID string `json:"id"`
|
||||
Parent string `json:"parent,omitempty"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
Created time.Time `json:"created"`
|
||||
Container string `json:"container,omitempty"`
|
||||
ContainerConfig Config `json:"container_config,omitempty"`
|
||||
DockerVersion string `json:"docker_version,omitempty"`
|
||||
Author string `json:"author,omitempty"`
|
||||
Config *Config `json:"config,omitempty"`
|
||||
Architecture string `json:"architecture,omitempty"`
|
||||
OS string `json:"os,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Parent string `json:"parent,omitempty"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
Created time.Time `json:"created"`
|
||||
Container string `json:"container,omitempty"`
|
||||
ContainerConfig runconfig.Config `json:"container_config,omitempty"`
|
||||
DockerVersion string `json:"docker_version,omitempty"`
|
||||
Author string `json:"author,omitempty"`
|
||||
Config *runconfig.Config `json:"config,omitempty"`
|
||||
Architecture string `json:"architecture,omitempty"`
|
||||
OS string `json:"os,omitempty"`
|
||||
graph *Graph
|
||||
Size int64
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/dotcloud/docker/api"
|
||||
"github.com/dotcloud/docker/dockerversion"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"net"
|
||||
|
@ -309,7 +310,7 @@ func TestGetContainersJSON(t *testing.T) {
|
|||
}
|
||||
beginLen := len(outs.Data)
|
||||
|
||||
containerID := createTestContainer(eng, &docker.Config{
|
||||
containerID := createTestContainer(eng, &runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"echo", "test"},
|
||||
}, t)
|
||||
|
@ -346,7 +347,7 @@ func TestGetContainersExport(t *testing.T) {
|
|||
|
||||
// Create a container and remove a file
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"touch", "/test"},
|
||||
},
|
||||
|
@ -394,7 +395,7 @@ func TestGetContainersChanges(t *testing.T) {
|
|||
|
||||
// Create a container and remove a file
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/rm", "/etc/passwd"},
|
||||
},
|
||||
|
@ -433,7 +434,7 @@ func TestGetContainersTop(t *testing.T) {
|
|||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/sh", "-c", "cat"},
|
||||
OpenStdin: true,
|
||||
|
@ -510,7 +511,7 @@ func TestGetContainersByName(t *testing.T) {
|
|||
|
||||
// Create a container and remove a file
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"echo", "test"},
|
||||
},
|
||||
|
@ -542,7 +543,7 @@ func TestPostCommit(t *testing.T) {
|
|||
|
||||
// Create a container and remove a file
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"touch", "/test"},
|
||||
},
|
||||
|
@ -578,7 +579,7 @@ func TestPostContainersCreate(t *testing.T) {
|
|||
eng := NewTestEngine(t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
configJSON, err := json.Marshal(&docker.Config{
|
||||
configJSON, err := json.Marshal(&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Memory: 33554432,
|
||||
Cmd: []string{"touch", "/test"},
|
||||
|
@ -620,7 +621,7 @@ func TestPostContainersKill(t *testing.T) {
|
|||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
|
@ -659,7 +660,7 @@ func TestPostContainersRestart(t *testing.T) {
|
|||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/top"},
|
||||
OpenStdin: true,
|
||||
|
@ -705,7 +706,7 @@ func TestPostContainersStart(t *testing.T) {
|
|||
|
||||
containerID := createTestContainer(
|
||||
eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
|
@ -713,7 +714,7 @@ func TestPostContainersStart(t *testing.T) {
|
|||
t,
|
||||
)
|
||||
|
||||
hostConfigJSON, err := json.Marshal(&docker.HostConfig{})
|
||||
hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{})
|
||||
|
||||
req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
|
||||
if err != nil {
|
||||
|
@ -758,7 +759,7 @@ func TestRunErrorBindMountRootSource(t *testing.T) {
|
|||
|
||||
containerID := createTestContainer(
|
||||
eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
|
@ -766,7 +767,7 @@ func TestRunErrorBindMountRootSource(t *testing.T) {
|
|||
t,
|
||||
)
|
||||
|
||||
hostConfigJSON, err := json.Marshal(&docker.HostConfig{
|
||||
hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{
|
||||
Binds: []string{"/:/tmp"},
|
||||
})
|
||||
|
||||
|
@ -792,7 +793,7 @@ func TestPostContainersStop(t *testing.T) {
|
|||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/top"},
|
||||
OpenStdin: true,
|
||||
|
@ -832,7 +833,7 @@ func TestPostContainersWait(t *testing.T) {
|
|||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/sleep", "1"},
|
||||
OpenStdin: true,
|
||||
|
@ -870,7 +871,7 @@ func TestPostContainersAttach(t *testing.T) {
|
|||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
|
@ -948,7 +949,7 @@ func TestPostContainersAttachStderr(t *testing.T) {
|
|||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/sh", "-c", "/bin/cat >&2"},
|
||||
OpenStdin: true,
|
||||
|
@ -1029,7 +1030,7 @@ func TestDeleteContainers(t *testing.T) {
|
|||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"touch", "/test"},
|
||||
},
|
||||
|
@ -1164,7 +1165,7 @@ func TestPostContainersCopy(t *testing.T) {
|
|||
|
||||
// Create a container and remove a file
|
||||
containerID := createTestContainer(eng,
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"touch", "/test.txt"},
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ package docker
|
|||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -20,7 +20,7 @@ func TestIDFormat(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container1, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/sh", "-c", "echo hello world"},
|
||||
},
|
||||
|
@ -234,7 +234,7 @@ func TestCommitAutoRun(t *testing.T) {
|
|||
t.Errorf("Container shouldn't be running")
|
||||
}
|
||||
|
||||
img, err := runtime.Commit(container1, "", "", "unit test commited image", "", &docker.Config{Cmd: []string{"cat", "/world"}})
|
||||
img, err := runtime.Commit(container1, "", "", "unit test commited image", "", &runconfig.Config{Cmd: []string{"cat", "/world"}})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -415,7 +415,7 @@ func TestOutput(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foobar"},
|
||||
},
|
||||
|
@ -438,7 +438,7 @@ func TestContainerNetwork(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ping", "-c", "1", "127.0.0.1"},
|
||||
},
|
||||
|
@ -460,7 +460,7 @@ func TestKillDifferentUser(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"cat"},
|
||||
OpenStdin: true,
|
||||
|
@ -520,7 +520,7 @@ func TestCreateVolume(t *testing.T) {
|
|||
runtime := mkRuntimeFromEngine(eng, t)
|
||||
defer nuke(runtime)
|
||||
|
||||
config, hc, _, err := docker.ParseRun([]string{"-v", "/var/lib/data", unitTestImageID, "echo", "hello", "world"}, nil)
|
||||
config, hc, _, err := runconfig.Parse([]string{"-v", "/var/lib/data", unitTestImageID, "echo", "hello", "world"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -552,7 +552,7 @@ func TestCreateVolume(t *testing.T) {
|
|||
func TestKill(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sleep", "2"},
|
||||
},
|
||||
|
@ -596,7 +596,7 @@ func TestExitCode(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
trueContainer, _, err := runtime.Create(&docker.Config{
|
||||
trueContainer, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/true"},
|
||||
}, "")
|
||||
|
@ -611,7 +611,7 @@ func TestExitCode(t *testing.T) {
|
|||
t.Fatalf("Unexpected exit code %d (expected 0)", code)
|
||||
}
|
||||
|
||||
falseContainer, _, err := runtime.Create(&docker.Config{
|
||||
falseContainer, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/false"},
|
||||
}, "")
|
||||
|
@ -630,7 +630,7 @@ func TestExitCode(t *testing.T) {
|
|||
func TestRestart(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foobar"},
|
||||
},
|
||||
|
@ -661,7 +661,7 @@ func TestRestart(t *testing.T) {
|
|||
func TestRestartStdin(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"cat"},
|
||||
|
||||
|
@ -739,7 +739,7 @@ func TestUser(t *testing.T) {
|
|||
defer nuke(runtime)
|
||||
|
||||
// Default user must be root
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"id"},
|
||||
},
|
||||
|
@ -758,7 +758,7 @@ func TestUser(t *testing.T) {
|
|||
}
|
||||
|
||||
// Set a username
|
||||
container, _, err = runtime.Create(&docker.Config{
|
||||
container, _, err = runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"id"},
|
||||
|
||||
|
@ -779,7 +779,7 @@ func TestUser(t *testing.T) {
|
|||
}
|
||||
|
||||
// Set a UID
|
||||
container, _, err = runtime.Create(&docker.Config{
|
||||
container, _, err = runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"id"},
|
||||
|
||||
|
@ -800,7 +800,7 @@ func TestUser(t *testing.T) {
|
|||
}
|
||||
|
||||
// Set a different user by uid
|
||||
container, _, err = runtime.Create(&docker.Config{
|
||||
container, _, err = runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"id"},
|
||||
|
||||
|
@ -823,7 +823,7 @@ func TestUser(t *testing.T) {
|
|||
}
|
||||
|
||||
// Set a different user by username
|
||||
container, _, err = runtime.Create(&docker.Config{
|
||||
container, _, err = runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"id"},
|
||||
|
||||
|
@ -844,7 +844,7 @@ func TestUser(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test an wrong username
|
||||
container, _, err = runtime.Create(&docker.Config{
|
||||
container, _, err = runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"id"},
|
||||
|
||||
|
@ -866,7 +866,7 @@ func TestMultipleContainers(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
container1, _, err := runtime.Create(&docker.Config{
|
||||
container1, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sleep", "2"},
|
||||
},
|
||||
|
@ -877,7 +877,7 @@ func TestMultipleContainers(t *testing.T) {
|
|||
}
|
||||
defer runtime.Destroy(container1)
|
||||
|
||||
container2, _, err := runtime.Create(&docker.Config{
|
||||
container2, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sleep", "2"},
|
||||
},
|
||||
|
@ -921,7 +921,7 @@ func TestMultipleContainers(t *testing.T) {
|
|||
func TestStdin(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"cat"},
|
||||
|
||||
|
@ -966,7 +966,7 @@ func TestStdin(t *testing.T) {
|
|||
func TestTty(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"cat"},
|
||||
|
||||
|
@ -1013,7 +1013,7 @@ func TestEnv(t *testing.T) {
|
|||
os.Setenv("TRICKY", "tri\ncky\n")
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
config, _, _, err := docker.ParseRun([]string{"-e=FALSE=true", "-e=TRUE", "-e=TRICKY", GetTestImage(runtime).ID, "env"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{"-e=FALSE=true", "-e=TRUE", "-e=TRICKY", GetTestImage(runtime).ID, "env"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1067,7 +1067,7 @@ func TestEntrypoint(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Entrypoint: []string{"/bin/echo"},
|
||||
Cmd: []string{"-n", "foobar"},
|
||||
|
@ -1091,7 +1091,7 @@ func TestEntrypointNoCmd(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Entrypoint: []string{"/bin/echo", "foobar"},
|
||||
},
|
||||
|
@ -1114,7 +1114,7 @@ func BenchmarkRunSequencial(b *testing.B) {
|
|||
runtime := mkRuntime(b)
|
||||
defer nuke(runtime)
|
||||
for i := 0; i < b.N; i++ {
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foo"},
|
||||
},
|
||||
|
@ -1147,7 +1147,7 @@ func BenchmarkRunParallel(b *testing.B) {
|
|||
complete := make(chan error)
|
||||
tasks = append(tasks, complete)
|
||||
go func(i int, complete chan error) {
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foo"},
|
||||
},
|
||||
|
@ -1301,7 +1301,7 @@ func TestFromVolumesInReadonlyMode(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
|
@ -1321,7 +1321,7 @@ func TestFromVolumesInReadonlyMode(t *testing.T) {
|
|||
}
|
||||
|
||||
container2, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
VolumesFrom: container.ID + ":ro",
|
||||
|
@ -1362,7 +1362,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
|
@ -1382,7 +1382,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
|
|||
}
|
||||
|
||||
container2, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
VolumesFrom: container.ID,
|
||||
|
@ -1418,7 +1418,7 @@ func TestRestartWithVolumes(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foobar"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
|
@ -1462,7 +1462,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
|
@ -1491,7 +1491,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
|
|||
}
|
||||
|
||||
container2, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"cat", "/test/foo"},
|
||||
VolumesFrom: container.ID,
|
||||
|
@ -1529,7 +1529,7 @@ func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
|
|||
runtime := mkRuntimeFromEngine(eng, t)
|
||||
defer nuke(runtime)
|
||||
|
||||
config, hc, _, err := docker.ParseRun([]string{"-n=false", GetTestImage(runtime).ID, "ip", "addr", "show"}, nil)
|
||||
config, hc, _, err := runconfig.Parse([]string{"-n=false", GetTestImage(runtime).ID, "ip", "addr", "show"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1617,7 +1617,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
|
@ -1646,7 +1646,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
|
|||
}
|
||||
|
||||
container2, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sh", "-c", "echo -n bar > /other/foo"},
|
||||
Volumes: map[string]struct{}{"/other": {}},
|
||||
|
@ -1668,7 +1668,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
|
|||
}
|
||||
|
||||
container3, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
VolumesFrom: strings.Join([]string{container.ID, container2.ID}, ","),
|
||||
|
@ -1696,7 +1696,7 @@ func TestRestartGhost(t *testing.T) {
|
|||
defer nuke(runtime)
|
||||
|
||||
container, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/sysinit"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
|
@ -200,7 +201,7 @@ func TestRuntimeCreate(t *testing.T) {
|
|||
t.Errorf("Expected 0 containers, %v found", len(runtime.List()))
|
||||
}
|
||||
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
},
|
||||
|
@ -243,23 +244,23 @@ func TestRuntimeCreate(t *testing.T) {
|
|||
|
||||
// Test that conflict error displays correct details
|
||||
testContainer, _, _ := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
},
|
||||
"conflictname",
|
||||
)
|
||||
if _, _, err := runtime.Create(&docker.Config{Image: GetTestImage(runtime).ID, Cmd: []string{"ls", "-al"}}, testContainer.Name); err == nil || !strings.Contains(err.Error(), utils.TruncateID(testContainer.ID)) {
|
||||
if _, _, err := runtime.Create(&runconfig.Config{Image: GetTestImage(runtime).ID, Cmd: []string{"ls", "-al"}}, testContainer.Name); err == nil || !strings.Contains(err.Error(), utils.TruncateID(testContainer.ID)) {
|
||||
t.Fatalf("Name conflict error doesn't include the correct short id. Message was: %s", err.Error())
|
||||
}
|
||||
|
||||
// Make sure create with bad parameters returns an error
|
||||
if _, _, err = runtime.Create(&docker.Config{Image: GetTestImage(runtime).ID}, ""); err == nil {
|
||||
if _, _, err = runtime.Create(&runconfig.Config{Image: GetTestImage(runtime).ID}, ""); err == nil {
|
||||
t.Fatal("Builder.Create should throw an error when Cmd is missing")
|
||||
}
|
||||
|
||||
if _, _, err := runtime.Create(
|
||||
&docker.Config{
|
||||
&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{},
|
||||
},
|
||||
|
@ -268,7 +269,7 @@ func TestRuntimeCreate(t *testing.T) {
|
|||
t.Fatal("Builder.Create should throw an error when Cmd is empty")
|
||||
}
|
||||
|
||||
config := &docker.Config{
|
||||
config := &runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/ls"},
|
||||
PortSpecs: []string{"80"},
|
||||
|
@ -281,7 +282,7 @@ func TestRuntimeCreate(t *testing.T) {
|
|||
}
|
||||
|
||||
// test expose 80:8000
|
||||
container, warnings, err := runtime.Create(&docker.Config{
|
||||
container, warnings, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
PortSpecs: []string{"80:8000"},
|
||||
|
@ -300,7 +301,7 @@ func TestDestroy(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
}, "")
|
||||
|
@ -712,7 +713,7 @@ func TestDefaultContainerName(t *testing.T) {
|
|||
runtime := mkRuntimeFromEngine(eng, t)
|
||||
defer nuke(runtime)
|
||||
|
||||
config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{unitTestImageID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -736,7 +737,7 @@ func TestRandomContainerName(t *testing.T) {
|
|||
runtime := mkRuntimeFromEngine(eng, t)
|
||||
defer nuke(runtime)
|
||||
|
||||
config, _, _, err := docker.ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{GetTestImage(runtime).ID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -767,7 +768,7 @@ func TestContainerNameValidation(t *testing.T) {
|
|||
{"abc-123_AAA.1", true},
|
||||
{"\000asdf", false},
|
||||
} {
|
||||
config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{unitTestImageID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
if !test.Valid {
|
||||
continue
|
||||
|
@ -808,7 +809,7 @@ func TestLinkChildContainer(t *testing.T) {
|
|||
runtime := mkRuntimeFromEngine(eng, t)
|
||||
defer nuke(runtime)
|
||||
|
||||
config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{unitTestImageID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -824,7 +825,7 @@ func TestLinkChildContainer(t *testing.T) {
|
|||
t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
|
||||
}
|
||||
|
||||
config, _, _, err = docker.ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
|
||||
config, _, _, err = runconfig.Parse([]string{GetTestImage(runtime).ID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -850,7 +851,7 @@ func TestGetAllChildren(t *testing.T) {
|
|||
runtime := mkRuntimeFromEngine(eng, t)
|
||||
defer nuke(runtime)
|
||||
|
||||
config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{unitTestImageID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -866,7 +867,7 @@ func TestGetAllChildren(t *testing.T) {
|
|||
t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
|
||||
}
|
||||
|
||||
config, _, _, err = docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
|
||||
config, _, _, err = runconfig.Parse([]string{unitTestImageID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -903,7 +904,7 @@ func TestDestroyWithInitLayer(t *testing.T) {
|
|||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
container, _, err := runtime.Create(&docker.Config{
|
||||
container, _, err := runtime.Create(&runconfig.Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
}, "")
|
||||
|
|
|
@ -3,6 +3,7 @@ package docker
|
|||
import (
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -71,7 +72,7 @@ func TestCreateRm(t *testing.T) {
|
|||
eng := NewTestEngine(t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{unitTestImageID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -118,7 +119,7 @@ func TestCreateNumberHostname(t *testing.T) {
|
|||
eng := NewTestEngine(t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
config, _, _, err := docker.ParseRun([]string{"-h", "web.0", unitTestImageID, "echo test"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{"-h", "web.0", unitTestImageID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -130,7 +131,7 @@ func TestCreateNumberUsername(t *testing.T) {
|
|||
eng := NewTestEngine(t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
config, _, _, err := docker.ParseRun([]string{"-u", "1002", unitTestImageID, "echo test"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{"-u", "1002", unitTestImageID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -142,7 +143,7 @@ func TestCreateRmVolumes(t *testing.T) {
|
|||
eng := NewTestEngine(t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
config, hostConfig, _, err := docker.ParseRun([]string{"-v", "/srv", unitTestImageID, "echo", "test"}, nil)
|
||||
config, hostConfig, _, err := runconfig.Parse([]string{"-v", "/srv", unitTestImageID, "echo", "test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -202,7 +203,7 @@ func TestCommit(t *testing.T) {
|
|||
eng := NewTestEngine(t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
config, _, _, err := docker.ParseRun([]string{unitTestImageID, "/bin/cat"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{unitTestImageID, "/bin/cat"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -224,7 +225,7 @@ func TestRestartKillWait(t *testing.T) {
|
|||
runtime := mkRuntimeFromEngine(eng, t)
|
||||
defer runtime.Nuke()
|
||||
|
||||
config, hostConfig, _, err := docker.ParseRun([]string{"-i", unitTestImageID, "/bin/cat"}, nil)
|
||||
config, hostConfig, _, err := runconfig.Parse([]string{"-i", unitTestImageID, "/bin/cat"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -302,7 +303,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
|||
srv := mkServerFromEngine(eng, t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
config, hostConfig, _, err := docker.ParseRun([]string{"-i", unitTestImageID, "/bin/cat"}, nil)
|
||||
config, hostConfig, _, err := runconfig.Parse([]string{"-i", unitTestImageID, "/bin/cat"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -401,7 +402,7 @@ func TestRmi(t *testing.T) {
|
|||
|
||||
initialImages := getAllImages(eng, t)
|
||||
|
||||
config, hostConfig, _, err := docker.ParseRun([]string{unitTestImageID, "echo", "test"}, nil)
|
||||
config, hostConfig, _, err := runconfig.Parse([]string{unitTestImageID, "echo", "test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -548,7 +549,7 @@ func TestListContainers(t *testing.T) {
|
|||
srv := mkServerFromEngine(eng, t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
config := docker.Config{
|
||||
config := runconfig.Config{
|
||||
Image: unitTestImageID,
|
||||
Cmd: []string{"/bin/sh", "-c", "cat"},
|
||||
OpenStdin: true,
|
||||
|
@ -671,7 +672,7 @@ func TestDeleteTagWithExistingContainers(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a container from the image
|
||||
config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
|
||||
config, _, _, err := runconfig.Parse([]string{unitTestImageID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
)
|
||||
|
||||
|
@ -48,7 +49,7 @@ func mkRuntime(f utils.Fataler) *docker.Runtime {
|
|||
return r
|
||||
}
|
||||
|
||||
func createNamedTestContainer(eng *engine.Engine, config *docker.Config, f utils.Fataler, name string) (shortId string) {
|
||||
func createNamedTestContainer(eng *engine.Engine, config *runconfig.Config, f utils.Fataler, name string) (shortId string) {
|
||||
job := eng.Job("create", name)
|
||||
if err := job.ImportEnv(config); err != nil {
|
||||
f.Fatal(err)
|
||||
|
@ -60,7 +61,7 @@ func createNamedTestContainer(eng *engine.Engine, config *docker.Config, f utils
|
|||
return
|
||||
}
|
||||
|
||||
func createTestContainer(eng *engine.Engine, config *docker.Config, f utils.Fataler) (shortId string) {
|
||||
func createTestContainer(eng *engine.Engine, config *runconfig.Config, f utils.Fataler) (shortId string) {
|
||||
return createNamedTestContainer(eng, config, f, "")
|
||||
}
|
||||
|
||||
|
@ -252,8 +253,8 @@ func readFile(src string, t *testing.T) (content string) {
|
|||
// dynamically replaced by the current test image.
|
||||
// The caller is responsible for destroying the container.
|
||||
// Call t.Fatal() at the first error.
|
||||
func mkContainer(r *docker.Runtime, args []string, t *testing.T) (*docker.Container, *docker.HostConfig, error) {
|
||||
config, hc, _, err := docker.ParseRun(args, nil)
|
||||
func mkContainer(r *docker.Runtime, args []string, t *testing.T) (*docker.Container, *runconfig.HostConfig, error) {
|
||||
config, hc, _, err := runconfig.Parse(args, nil)
|
||||
defer func() {
|
||||
if err != nil && t != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -2,13 +2,14 @@ package docker
|
|||
|
||||
import (
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func newMockLinkContainer(id string, ip string) *Container {
|
||||
return &Container{
|
||||
Config: &Config{},
|
||||
Config: &runconfig.Config{},
|
||||
ID: id,
|
||||
NetworkSettings: &NetworkSettings{
|
||||
IPAddress: ip,
|
||||
|
|
67
runconfig/compare.go
Normal file
67
runconfig/compare.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package runconfig
|
||||
|
||||
// Compare two Config struct. Do not compare the "Image" nor "Hostname" fields
|
||||
// If OpenStdin is set, then it differs
|
||||
func Compare(a, b *Config) bool {
|
||||
if a == nil || b == nil ||
|
||||
a.OpenStdin || b.OpenStdin {
|
||||
return false
|
||||
}
|
||||
if a.AttachStdout != b.AttachStdout ||
|
||||
a.AttachStderr != b.AttachStderr ||
|
||||
a.User != b.User ||
|
||||
a.Memory != b.Memory ||
|
||||
a.MemorySwap != b.MemorySwap ||
|
||||
a.CpuShares != b.CpuShares ||
|
||||
a.OpenStdin != b.OpenStdin ||
|
||||
a.Tty != b.Tty ||
|
||||
a.VolumesFrom != b.VolumesFrom {
|
||||
return false
|
||||
}
|
||||
if len(a.Cmd) != len(b.Cmd) ||
|
||||
len(a.Dns) != len(b.Dns) ||
|
||||
len(a.Env) != len(b.Env) ||
|
||||
len(a.PortSpecs) != len(b.PortSpecs) ||
|
||||
len(a.ExposedPorts) != len(b.ExposedPorts) ||
|
||||
len(a.Entrypoint) != len(b.Entrypoint) ||
|
||||
len(a.Volumes) != len(b.Volumes) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(a.Cmd); i++ {
|
||||
if a.Cmd[i] != b.Cmd[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.Dns); i++ {
|
||||
if a.Dns[i] != b.Dns[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.Env); i++ {
|
||||
if a.Env[i] != b.Env[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.PortSpecs); i++ {
|
||||
if a.PortSpecs[i] != b.PortSpecs[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for k := range a.ExposedPorts {
|
||||
if _, exists := b.ExposedPorts[k]; !exists {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.Entrypoint); i++ {
|
||||
if a.Entrypoint[i] != b.Entrypoint[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for key := range a.Volumes {
|
||||
if _, exists := b.Volumes[key]; !exists {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
76
runconfig/config.go
Normal file
76
runconfig/config.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package runconfig
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
)
|
||||
|
||||
// Note: the Config structure should hold only portable information about the container.
|
||||
// Here, "portable" means "independent from the host we are running on".
|
||||
// Non-portable information *should* appear in HostConfig.
|
||||
type Config struct {
|
||||
Hostname string
|
||||
Domainname string
|
||||
User string
|
||||
Memory int64 // Memory limit (in bytes)
|
||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
|
||||
CpuShares int64 // CPU shares (relative weight vs. other containers)
|
||||
AttachStdin bool
|
||||
AttachStdout bool
|
||||
AttachStderr bool
|
||||
PortSpecs []string // Deprecated - Can be in the format of 8080/tcp
|
||||
ExposedPorts map[nat.Port]struct{}
|
||||
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
||||
OpenStdin bool // Open stdin
|
||||
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
||||
Env []string
|
||||
Cmd []string
|
||||
Dns []string
|
||||
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
||||
Volumes map[string]struct{}
|
||||
VolumesFrom string
|
||||
WorkingDir string
|
||||
Entrypoint []string
|
||||
NetworkDisabled bool
|
||||
OnBuild []string
|
||||
}
|
||||
|
||||
func ContainerConfigFromJob(job *engine.Job) *Config {
|
||||
config := &Config{
|
||||
Hostname: job.Getenv("Hostname"),
|
||||
Domainname: job.Getenv("Domainname"),
|
||||
User: job.Getenv("User"),
|
||||
Memory: job.GetenvInt64("Memory"),
|
||||
MemorySwap: job.GetenvInt64("MemorySwap"),
|
||||
CpuShares: job.GetenvInt64("CpuShares"),
|
||||
AttachStdin: job.GetenvBool("AttachStdin"),
|
||||
AttachStdout: job.GetenvBool("AttachStdout"),
|
||||
AttachStderr: job.GetenvBool("AttachStderr"),
|
||||
Tty: job.GetenvBool("Tty"),
|
||||
OpenStdin: job.GetenvBool("OpenStdin"),
|
||||
StdinOnce: job.GetenvBool("StdinOnce"),
|
||||
Image: job.Getenv("Image"),
|
||||
VolumesFrom: job.Getenv("VolumesFrom"),
|
||||
WorkingDir: job.Getenv("WorkingDir"),
|
||||
NetworkDisabled: job.GetenvBool("NetworkDisabled"),
|
||||
}
|
||||
job.GetenvJson("ExposedPorts", &config.ExposedPorts)
|
||||
job.GetenvJson("Volumes", &config.Volumes)
|
||||
if PortSpecs := job.GetenvList("PortSpecs"); PortSpecs != nil {
|
||||
config.PortSpecs = PortSpecs
|
||||
}
|
||||
if Env := job.GetenvList("Env"); Env != nil {
|
||||
config.Env = Env
|
||||
}
|
||||
if Cmd := job.GetenvList("Cmd"); Cmd != nil {
|
||||
config.Cmd = Cmd
|
||||
}
|
||||
if Dns := job.GetenvList("Dns"); Dns != nil {
|
||||
config.Dns = Dns
|
||||
}
|
||||
if Entrypoint := job.GetenvList("Entrypoint"); Entrypoint != nil {
|
||||
config.Entrypoint = Entrypoint
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package docker
|
||||
package runconfig
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareConfig(t *testing.T) {
|
||||
func TestCompare(t *testing.T) {
|
||||
volumes1 := make(map[string]struct{})
|
||||
volumes1["/test1"] = struct{}{}
|
||||
config1 := Config{
|
||||
|
@ -45,24 +45,24 @@ func TestCompareConfig(t *testing.T) {
|
|||
VolumesFrom: "11111111",
|
||||
Volumes: volumes2,
|
||||
}
|
||||
if CompareConfig(&config1, &config2) {
|
||||
t.Fatalf("CompareConfig should return false, Dns are different")
|
||||
if Compare(&config1, &config2) {
|
||||
t.Fatalf("Compare should return false, Dns are different")
|
||||
}
|
||||
if CompareConfig(&config1, &config3) {
|
||||
t.Fatalf("CompareConfig should return false, PortSpecs are different")
|
||||
if Compare(&config1, &config3) {
|
||||
t.Fatalf("Compare should return false, PortSpecs are different")
|
||||
}
|
||||
if CompareConfig(&config1, &config4) {
|
||||
t.Fatalf("CompareConfig should return false, VolumesFrom are different")
|
||||
if Compare(&config1, &config4) {
|
||||
t.Fatalf("Compare should return false, VolumesFrom are different")
|
||||
}
|
||||
if CompareConfig(&config1, &config5) {
|
||||
t.Fatalf("CompareConfig should return false, Volumes are different")
|
||||
if Compare(&config1, &config5) {
|
||||
t.Fatalf("Compare should return false, Volumes are different")
|
||||
}
|
||||
if !CompareConfig(&config1, &config1) {
|
||||
t.Fatalf("CompareConfig should return true")
|
||||
if !Compare(&config1, &config1) {
|
||||
t.Fatalf("Compare should return true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeConfig(t *testing.T) {
|
||||
func TestMerge(t *testing.T) {
|
||||
volumesImage := make(map[string]struct{})
|
||||
volumesImage["/test1"] = struct{}{}
|
||||
volumesImage["/test2"] = struct{}{}
|
||||
|
@ -83,7 +83,7 @@ func TestMergeConfig(t *testing.T) {
|
|||
Volumes: volumesUser,
|
||||
}
|
||||
|
||||
if err := MergeConfig(configUser, configImage); err != nil {
|
||||
if err := Merge(configUser, configImage); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ func TestMergeConfig(t *testing.T) {
|
|||
ExposedPorts: ports,
|
||||
}
|
||||
|
||||
if err := MergeConfig(configUser, configImage2); err != nil {
|
||||
if err := Merge(configUser, configImage2); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
39
runconfig/hostconfig.go
Normal file
39
runconfig/hostconfig.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package runconfig
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
)
|
||||
|
||||
type HostConfig struct {
|
||||
Binds []string
|
||||
ContainerIDFile string
|
||||
LxcConf []KeyValuePair
|
||||
Privileged bool
|
||||
PortBindings nat.PortMap
|
||||
Links []string
|
||||
PublishAllPorts bool
|
||||
}
|
||||
|
||||
type KeyValuePair struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
||||
hostConfig := &HostConfig{
|
||||
ContainerIDFile: job.Getenv("ContainerIDFile"),
|
||||
Privileged: job.GetenvBool("Privileged"),
|
||||
PublishAllPorts: job.GetenvBool("PublishAllPorts"),
|
||||
}
|
||||
job.GetenvJson("LxcConf", &hostConfig.LxcConf)
|
||||
job.GetenvJson("PortBindings", &hostConfig.PortBindings)
|
||||
if Binds := job.GetenvList("Binds"); Binds != nil {
|
||||
hostConfig.Binds = Binds
|
||||
}
|
||||
if Links := job.GetenvList("Links"); Links != nil {
|
||||
hostConfig.Links = Links
|
||||
}
|
||||
|
||||
return hostConfig
|
||||
}
|
119
runconfig/merge.go
Normal file
119
runconfig/merge.go
Normal file
|
@ -0,0 +1,119 @@
|
|||
package runconfig
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Merge(userConf, imageConf *Config) error {
|
||||
if userConf.User == "" {
|
||||
userConf.User = imageConf.User
|
||||
}
|
||||
if userConf.Memory == 0 {
|
||||
userConf.Memory = imageConf.Memory
|
||||
}
|
||||
if userConf.MemorySwap == 0 {
|
||||
userConf.MemorySwap = imageConf.MemorySwap
|
||||
}
|
||||
if userConf.CpuShares == 0 {
|
||||
userConf.CpuShares = imageConf.CpuShares
|
||||
}
|
||||
if userConf.ExposedPorts == nil || len(userConf.ExposedPorts) == 0 {
|
||||
userConf.ExposedPorts = imageConf.ExposedPorts
|
||||
} else if imageConf.ExposedPorts != nil {
|
||||
if userConf.ExposedPorts == nil {
|
||||
userConf.ExposedPorts = make(nat.PortSet)
|
||||
}
|
||||
for port := range imageConf.ExposedPorts {
|
||||
if _, exists := userConf.ExposedPorts[port]; !exists {
|
||||
userConf.ExposedPorts[port] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if userConf.PortSpecs != nil && len(userConf.PortSpecs) > 0 {
|
||||
if userConf.ExposedPorts == nil {
|
||||
userConf.ExposedPorts = make(nat.PortSet)
|
||||
}
|
||||
ports, _, err := nat.ParsePortSpecs(userConf.PortSpecs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for port := range ports {
|
||||
if _, exists := userConf.ExposedPorts[port]; !exists {
|
||||
userConf.ExposedPorts[port] = struct{}{}
|
||||
}
|
||||
}
|
||||
userConf.PortSpecs = nil
|
||||
}
|
||||
if imageConf.PortSpecs != nil && len(imageConf.PortSpecs) > 0 {
|
||||
// FIXME: I think we can safely remove this. Leaving it for now for the sake of reverse-compat paranoia.
|
||||
utils.Debugf("Migrating image port specs to containter: %s", strings.Join(imageConf.PortSpecs, ", "))
|
||||
if userConf.ExposedPorts == nil {
|
||||
userConf.ExposedPorts = make(nat.PortSet)
|
||||
}
|
||||
|
||||
ports, _, err := nat.ParsePortSpecs(imageConf.PortSpecs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for port := range ports {
|
||||
if _, exists := userConf.ExposedPorts[port]; !exists {
|
||||
userConf.ExposedPorts[port] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !userConf.Tty {
|
||||
userConf.Tty = imageConf.Tty
|
||||
}
|
||||
if !userConf.OpenStdin {
|
||||
userConf.OpenStdin = imageConf.OpenStdin
|
||||
}
|
||||
if !userConf.StdinOnce {
|
||||
userConf.StdinOnce = imageConf.StdinOnce
|
||||
}
|
||||
if userConf.Env == nil || len(userConf.Env) == 0 {
|
||||
userConf.Env = imageConf.Env
|
||||
} else {
|
||||
for _, imageEnv := range imageConf.Env {
|
||||
found := false
|
||||
imageEnvKey := strings.Split(imageEnv, "=")[0]
|
||||
for _, userEnv := range userConf.Env {
|
||||
userEnvKey := strings.Split(userEnv, "=")[0]
|
||||
if imageEnvKey == userEnvKey {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
userConf.Env = append(userConf.Env, imageEnv)
|
||||
}
|
||||
}
|
||||
}
|
||||
if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
|
||||
userConf.Cmd = imageConf.Cmd
|
||||
}
|
||||
if userConf.Dns == nil || len(userConf.Dns) == 0 {
|
||||
userConf.Dns = imageConf.Dns
|
||||
} else {
|
||||
//duplicates aren't an issue here
|
||||
userConf.Dns = append(userConf.Dns, imageConf.Dns...)
|
||||
}
|
||||
if userConf.Entrypoint == nil || len(userConf.Entrypoint) == 0 {
|
||||
userConf.Entrypoint = imageConf.Entrypoint
|
||||
}
|
||||
if userConf.WorkingDir == "" {
|
||||
userConf.WorkingDir = imageConf.WorkingDir
|
||||
}
|
||||
if userConf.VolumesFrom == "" {
|
||||
userConf.VolumesFrom = imageConf.VolumesFrom
|
||||
}
|
||||
if userConf.Volumes == nil || len(userConf.Volumes) == 0 {
|
||||
userConf.Volumes = imageConf.Volumes
|
||||
} else {
|
||||
for k, v := range imageConf.Volumes {
|
||||
userConf.Volumes[k] = v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
246
runconfig/parse.go
Normal file
246
runconfig/parse.go
Normal file
|
@ -0,0 +1,246 @@
|
|||
package runconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
flag "github.com/dotcloud/docker/pkg/mflag"
|
||||
"github.com/dotcloud/docker/pkg/opts"
|
||||
"github.com/dotcloud/docker/pkg/sysinfo"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidWorikingDirectory = fmt.Errorf("The working directory is invalid. It needs to be an absolute path.")
|
||||
ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d")
|
||||
ErrConflictDetachAutoRemove = fmt.Errorf("Conflicting options: -rm and -d")
|
||||
)
|
||||
|
||||
//FIXME Only used in tests
|
||||
func Parse(args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
||||
cmd := flag.NewFlagSet("run", flag.ContinueOnError)
|
||||
cmd.SetOutput(ioutil.Discard)
|
||||
cmd.Usage = nil
|
||||
return parseRun(cmd, args, sysInfo)
|
||||
}
|
||||
|
||||
// FIXME: this maps the legacy commands.go code. It should be merged with Parse to only expose a single parse function.
|
||||
func ParseSubcommand(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
||||
return parseRun(cmd, args, sysInfo)
|
||||
}
|
||||
|
||||
func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
|
||||
var (
|
||||
// FIXME: use utils.ListOpts for attach and volumes?
|
||||
flAttach = opts.NewListOpts(opts.ValidateAttach)
|
||||
flVolumes = opts.NewListOpts(opts.ValidatePath)
|
||||
flLinks = opts.NewListOpts(opts.ValidateLink)
|
||||
flEnv = opts.NewListOpts(opts.ValidateEnv)
|
||||
|
||||
flPublish opts.ListOpts
|
||||
flExpose opts.ListOpts
|
||||
flDns opts.ListOpts
|
||||
flVolumesFrom opts.ListOpts
|
||||
flLxcOpts 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")
|
||||
flNetwork = cmd.Bool([]string{"n", "-networking"}, true, "Enable networking for this container")
|
||||
flPrivileged = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
|
||||
flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to the host interfaces")
|
||||
flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep stdin open even if not attached")
|
||||
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-tty")
|
||||
flContainerIDFile = cmd.String([]string{"#cidfile", "-cidfile"}, "", "Write the container ID to the file")
|
||||
flEntrypoint = cmd.String([]string{"#entrypoint", "-entrypoint"}, "", "Overwrite the default entrypoint of the image")
|
||||
flHostname = cmd.String([]string{"h", "-hostname"}, "", "Container host name")
|
||||
flMemoryString = cmd.String([]string{"m", "-memory"}, "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")
|
||||
flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID")
|
||||
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
||||
flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
|
||||
|
||||
// For documentation purpose
|
||||
_ = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
|
||||
_ = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
|
||||
)
|
||||
|
||||
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to stdin, stdout or stderr.")
|
||||
cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
|
||||
cmd.Var(&flLinks, []string{"#link", "-link"}, "Add link to another container (name:alias)")
|
||||
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
||||
|
||||
cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", nat.PortSpecTemplateFormat))
|
||||
cmd.Var(&flExpose, []string{"#expose", "-expose"}, "Expose a port from the container without publishing it to your host")
|
||||
cmd.Var(&flDns, []string{"#dns", "-dns"}, "Set custom dns servers")
|
||||
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
|
||||
cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
|
||||
// Check if the kernel supports memory limit cgroup.
|
||||
if sysInfo != nil && *flMemoryString != "" && !sysInfo.MemoryLimit {
|
||||
*flMemoryString = ""
|
||||
}
|
||||
|
||||
// Validate input params
|
||||
if *flDetach && flAttach.Len() > 0 {
|
||||
return nil, nil, cmd, ErrConflictAttachDetach
|
||||
}
|
||||
if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) {
|
||||
return nil, nil, cmd, ErrInvalidWorikingDirectory
|
||||
}
|
||||
if *flDetach && *flAutoRemove {
|
||||
return nil, nil, cmd, ErrConflictDetachAutoRemove
|
||||
}
|
||||
|
||||
// If neither -d or -a are set, attach to everything by default
|
||||
if flAttach.Len() == 0 && !*flDetach {
|
||||
if !*flDetach {
|
||||
flAttach.Set("stdout")
|
||||
flAttach.Set("stderr")
|
||||
if *flStdin {
|
||||
flAttach.Set("stdin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var flMemory int64
|
||||
if *flMemoryString != "" {
|
||||
parsedMemory, err := utils.RAMInBytes(*flMemoryString)
|
||||
if err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
flMemory = parsedMemory
|
||||
}
|
||||
|
||||
var binds []string
|
||||
// add any bind targets to the list of container volumes
|
||||
for bind := range flVolumes.GetMap() {
|
||||
if arr := strings.Split(bind, ":"); len(arr) > 1 {
|
||||
if arr[0] == "/" {
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid bind mount: source can't be '/'")
|
||||
}
|
||||
dstDir := arr[1]
|
||||
flVolumes.Set(dstDir)
|
||||
binds = append(binds, bind)
|
||||
flVolumes.Delete(bind)
|
||||
} else if bind == "/" {
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid volume: path can't be '/'")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
parsedArgs = cmd.Args()
|
||||
runCmd []string
|
||||
entrypoint []string
|
||||
image string
|
||||
)
|
||||
if len(parsedArgs) >= 1 {
|
||||
image = cmd.Arg(0)
|
||||
}
|
||||
if len(parsedArgs) > 1 {
|
||||
runCmd = parsedArgs[1:]
|
||||
}
|
||||
if *flEntrypoint != "" {
|
||||
entrypoint = []string{*flEntrypoint}
|
||||
}
|
||||
|
||||
lxcConf, err := parseLxcConfOpts(flLxcOpts)
|
||||
if err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
|
||||
var (
|
||||
domainname string
|
||||
hostname = *flHostname
|
||||
parts = strings.SplitN(hostname, ".", 2)
|
||||
)
|
||||
if len(parts) > 1 {
|
||||
hostname = parts[0]
|
||||
domainname = parts[1]
|
||||
}
|
||||
|
||||
ports, portBindings, err := nat.ParsePortSpecs(flPublish.GetAll())
|
||||
if err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
|
||||
// Merge in exposed ports to the map of published ports
|
||||
for _, e := range flExpose.GetAll() {
|
||||
if strings.Contains(e, ":") {
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid port format for --expose: %s", e)
|
||||
}
|
||||
p := nat.NewPort(nat.SplitProtoPort(e))
|
||||
if _, exists := ports[p]; !exists {
|
||||
ports[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
config := &Config{
|
||||
Hostname: hostname,
|
||||
Domainname: domainname,
|
||||
PortSpecs: nil, // Deprecated
|
||||
ExposedPorts: ports,
|
||||
User: *flUser,
|
||||
Tty: *flTty,
|
||||
NetworkDisabled: !*flNetwork,
|
||||
OpenStdin: *flStdin,
|
||||
Memory: flMemory,
|
||||
CpuShares: *flCpuShares,
|
||||
AttachStdin: flAttach.Get("stdin"),
|
||||
AttachStdout: flAttach.Get("stdout"),
|
||||
AttachStderr: flAttach.Get("stderr"),
|
||||
Env: flEnv.GetAll(),
|
||||
Cmd: runCmd,
|
||||
Dns: flDns.GetAll(),
|
||||
Image: image,
|
||||
Volumes: flVolumes.GetMap(),
|
||||
VolumesFrom: strings.Join(flVolumesFrom.GetAll(), ","),
|
||||
Entrypoint: entrypoint,
|
||||
WorkingDir: *flWorkingDir,
|
||||
}
|
||||
|
||||
hostConfig := &HostConfig{
|
||||
Binds: binds,
|
||||
ContainerIDFile: *flContainerIDFile,
|
||||
LxcConf: lxcConf,
|
||||
Privileged: *flPrivileged,
|
||||
PortBindings: portBindings,
|
||||
Links: flLinks.GetAll(),
|
||||
PublishAllPorts: *flPublishAll,
|
||||
}
|
||||
|
||||
if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit {
|
||||
//fmt.Fprintf(stdout, "WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
||||
config.MemorySwap = -1
|
||||
}
|
||||
|
||||
// When allocating stdin in attached mode, close stdin at client disconnect
|
||||
if config.OpenStdin && config.AttachStdin {
|
||||
config.StdinOnce = true
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
22
runconfig/parse_test.go
Normal file
22
runconfig/parse_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package runconfig
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
11
runtime.go
11
runtime.go
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/dotcloud/docker/networkdriver/portallocator"
|
||||
"github.com/dotcloud/docker/pkg/graphdb"
|
||||
"github.com/dotcloud/docker/pkg/sysinfo"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -329,7 +330,7 @@ func (runtime *Runtime) restore() error {
|
|||
}
|
||||
|
||||
// Create creates a new container from the given configuration with a given name.
|
||||
func (runtime *Runtime) Create(config *Config, name string) (*Container, []string, error) {
|
||||
func (runtime *Runtime) Create(config *runconfig.Config, name string) (*Container, []string, error) {
|
||||
// Lookup image
|
||||
img, err := runtime.repositories.LookupImage(config.Image)
|
||||
if err != nil {
|
||||
|
@ -347,7 +348,7 @@ func (runtime *Runtime) Create(config *Config, name string) (*Container, []strin
|
|||
return nil, nil, fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
|
||||
}
|
||||
|
||||
checkDeprecatedExpose := func(config *Config) bool {
|
||||
checkDeprecatedExpose := func(config *runconfig.Config) bool {
|
||||
if config != nil {
|
||||
if config.PortSpecs != nil {
|
||||
for _, p := range config.PortSpecs {
|
||||
|
@ -366,7 +367,7 @@ func (runtime *Runtime) Create(config *Config, name string) (*Container, []strin
|
|||
}
|
||||
|
||||
if img.Config != nil {
|
||||
if err := MergeConfig(config, img.Config); err != nil {
|
||||
if err := runconfig.Merge(config, img.Config); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
@ -441,7 +442,7 @@ func (runtime *Runtime) Create(config *Config, name string) (*Container, []strin
|
|||
Path: entrypoint,
|
||||
Args: args, //FIXME: de-duplicate from config
|
||||
Config: config,
|
||||
hostConfig: &HostConfig{},
|
||||
hostConfig: &runconfig.HostConfig{},
|
||||
Image: img.ID, // Always use the resolved image id
|
||||
NetworkSettings: &NetworkSettings{},
|
||||
Name: name,
|
||||
|
@ -518,7 +519,7 @@ func (runtime *Runtime) Create(config *Config, name string) (*Container, []strin
|
|||
|
||||
// Commit creates a new filesystem image from the current state of a container.
|
||||
// The image can optionally be tagged into a repository
|
||||
func (runtime *Runtime) Commit(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
|
||||
func (runtime *Runtime) Commit(container *Container, repository, tag, comment, author string, config *runconfig.Config) (*Image, error) {
|
||||
// FIXME: freeze the container before copying it to avoid data corruption?
|
||||
// FIXME: this shouldn't be in commands.
|
||||
if err := container.Mount(); err != nil {
|
||||
|
|
17
server.go
17
server.go
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/pkg/graphdb"
|
||||
"github.com/dotcloud/docker/registry"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -662,7 +663,7 @@ func (srv *Server) ImageInsert(job *engine.Job) engine.Status {
|
|||
}
|
||||
defer file.Body.Close()
|
||||
|
||||
config, _, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.sysInfo)
|
||||
config, _, _, err := runconfig.Parse([]string{img.ID, "echo", "insert", url, path}, srv.runtime.sysInfo)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
@ -1043,7 +1044,7 @@ func (srv *Server) ContainerCommit(job *engine.Job) engine.Status {
|
|||
if container == nil {
|
||||
return job.Errorf("No such container: %s", name)
|
||||
}
|
||||
var config Config
|
||||
var config runconfig.Config
|
||||
if err := job.GetenvJson("config", &config); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
@ -1623,7 +1624,7 @@ func (srv *Server) ContainerCreate(job *engine.Job) engine.Status {
|
|||
} else if len(job.Args) > 1 {
|
||||
return job.Errorf("Usage: %s", job.Name)
|
||||
}
|
||||
config := ContainerConfigFromJob(job)
|
||||
config := runconfig.ContainerConfigFromJob(job)
|
||||
if config.Memory != 0 && config.Memory < 524288 {
|
||||
return job.Errorf("Minimum memory limit allowed is 512k")
|
||||
}
|
||||
|
@ -1989,7 +1990,7 @@ func (srv *Server) canDeleteImage(imgID string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error) {
|
||||
func (srv *Server) ImageGetCached(imgID string, config *runconfig.Config) (*Image, error) {
|
||||
|
||||
// Retrieve all images
|
||||
images, err := srv.runtime.graph.Map()
|
||||
|
@ -2013,7 +2014,7 @@ func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if CompareConfig(&img.ContainerConfig, config) {
|
||||
if runconfig.Compare(&img.ContainerConfig, config) {
|
||||
if match == nil || match.Created.Before(img.Created) {
|
||||
match = img
|
||||
}
|
||||
|
@ -2022,7 +2023,7 @@ func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error)
|
|||
return match, nil
|
||||
}
|
||||
|
||||
func (srv *Server) RegisterLinks(container *Container, hostConfig *HostConfig) error {
|
||||
func (srv *Server) RegisterLinks(container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
runtime := srv.runtime
|
||||
|
||||
if hostConfig != nil && hostConfig.Links != nil {
|
||||
|
@ -2066,7 +2067,7 @@ func (srv *Server) ContainerStart(job *engine.Job) engine.Status {
|
|||
}
|
||||
// If no environment was set, then no hostconfig was passed.
|
||||
if len(job.Environ()) > 0 {
|
||||
hostConfig := ContainerHostConfigFromJob(job)
|
||||
hostConfig := runconfig.ContainerHostConfigFromJob(job)
|
||||
// Validate the HostConfig binds. Make sure that:
|
||||
// 1) the source of a bind mount isn't /
|
||||
// The bind mount "/:/foo" isn't allowed.
|
||||
|
@ -2310,7 +2311,7 @@ func (srv *Server) JobInspect(job *engine.Job) engine.Status {
|
|||
}
|
||||
object = &struct {
|
||||
*Container
|
||||
HostConfig *HostConfig
|
||||
HostConfig *runconfig.HostConfig
|
||||
}{container, container.hostConfig}
|
||||
default:
|
||||
return job.Errorf("Unknown kind: %s", kind)
|
||||
|
|
205
utils.go
205
utils.go
|
@ -1,14 +1,12 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/archive"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/pkg/namesgenerator"
|
||||
"github.com/dotcloud/docker/pkg/opts"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
|
@ -16,204 +14,7 @@ type Change struct {
|
|||
archive.Change
|
||||
}
|
||||
|
||||
// Compare two Config struct. Do not compare the "Image" nor "Hostname" fields
|
||||
// If OpenStdin is set, then it differs
|
||||
func CompareConfig(a, b *Config) bool {
|
||||
if a == nil || b == nil ||
|
||||
a.OpenStdin || b.OpenStdin {
|
||||
return false
|
||||
}
|
||||
if a.AttachStdout != b.AttachStdout ||
|
||||
a.AttachStderr != b.AttachStderr ||
|
||||
a.User != b.User ||
|
||||
a.Memory != b.Memory ||
|
||||
a.MemorySwap != b.MemorySwap ||
|
||||
a.CpuShares != b.CpuShares ||
|
||||
a.OpenStdin != b.OpenStdin ||
|
||||
a.Tty != b.Tty ||
|
||||
a.VolumesFrom != b.VolumesFrom {
|
||||
return false
|
||||
}
|
||||
if len(a.Cmd) != len(b.Cmd) ||
|
||||
len(a.Dns) != len(b.Dns) ||
|
||||
len(a.Env) != len(b.Env) ||
|
||||
len(a.PortSpecs) != len(b.PortSpecs) ||
|
||||
len(a.ExposedPorts) != len(b.ExposedPorts) ||
|
||||
len(a.Entrypoint) != len(b.Entrypoint) ||
|
||||
len(a.Volumes) != len(b.Volumes) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(a.Cmd); i++ {
|
||||
if a.Cmd[i] != b.Cmd[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.Dns); i++ {
|
||||
if a.Dns[i] != b.Dns[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.Env); i++ {
|
||||
if a.Env[i] != b.Env[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.PortSpecs); i++ {
|
||||
if a.PortSpecs[i] != b.PortSpecs[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for k := range a.ExposedPorts {
|
||||
if _, exists := b.ExposedPorts[k]; !exists {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(a.Entrypoint); i++ {
|
||||
if a.Entrypoint[i] != b.Entrypoint[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for key := range a.Volumes {
|
||||
if _, exists := b.Volumes[key]; !exists {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func MergeConfig(userConf, imageConf *Config) error {
|
||||
if userConf.User == "" {
|
||||
userConf.User = imageConf.User
|
||||
}
|
||||
if userConf.Memory == 0 {
|
||||
userConf.Memory = imageConf.Memory
|
||||
}
|
||||
if userConf.MemorySwap == 0 {
|
||||
userConf.MemorySwap = imageConf.MemorySwap
|
||||
}
|
||||
if userConf.CpuShares == 0 {
|
||||
userConf.CpuShares = imageConf.CpuShares
|
||||
}
|
||||
if userConf.ExposedPorts == nil || len(userConf.ExposedPorts) == 0 {
|
||||
userConf.ExposedPorts = imageConf.ExposedPorts
|
||||
} else if imageConf.ExposedPorts != nil {
|
||||
if userConf.ExposedPorts == nil {
|
||||
userConf.ExposedPorts = make(nat.PortSet)
|
||||
}
|
||||
for port := range imageConf.ExposedPorts {
|
||||
if _, exists := userConf.ExposedPorts[port]; !exists {
|
||||
userConf.ExposedPorts[port] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if userConf.PortSpecs != nil && len(userConf.PortSpecs) > 0 {
|
||||
if userConf.ExposedPorts == nil {
|
||||
userConf.ExposedPorts = make(nat.PortSet)
|
||||
}
|
||||
ports, _, err := nat.ParsePortSpecs(userConf.PortSpecs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for port := range ports {
|
||||
if _, exists := userConf.ExposedPorts[port]; !exists {
|
||||
userConf.ExposedPorts[port] = struct{}{}
|
||||
}
|
||||
}
|
||||
userConf.PortSpecs = nil
|
||||
}
|
||||
if imageConf.PortSpecs != nil && len(imageConf.PortSpecs) > 0 {
|
||||
utils.Debugf("Migrating image port specs to containter: %s", strings.Join(imageConf.PortSpecs, ", "))
|
||||
if userConf.ExposedPorts == nil {
|
||||
userConf.ExposedPorts = make(nat.PortSet)
|
||||
}
|
||||
|
||||
ports, _, err := nat.ParsePortSpecs(imageConf.PortSpecs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for port := range ports {
|
||||
if _, exists := userConf.ExposedPorts[port]; !exists {
|
||||
userConf.ExposedPorts[port] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !userConf.Tty {
|
||||
userConf.Tty = imageConf.Tty
|
||||
}
|
||||
if !userConf.OpenStdin {
|
||||
userConf.OpenStdin = imageConf.OpenStdin
|
||||
}
|
||||
if !userConf.StdinOnce {
|
||||
userConf.StdinOnce = imageConf.StdinOnce
|
||||
}
|
||||
if userConf.Env == nil || len(userConf.Env) == 0 {
|
||||
userConf.Env = imageConf.Env
|
||||
} else {
|
||||
for _, imageEnv := range imageConf.Env {
|
||||
found := false
|
||||
imageEnvKey := strings.Split(imageEnv, "=")[0]
|
||||
for _, userEnv := range userConf.Env {
|
||||
userEnvKey := strings.Split(userEnv, "=")[0]
|
||||
if imageEnvKey == userEnvKey {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
userConf.Env = append(userConf.Env, imageEnv)
|
||||
}
|
||||
}
|
||||
}
|
||||
if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
|
||||
userConf.Cmd = imageConf.Cmd
|
||||
}
|
||||
if userConf.Dns == nil || len(userConf.Dns) == 0 {
|
||||
userConf.Dns = imageConf.Dns
|
||||
} else {
|
||||
//duplicates aren't an issue here
|
||||
userConf.Dns = append(userConf.Dns, imageConf.Dns...)
|
||||
}
|
||||
if userConf.Entrypoint == nil || len(userConf.Entrypoint) == 0 {
|
||||
userConf.Entrypoint = imageConf.Entrypoint
|
||||
}
|
||||
if userConf.WorkingDir == "" {
|
||||
userConf.WorkingDir = imageConf.WorkingDir
|
||||
}
|
||||
if userConf.VolumesFrom == "" {
|
||||
userConf.VolumesFrom = imageConf.VolumesFrom
|
||||
}
|
||||
if userConf.Volumes == nil || len(userConf.Volumes) == 0 {
|
||||
userConf.Volumes = imageConf.Volumes
|
||||
} else {
|
||||
for k, v := range imageConf.Volumes {
|
||||
userConf.Volumes[k] = v
|
||||
}
|
||||
}
|
||||
return 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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func migratePortMappings(config *Config, hostConfig *HostConfig) error {
|
||||
func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostConfig) error {
|
||||
if config.PortSpecs != nil {
|
||||
ports, bindings, err := nat.ParsePortSpecs(config.PortSpecs)
|
||||
if err != nil {
|
||||
|
@ -222,7 +23,7 @@ func migratePortMappings(config *Config, hostConfig *HostConfig) error {
|
|||
config.PortSpecs = nil
|
||||
if len(bindings) > 0 {
|
||||
if hostConfig == nil {
|
||||
hostConfig = &HostConfig{}
|
||||
hostConfig = &runconfig.HostConfig{}
|
||||
}
|
||||
hostConfig.PortBindings = bindings
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue