utils.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package docker
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "strings"
  6. )
  7. // Compare two Config struct. Do not compare the "Image" nor "Hostname" fields
  8. // If OpenStdin is set, then it differs
  9. func CompareConfig(a, b *Config) bool {
  10. if a == nil || b == nil ||
  11. a.OpenStdin || b.OpenStdin {
  12. return false
  13. }
  14. if a.AttachStdout != b.AttachStdout ||
  15. a.AttachStderr != b.AttachStderr ||
  16. a.User != b.User ||
  17. a.Memory != b.Memory ||
  18. a.MemorySwap != b.MemorySwap ||
  19. a.CpuShares != b.CpuShares ||
  20. a.OpenStdin != b.OpenStdin ||
  21. a.Tty != b.Tty ||
  22. a.VolumesFrom != b.VolumesFrom {
  23. return false
  24. }
  25. if len(a.Cmd) != len(b.Cmd) ||
  26. len(a.Dns) != len(b.Dns) ||
  27. len(a.Env) != len(b.Env) ||
  28. len(a.PortSpecs) != len(b.PortSpecs) ||
  29. len(a.Entrypoint) != len(b.Entrypoint) ||
  30. len(a.Volumes) != len(b.Volumes) {
  31. return false
  32. }
  33. for i := 0; i < len(a.Cmd); i++ {
  34. if a.Cmd[i] != b.Cmd[i] {
  35. return false
  36. }
  37. }
  38. for i := 0; i < len(a.Dns); i++ {
  39. if a.Dns[i] != b.Dns[i] {
  40. return false
  41. }
  42. }
  43. for i := 0; i < len(a.Env); i++ {
  44. if a.Env[i] != b.Env[i] {
  45. return false
  46. }
  47. }
  48. for i := 0; i < len(a.PortSpecs); i++ {
  49. if a.PortSpecs[i] != b.PortSpecs[i] {
  50. return false
  51. }
  52. }
  53. for i := 0; i < len(a.Entrypoint); i++ {
  54. if a.Entrypoint[i] != b.Entrypoint[i] {
  55. return false
  56. }
  57. }
  58. for key := range a.Volumes {
  59. if _, exists := b.Volumes[key]; !exists {
  60. return false
  61. }
  62. }
  63. return true
  64. }
  65. func MergeConfig(userConf, imageConf *Config) {
  66. if userConf.User == "" {
  67. userConf.User = imageConf.User
  68. }
  69. if userConf.Memory == 0 {
  70. userConf.Memory = imageConf.Memory
  71. }
  72. if userConf.MemorySwap == 0 {
  73. userConf.MemorySwap = imageConf.MemorySwap
  74. }
  75. if userConf.CpuShares == 0 {
  76. userConf.CpuShares = imageConf.CpuShares
  77. }
  78. if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
  79. userConf.PortSpecs = imageConf.PortSpecs
  80. } else {
  81. for _, imagePortSpec := range imageConf.PortSpecs {
  82. found := false
  83. imageNat, _ := parseNat(imagePortSpec)
  84. for _, userPortSpec := range userConf.PortSpecs {
  85. userNat, _ := parseNat(userPortSpec)
  86. if imageNat.Proto == userNat.Proto && imageNat.Backend == userNat.Backend {
  87. found = true
  88. }
  89. }
  90. if !found {
  91. userConf.PortSpecs = append(userConf.PortSpecs, imagePortSpec)
  92. }
  93. }
  94. }
  95. if !userConf.Tty {
  96. userConf.Tty = imageConf.Tty
  97. }
  98. if !userConf.OpenStdin {
  99. userConf.OpenStdin = imageConf.OpenStdin
  100. }
  101. if !userConf.StdinOnce {
  102. userConf.StdinOnce = imageConf.StdinOnce
  103. }
  104. if userConf.Env == nil || len(userConf.Env) == 0 {
  105. userConf.Env = imageConf.Env
  106. } else {
  107. for _, imageEnv := range imageConf.Env {
  108. found := false
  109. imageEnvKey := strings.Split(imageEnv, "=")[0]
  110. for _, userEnv := range userConf.Env {
  111. userEnvKey := strings.Split(userEnv, "=")[0]
  112. if imageEnvKey == userEnvKey {
  113. found = true
  114. }
  115. }
  116. if !found {
  117. userConf.Env = append(userConf.Env, imageEnv)
  118. }
  119. }
  120. }
  121. if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
  122. userConf.Cmd = imageConf.Cmd
  123. }
  124. if userConf.Dns == nil || len(userConf.Dns) == 0 {
  125. userConf.Dns = imageConf.Dns
  126. } else {
  127. //duplicates aren't an issue here
  128. userConf.Dns = append(userConf.Dns, imageConf.Dns...)
  129. }
  130. if userConf.Entrypoint == nil || len(userConf.Entrypoint) == 0 {
  131. userConf.Entrypoint = imageConf.Entrypoint
  132. }
  133. if userConf.WorkingDir == "" {
  134. userConf.WorkingDir = imageConf.WorkingDir
  135. }
  136. if userConf.VolumesFrom == "" {
  137. userConf.VolumesFrom = imageConf.VolumesFrom
  138. }
  139. if userConf.Volumes == nil || len(userConf.Volumes) == 0 {
  140. userConf.Volumes = imageConf.Volumes
  141. } else {
  142. for k, v := range imageConf.Volumes {
  143. userConf.Volumes[k] = v
  144. }
  145. }
  146. }
  147. func parseLxcConfOpts(opts ListOpts) ([]KeyValuePair, error) {
  148. out := make([]KeyValuePair, len(opts))
  149. for i, o := range opts {
  150. k, v, err := parseLxcOpt(o)
  151. if err != nil {
  152. return nil, err
  153. }
  154. out[i] = KeyValuePair{Key: k, Value: v}
  155. }
  156. return out, nil
  157. }
  158. func parseLxcOpt(opt string) (string, string, error) {
  159. parts := strings.SplitN(opt, "=", 2)
  160. if len(parts) != 2 {
  161. return "", "", fmt.Errorf("Unable to parse lxc conf option: %s", opt)
  162. }
  163. return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
  164. }
  165. func RootIsShared() bool {
  166. if data, err := ioutil.ReadFile("/proc/self/mountinfo"); err == nil {
  167. for _, line := range strings.Split(string(data), "\n") {
  168. cols := strings.Split(line, " ")
  169. if len(cols) >= 6 && cols[3] == "/" && cols[4] == "/" {
  170. return strings.HasPrefix(cols[6], "shared")
  171. }
  172. }
  173. }
  174. // No idea, probably safe to assume so
  175. return true
  176. }