container.go 9.9 KB

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