pod_template.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package k8s
  15. import (
  16. "fmt"
  17. "strings"
  18. "yunion.io/x/jsonutils"
  19. )
  20. // only support one container now
  21. type K8sPodTemplateOptions struct {
  22. // container option
  23. name string
  24. Image string `help:"The image for the container to run" required:"true"`
  25. Command string `help:"Container start command"`
  26. Args string `help:"Container start command args"`
  27. Env []string `help:"Environment variables to set in container"`
  28. Mem int `help:"Memory request MB size"`
  29. Cpu float64 `help:"Cpu request cores"`
  30. Pvc []string `help:"PVC volume desc, format is <pvc_name>:<mount_point>"`
  31. RunAsPrivileged bool `help:"Whether to run the container as privileged user"`
  32. // pod option
  33. RestartPolicy string `help:"Pod restart policy" choices:"Always|OnFailure|Never"`
  34. RegistrySecret []string `help:"Docker registry secret"`
  35. }
  36. func (o *K8sPodTemplateOptions) setContainerName(name string) {
  37. o.name = name
  38. }
  39. func (o K8sPodTemplateOptions) Params() (*jsonutils.JSONDict, error) {
  40. params := jsonutils.NewDict()
  41. container := jsonutils.NewDict()
  42. containers := jsonutils.NewArray()
  43. container.Add(jsonutils.NewString(o.name), "name")
  44. container.Add(jsonutils.NewString(o.Image), "image")
  45. if len(o.Command) != 0 {
  46. container.Add(jsonutils.NewStringArray(strings.Split(o.Command, " ")), "command")
  47. }
  48. if len(o.Args) != 0 {
  49. container.Add(jsonutils.NewStringArray(strings.Split(o.Args, " ")), "args")
  50. }
  51. resourcesReq := jsonutils.NewDict()
  52. if o.Cpu > 0 {
  53. resourcesReq.Add(jsonutils.NewString(fmt.Sprintf("%dm", int64(o.Cpu*1000))), "cpu")
  54. }
  55. if o.Mem > 0 {
  56. resourcesReq.Add(jsonutils.NewString(fmt.Sprintf("%dMi", o.Mem)), "memory")
  57. }
  58. if len(o.Env) != 0 {
  59. envs := jsonutils.NewArray()
  60. for _, e := range o.Env {
  61. parts := strings.Split(e, "=")
  62. if len(parts) != 2 {
  63. return nil, fmt.Errorf("Bad env value: %v", e)
  64. }
  65. envObj := jsonutils.NewDict()
  66. envObj.Add(jsonutils.NewString(parts[0]), "name")
  67. envObj.Add(jsonutils.NewString(parts[1]), "value")
  68. envs.Add(envObj)
  69. }
  70. container.Add(envs, "env")
  71. }
  72. if o.RunAsPrivileged {
  73. container.Add(jsonutils.JSONTrue, "securityContext", "privileged")
  74. }
  75. vols := jsonutils.NewArray()
  76. volMounts := jsonutils.NewArray()
  77. if len(o.Pvc) != 0 {
  78. for _, pvc := range o.Pvc {
  79. vol, volMount, err := parsePvc(pvc)
  80. if err != nil {
  81. return nil, err
  82. }
  83. vols.Add(vol)
  84. volMounts.Add(volMount)
  85. }
  86. }
  87. container.Add(resourcesReq, "resources", "requests")
  88. if volMounts.Length() > 0 {
  89. container.Add(volMounts, "volumeMounts")
  90. }
  91. containers.Add(container)
  92. if o.RestartPolicy != "" {
  93. params.Add(jsonutils.NewString(o.RestartPolicy), "restartPolicy")
  94. }
  95. if len(o.RegistrySecret) != 0 {
  96. rs := jsonutils.NewArray()
  97. for _, s := range o.RegistrySecret {
  98. obj := jsonutils.NewDict()
  99. obj.Add(jsonutils.NewString(s), "name")
  100. rs.Add(obj)
  101. }
  102. params.Add(rs, "imagePullSecrets")
  103. }
  104. params.Add(containers, "containers")
  105. if vols.Length() > 0 {
  106. params.Add(vols, "volumes")
  107. }
  108. return params, nil
  109. }
  110. func parsePvc(pvcDesc string) (jsonutils.JSONObject, jsonutils.JSONObject, error) {
  111. parts := strings.Split(pvcDesc, ":")
  112. if len(parts) != 2 {
  113. return nil, nil, fmt.Errorf("Invalid PVC desc string: %s", pvcDesc)
  114. }
  115. pvcName := parts[0]
  116. pvcMntPath := parts[1]
  117. pvcVol := jsonutils.NewDict()
  118. pvcVol.Add(jsonutils.NewString(pvcName), "claimName")
  119. vol := jsonutils.NewDict()
  120. vol.Add(jsonutils.NewString(pvcName), "name")
  121. vol.Add(pvcVol, "persistentVolumeClaim")
  122. volMnt := jsonutils.NewDict()
  123. volMnt.Add(jsonutils.NewString(pvcName), "name")
  124. volMnt.Add(jsonutils.NewString(pvcMntPath), "mountPath")
  125. return vol, volMnt, nil
  126. }
  127. type IOption interface {
  128. Params() (*jsonutils.JSONDict, error)
  129. }
  130. func attachData(o IOption, data *jsonutils.JSONDict, keys ...string) error {
  131. ret, err := o.Params()
  132. if err != nil {
  133. return err
  134. }
  135. if ret == nil {
  136. return nil
  137. }
  138. data.Add(ret, keys...)
  139. return nil
  140. }
  141. func (o K8sPodTemplateOptions) Attach(data *jsonutils.JSONDict) error {
  142. return attachData(o, data, "template", "spec")
  143. }
  144. type K8sLabelOptions struct {
  145. Label []string `help:"Labels to apply to the pod(s), e.g. 'env=prod'"`
  146. }
  147. func (o K8sLabelOptions) Params() (*jsonutils.JSONDict, error) {
  148. labels := map[string]string{}
  149. for _, label := range o.Label {
  150. k, v, err := parseLabel(label)
  151. if err != nil {
  152. return nil, err
  153. }
  154. labels[k] = v
  155. }
  156. params := jsonutils.Marshal(labels).(*jsonutils.JSONDict)
  157. return params, nil
  158. }
  159. func parseLabel(str string) (string, string, error) {
  160. parts := strings.Split(str, "=")
  161. if len(parts) != 2 {
  162. return "", "", fmt.Errorf("Invalid label string: %s", str)
  163. }
  164. return parts[0], parts[1], nil
  165. }
  166. func (o K8sLabelOptions) Attach(data *jsonutils.JSONDict) error {
  167. if len(o.Label) == 0 {
  168. return nil
  169. }
  170. return attachData(o, data, "labels")
  171. }
  172. type K8sPVCTemplateOptions struct {
  173. PvcTemplate []string `help:"PVC volume desc, format is <pvc_name>:<size>:<mount_point>"`
  174. }
  175. func (o K8sPVCTemplateOptions) Parse() ([]*pvcTemplate, error) {
  176. if len(o.PvcTemplate) == 0 {
  177. return nil, nil
  178. }
  179. pvcs := []*pvcTemplate{}
  180. for _, pvc := range o.PvcTemplate {
  181. template, err := parsePVCTemplate(pvc)
  182. if err != nil {
  183. return nil, err
  184. }
  185. pvcs = append(pvcs, template)
  186. }
  187. return pvcs, nil
  188. }
  189. // PVCTemplateOptions Attach must invoke before podTemplate Attach
  190. func (o K8sPVCTemplateOptions) Attach(
  191. data *jsonutils.JSONDict,
  192. pvcs []*pvcTemplate,
  193. podTemplate *K8sPodTemplateOptions,
  194. ) {
  195. pvcsObj := jsonutils.NewArray()
  196. for _, p := range pvcs {
  197. pvcsObj.Add(p.pvc)
  198. podTemplate.Pvc = append(podTemplate.Pvc, p.volMount)
  199. }
  200. data.Add(pvcsObj, "volumeClaimTemplates")
  201. }
  202. type pvcTemplate struct {
  203. pvc *jsonutils.JSONDict
  204. volMount string
  205. }
  206. func parsePVCTemplate(pvcDesc string) (*pvcTemplate, error) {
  207. parts := strings.Split(pvcDesc, ":")
  208. if len(parts) != 3 {
  209. return nil, fmt.Errorf("Invalid PVC desc string: %s", pvcDesc)
  210. }
  211. pvcName := parts[0]
  212. pvcSize := parts[1]
  213. pvcMntPath := parts[2]
  214. spec := jsonutils.NewDict()
  215. spec.Add(jsonutils.NewString(pvcSize), "resources", "requests", "storage")
  216. obj := jsonutils.NewDict()
  217. obj.Add(spec, "spec")
  218. obj.Add(jsonutils.NewString(pvcName), "metadata", "name")
  219. return &pvcTemplate{
  220. pvc: obj,
  221. volMount: fmt.Sprintf("%s:%s", pvcName, pvcMntPath),
  222. }, nil
  223. }