func setEnvFromImageConfig(config, imageConfig *containertypes.Config) { // Set PATH in ENV if needed setPathFromImageConfig(config, imageConfig) containerEnv := make(map[string]string, len(config.Env)) for _, env := range config.Env { kv := strings.SplitN(env, "=", 2) var val string if len(kv) == 2 { val = kv[1] } containerEnv[kv[0]] = val } // Set TERM to xterm if tty is set, unless user supplied a different TERM if config.Tty { if _, ok := containerEnv["TERM"]; !ok { config.Env = append(config.Env, "TERM=xterm") } } // add remaining environment variables from the image config to the container // config, taking care not to overwrite anything for _, imageEnv := range imageConfig.Env { key := strings.SplitN(imageEnv, "=", 2)[0] // is environment variable already set in container config? if _, ok := containerEnv[key]; !ok { // no? let's copy it from the image config config.Env = append(config.Env, imageEnv) } } }
func setPathFromImageConfig(config, imageConfig *containertypes.Config) { // check if user supplied PATH environment variable at creation time for _, v := range config.Env { if strings.HasPrefix(v, "PATH=") { // a PATH is set, bail return } } // check to see if the image this container is created from supplies a PATH for _, v := range imageConfig.Env { if strings.HasPrefix(v, "PATH=") { // a PATH was found, add it to the config config.Env = append(config.Env, v) return } } // no PATH set, use the default config.Env = append(config.Env, fmt.Sprintf("PATH=%s", defaultEnvPath)) }
// merge merges two Config, the image container configuration (defaults values), // and the user container configuration, either passed by the API or generated // by the cli. // It will mutate the specified user configuration (userConf) with the image // configuration where the user configuration is incomplete. func merge(userConf, imageConf *containertypes.Config) error { if userConf.User == "" { userConf.User = imageConf.User } if 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 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 break } } if !found { userConf.Env = append(userConf.Env, imageEnv) } } } if userConf.Labels == nil { userConf.Labels = map[string]string{} } if imageConf.Labels != nil { for l := range userConf.Labels { imageConf.Labels[l] = userConf.Labels[l] } userConf.Labels = imageConf.Labels } if userConf.Entrypoint.Len() == 0 { if userConf.Cmd.Len() == 0 { userConf.Cmd = imageConf.Cmd } if userConf.Entrypoint == nil { userConf.Entrypoint = imageConf.Entrypoint } } if userConf.WorkingDir == "" { userConf.WorkingDir = imageConf.WorkingDir } if len(userConf.Volumes) == 0 { userConf.Volumes = imageConf.Volumes } else { for k, v := range imageConf.Volumes { userConf.Volumes[k] = v } } return nil }
// merge merges two Config, the image container configuration (defaults values), // and the user container configuration, either passed by the API or generated // by the cli. // It will mutate the specified user configuration (userConf) with the image // configuration where the user configuration is incomplete. func merge(userConf, imageConf *containertypes.Config) error { if userConf.User == "" { userConf.User = imageConf.User } if 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 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 break } } if !found { userConf.Env = append(userConf.Env, imageEnv) } } } if userConf.Labels == nil { userConf.Labels = map[string]string{} } if imageConf.Labels != nil { for l := range userConf.Labels { imageConf.Labels[l] = userConf.Labels[l] } userConf.Labels = imageConf.Labels } if len(userConf.Entrypoint) == 0 { if len(userConf.Cmd) == 0 { userConf.Cmd = imageConf.Cmd userConf.ArgsEscaped = imageConf.ArgsEscaped } if userConf.Entrypoint == nil { userConf.Entrypoint = imageConf.Entrypoint } } if imageConf.Healthcheck != nil { if userConf.Healthcheck == nil { userConf.Healthcheck = imageConf.Healthcheck } else { if len(userConf.Healthcheck.Test) == 0 { userConf.Healthcheck.Test = imageConf.Healthcheck.Test } if userConf.Healthcheck.Interval == 0 { userConf.Healthcheck.Interval = imageConf.Healthcheck.Interval } if userConf.Healthcheck.Timeout == 0 { userConf.Healthcheck.Timeout = imageConf.Healthcheck.Timeout } if userConf.Healthcheck.Retries == 0 { userConf.Healthcheck.Retries = imageConf.Healthcheck.Retries } } } if userConf.WorkingDir == "" { userConf.WorkingDir = imageConf.WorkingDir } if len(userConf.Volumes) == 0 { userConf.Volumes = imageConf.Volumes } else { for k, v := range imageConf.Volumes { userConf.Volumes[k] = v } } if userConf.StopSignal == "" { userConf.StopSignal = imageConf.StopSignal } return nil }
// BuildContainerConfig creates a cluster.ContainerConfig from a Config, HostConfig, and NetworkingConfig func BuildContainerConfig(c container.Config, h container.HostConfig, n network.NetworkingConfig) *ContainerConfig { var ( affinities []string constraints []string reschedulePolicies []string env []string ) // only for tests if c.Labels == nil { c.Labels = make(map[string]string) } // parse affinities from labels (ex. docker run --label 'com.docker.swarm.affinities=["container==redis","image==nginx"]') if labels, ok := c.Labels[SwarmLabelNamespace+".affinities"]; ok { json.Unmarshal([]byte(labels), &affinities) } // parse constraints from labels (ex. docker run --label 'com.docker.swarm.constraints=["region==us-east","storage==ssd"]') if labels, ok := c.Labels[SwarmLabelNamespace+".constraints"]; ok { json.Unmarshal([]byte(labels), &constraints) } // parse reschedule policy from labels (ex. docker run --label 'com.docker.swarm.reschedule-policies=["on-node-failure"]') if labels, ok := c.Labels[SwarmLabelNamespace+".reschedule-policies"]; ok { json.Unmarshal([]byte(labels), &reschedulePolicies) } // parse affinities/constraints/reschedule policies from env (ex. docker run -e affinity:container==redis -e affinity:image==nginx -e constraint:region==us-east -e constraint:storage==ssd -e reschedule:off) for _, e := range c.Env { if ok, key, value := parseEnv(e); ok && key == "affinity" { affinities = append(affinities, value) } else if ok && key == "constraint" { constraints = append(constraints, value) } else if ok && key == "reschedule" { reschedulePolicies = append(reschedulePolicies, value) } else { env = append(env, e) } } // remove affinities/constraints/reschedule policies from env c.Env = env // store affinities in labels if len(affinities) > 0 { if labels, err := json.Marshal(affinities); err == nil { c.Labels[SwarmLabelNamespace+".affinities"] = string(labels) } } // store constraints in labels if len(constraints) > 0 { if labels, err := json.Marshal(constraints); err == nil { c.Labels[SwarmLabelNamespace+".constraints"] = string(labels) } } // store reschedule policies in labels if len(reschedulePolicies) > 0 { if labels, err := json.Marshal(reschedulePolicies); err == nil { c.Labels[SwarmLabelNamespace+".reschedule-policies"] = string(labels) } } return &ContainerConfig{c, h, n} }