container.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. package convert
  2. import (
  3. "errors"
  4. "fmt"
  5. "strings"
  6. "github.com/Sirupsen/logrus"
  7. container "github.com/docker/docker/api/types/container"
  8. mounttypes "github.com/docker/docker/api/types/mount"
  9. types "github.com/docker/docker/api/types/swarm"
  10. swarmapi "github.com/docker/swarmkit/api"
  11. gogotypes "github.com/gogo/protobuf/types"
  12. )
  13. func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec {
  14. containerSpec := types.ContainerSpec{
  15. Image: c.Image,
  16. Labels: c.Labels,
  17. Command: c.Command,
  18. Args: c.Args,
  19. Hostname: c.Hostname,
  20. Env: c.Env,
  21. Dir: c.Dir,
  22. User: c.User,
  23. Groups: c.Groups,
  24. StopSignal: c.StopSignal,
  25. TTY: c.TTY,
  26. OpenStdin: c.OpenStdin,
  27. ReadOnly: c.ReadOnly,
  28. Hosts: c.Hosts,
  29. Secrets: secretReferencesFromGRPC(c.Secrets),
  30. Configs: configReferencesFromGRPC(c.Configs),
  31. }
  32. if c.DNSConfig != nil {
  33. containerSpec.DNSConfig = &types.DNSConfig{
  34. Nameservers: c.DNSConfig.Nameservers,
  35. Search: c.DNSConfig.Search,
  36. Options: c.DNSConfig.Options,
  37. }
  38. }
  39. // Privileges
  40. if c.Privileges != nil {
  41. containerSpec.Privileges = &types.Privileges{}
  42. if c.Privileges.CredentialSpec != nil {
  43. containerSpec.Privileges.CredentialSpec = &types.CredentialSpec{}
  44. switch c.Privileges.CredentialSpec.Source.(type) {
  45. case *swarmapi.Privileges_CredentialSpec_File:
  46. containerSpec.Privileges.CredentialSpec.File = c.Privileges.CredentialSpec.GetFile()
  47. case *swarmapi.Privileges_CredentialSpec_Registry:
  48. containerSpec.Privileges.CredentialSpec.Registry = c.Privileges.CredentialSpec.GetRegistry()
  49. }
  50. }
  51. if c.Privileges.SELinuxContext != nil {
  52. containerSpec.Privileges.SELinuxContext = &types.SELinuxContext{
  53. Disable: c.Privileges.SELinuxContext.Disable,
  54. User: c.Privileges.SELinuxContext.User,
  55. Type: c.Privileges.SELinuxContext.Type,
  56. Role: c.Privileges.SELinuxContext.Role,
  57. Level: c.Privileges.SELinuxContext.Level,
  58. }
  59. }
  60. }
  61. // Mounts
  62. for _, m := range c.Mounts {
  63. mount := mounttypes.Mount{
  64. Target: m.Target,
  65. Source: m.Source,
  66. Type: mounttypes.Type(strings.ToLower(swarmapi.Mount_MountType_name[int32(m.Type)])),
  67. ReadOnly: m.ReadOnly,
  68. }
  69. if m.BindOptions != nil {
  70. mount.BindOptions = &mounttypes.BindOptions{
  71. Propagation: mounttypes.Propagation(strings.ToLower(swarmapi.Mount_BindOptions_MountPropagation_name[int32(m.BindOptions.Propagation)])),
  72. }
  73. }
  74. if m.VolumeOptions != nil {
  75. mount.VolumeOptions = &mounttypes.VolumeOptions{
  76. NoCopy: m.VolumeOptions.NoCopy,
  77. Labels: m.VolumeOptions.Labels,
  78. }
  79. if m.VolumeOptions.DriverConfig != nil {
  80. mount.VolumeOptions.DriverConfig = &mounttypes.Driver{
  81. Name: m.VolumeOptions.DriverConfig.Name,
  82. Options: m.VolumeOptions.DriverConfig.Options,
  83. }
  84. }
  85. }
  86. if m.TmpfsOptions != nil {
  87. mount.TmpfsOptions = &mounttypes.TmpfsOptions{
  88. SizeBytes: m.TmpfsOptions.SizeBytes,
  89. Mode: m.TmpfsOptions.Mode,
  90. }
  91. }
  92. containerSpec.Mounts = append(containerSpec.Mounts, mount)
  93. }
  94. if c.StopGracePeriod != nil {
  95. grace, _ := gogotypes.DurationFromProto(c.StopGracePeriod)
  96. containerSpec.StopGracePeriod = &grace
  97. }
  98. if c.Healthcheck != nil {
  99. containerSpec.Healthcheck = healthConfigFromGRPC(c.Healthcheck)
  100. }
  101. return containerSpec
  102. }
  103. func secretReferencesToGRPC(sr []*types.SecretReference) []*swarmapi.SecretReference {
  104. refs := make([]*swarmapi.SecretReference, 0, len(sr))
  105. for _, s := range sr {
  106. ref := &swarmapi.SecretReference{
  107. SecretID: s.SecretID,
  108. SecretName: s.SecretName,
  109. }
  110. if s.File != nil {
  111. ref.Target = &swarmapi.SecretReference_File{
  112. File: &swarmapi.FileTarget{
  113. Name: s.File.Name,
  114. UID: s.File.UID,
  115. GID: s.File.GID,
  116. Mode: s.File.Mode,
  117. },
  118. }
  119. }
  120. refs = append(refs, ref)
  121. }
  122. return refs
  123. }
  124. func secretReferencesFromGRPC(sr []*swarmapi.SecretReference) []*types.SecretReference {
  125. refs := make([]*types.SecretReference, 0, len(sr))
  126. for _, s := range sr {
  127. target := s.GetFile()
  128. if target == nil {
  129. // not a file target
  130. logrus.Warnf("secret target not a file: secret=%s", s.SecretID)
  131. continue
  132. }
  133. refs = append(refs, &types.SecretReference{
  134. File: &types.SecretReferenceFileTarget{
  135. Name: target.Name,
  136. UID: target.UID,
  137. GID: target.GID,
  138. Mode: target.Mode,
  139. },
  140. SecretID: s.SecretID,
  141. SecretName: s.SecretName,
  142. })
  143. }
  144. return refs
  145. }
  146. func configReferencesToGRPC(sr []*types.ConfigReference) []*swarmapi.ConfigReference {
  147. refs := make([]*swarmapi.ConfigReference, 0, len(sr))
  148. for _, s := range sr {
  149. ref := &swarmapi.ConfigReference{
  150. ConfigID: s.ConfigID,
  151. ConfigName: s.ConfigName,
  152. }
  153. if s.File != nil {
  154. ref.Target = &swarmapi.ConfigReference_File{
  155. File: &swarmapi.FileTarget{
  156. Name: s.File.Name,
  157. UID: s.File.UID,
  158. GID: s.File.GID,
  159. Mode: s.File.Mode,
  160. },
  161. }
  162. }
  163. refs = append(refs, ref)
  164. }
  165. return refs
  166. }
  167. func configReferencesFromGRPC(sr []*swarmapi.ConfigReference) []*types.ConfigReference {
  168. refs := make([]*types.ConfigReference, 0, len(sr))
  169. for _, s := range sr {
  170. target := s.GetFile()
  171. if target == nil {
  172. // not a file target
  173. logrus.Warnf("config target not a file: config=%s", s.ConfigID)
  174. continue
  175. }
  176. refs = append(refs, &types.ConfigReference{
  177. File: &types.ConfigReferenceFileTarget{
  178. Name: target.Name,
  179. UID: target.UID,
  180. GID: target.GID,
  181. Mode: target.Mode,
  182. },
  183. ConfigID: s.ConfigID,
  184. ConfigName: s.ConfigName,
  185. })
  186. }
  187. return refs
  188. }
  189. func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
  190. containerSpec := &swarmapi.ContainerSpec{
  191. Image: c.Image,
  192. Labels: c.Labels,
  193. Command: c.Command,
  194. Args: c.Args,
  195. Hostname: c.Hostname,
  196. Env: c.Env,
  197. Dir: c.Dir,
  198. User: c.User,
  199. Groups: c.Groups,
  200. StopSignal: c.StopSignal,
  201. TTY: c.TTY,
  202. OpenStdin: c.OpenStdin,
  203. ReadOnly: c.ReadOnly,
  204. Hosts: c.Hosts,
  205. Secrets: secretReferencesToGRPC(c.Secrets),
  206. Configs: configReferencesToGRPC(c.Configs),
  207. }
  208. if c.DNSConfig != nil {
  209. containerSpec.DNSConfig = &swarmapi.ContainerSpec_DNSConfig{
  210. Nameservers: c.DNSConfig.Nameservers,
  211. Search: c.DNSConfig.Search,
  212. Options: c.DNSConfig.Options,
  213. }
  214. }
  215. if c.StopGracePeriod != nil {
  216. containerSpec.StopGracePeriod = gogotypes.DurationProto(*c.StopGracePeriod)
  217. }
  218. // Privileges
  219. if c.Privileges != nil {
  220. containerSpec.Privileges = &swarmapi.Privileges{}
  221. if c.Privileges.CredentialSpec != nil {
  222. containerSpec.Privileges.CredentialSpec = &swarmapi.Privileges_CredentialSpec{}
  223. if c.Privileges.CredentialSpec.File != "" && c.Privileges.CredentialSpec.Registry != "" {
  224. return nil, errors.New("cannot specify both \"file\" and \"registry\" credential specs")
  225. }
  226. if c.Privileges.CredentialSpec.File != "" {
  227. containerSpec.Privileges.CredentialSpec.Source = &swarmapi.Privileges_CredentialSpec_File{
  228. File: c.Privileges.CredentialSpec.File,
  229. }
  230. } else if c.Privileges.CredentialSpec.Registry != "" {
  231. containerSpec.Privileges.CredentialSpec.Source = &swarmapi.Privileges_CredentialSpec_Registry{
  232. Registry: c.Privileges.CredentialSpec.Registry,
  233. }
  234. } else {
  235. return nil, errors.New("must either provide \"file\" or \"registry\" for credential spec")
  236. }
  237. }
  238. if c.Privileges.SELinuxContext != nil {
  239. containerSpec.Privileges.SELinuxContext = &swarmapi.Privileges_SELinuxContext{
  240. Disable: c.Privileges.SELinuxContext.Disable,
  241. User: c.Privileges.SELinuxContext.User,
  242. Type: c.Privileges.SELinuxContext.Type,
  243. Role: c.Privileges.SELinuxContext.Role,
  244. Level: c.Privileges.SELinuxContext.Level,
  245. }
  246. }
  247. }
  248. // Mounts
  249. for _, m := range c.Mounts {
  250. mount := swarmapi.Mount{
  251. Target: m.Target,
  252. Source: m.Source,
  253. ReadOnly: m.ReadOnly,
  254. }
  255. if mountType, ok := swarmapi.Mount_MountType_value[strings.ToUpper(string(m.Type))]; ok {
  256. mount.Type = swarmapi.Mount_MountType(mountType)
  257. } else if string(m.Type) != "" {
  258. return nil, fmt.Errorf("invalid MountType: %q", m.Type)
  259. }
  260. if m.BindOptions != nil {
  261. if mountPropagation, ok := swarmapi.Mount_BindOptions_MountPropagation_value[strings.ToUpper(string(m.BindOptions.Propagation))]; ok {
  262. mount.BindOptions = &swarmapi.Mount_BindOptions{Propagation: swarmapi.Mount_BindOptions_MountPropagation(mountPropagation)}
  263. } else if string(m.BindOptions.Propagation) != "" {
  264. return nil, fmt.Errorf("invalid MountPropagation: %q", m.BindOptions.Propagation)
  265. }
  266. }
  267. if m.VolumeOptions != nil {
  268. mount.VolumeOptions = &swarmapi.Mount_VolumeOptions{
  269. NoCopy: m.VolumeOptions.NoCopy,
  270. Labels: m.VolumeOptions.Labels,
  271. }
  272. if m.VolumeOptions.DriverConfig != nil {
  273. mount.VolumeOptions.DriverConfig = &swarmapi.Driver{
  274. Name: m.VolumeOptions.DriverConfig.Name,
  275. Options: m.VolumeOptions.DriverConfig.Options,
  276. }
  277. }
  278. }
  279. if m.TmpfsOptions != nil {
  280. mount.TmpfsOptions = &swarmapi.Mount_TmpfsOptions{
  281. SizeBytes: m.TmpfsOptions.SizeBytes,
  282. Mode: m.TmpfsOptions.Mode,
  283. }
  284. }
  285. containerSpec.Mounts = append(containerSpec.Mounts, mount)
  286. }
  287. if c.Healthcheck != nil {
  288. containerSpec.Healthcheck = healthConfigToGRPC(c.Healthcheck)
  289. }
  290. return containerSpec, nil
  291. }
  292. func healthConfigFromGRPC(h *swarmapi.HealthConfig) *container.HealthConfig {
  293. interval, _ := gogotypes.DurationFromProto(h.Interval)
  294. timeout, _ := gogotypes.DurationFromProto(h.Timeout)
  295. startPeriod, _ := gogotypes.DurationFromProto(h.StartPeriod)
  296. return &container.HealthConfig{
  297. Test: h.Test,
  298. Interval: interval,
  299. Timeout: timeout,
  300. Retries: int(h.Retries),
  301. StartPeriod: startPeriod,
  302. }
  303. }
  304. func healthConfigToGRPC(h *container.HealthConfig) *swarmapi.HealthConfig {
  305. return &swarmapi.HealthConfig{
  306. Test: h.Test,
  307. Interval: gogotypes.DurationProto(h.Interval),
  308. Timeout: gogotypes.DurationProto(h.Timeout),
  309. Retries: int32(h.Retries),
  310. StartPeriod: gogotypes.DurationProto(h.StartPeriod),
  311. }
  312. }