container.go 11 KB

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