| package docker |
| |
| import ( |
| "fmt" |
| "strings" |
| ) |
| |
| // 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.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 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.PortSpecs == nil || len(userConf.PortSpecs) == 0 { |
| userConf.PortSpecs = imageConf.PortSpecs |
| } else { |
| for _, imagePortSpec := range imageConf.PortSpecs { |
| found := false |
| imageNat, err := parseNat(imagePortSpec) |
| if err != nil { |
| return err |
| } |
| for _, userPortSpec := range userConf.PortSpecs { |
| userNat, err := parseNat(userPortSpec) |
| if err != nil { |
| return err |
| } |
| if imageNat.Proto == userNat.Proto && imageNat.Backend == userNat.Backend { |
| found = true |
| } |
| } |
| if !found { |
| userConf.PortSpecs = append(userConf.PortSpecs, imagePortSpec) |
| } |
| } |
| } |
| 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 ListOpts) ([]KeyValuePair, error) { |
| out := make([]KeyValuePair, len(opts)) |
| for i, o := range opts { |
| k, v, err := parseLxcOpt(o) |
| if err != nil { |
| return nil, err |
| } |
| out[i] = KeyValuePair{Key: k, Value: v} |
| } |
| return out, nil |
| } |
| |
| func parseLxcOpt(opt string) (string, string, error) { |
| parts := strings.SplitN(opt, "=", 2) |
| if len(parts) != 2 { |
| return "", "", fmt.Errorf("Unable to parse lxc conf option: %s", opt) |
| } |
| return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil |
| } |