run.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package versioned
  14. import (
  15. "fmt"
  16. "strconv"
  17. "strings"
  18. appsv1 "k8s.io/api/apps/v1"
  19. appsv1beta1 "k8s.io/api/apps/v1beta1"
  20. batchv1 "k8s.io/api/batch/v1"
  21. batchv1beta1 "k8s.io/api/batch/v1beta1"
  22. batchv2alpha1 "k8s.io/api/batch/v2alpha1"
  23. "k8s.io/api/core/v1"
  24. extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
  25. "k8s.io/apimachinery/pkg/api/resource"
  26. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  27. "k8s.io/apimachinery/pkg/runtime"
  28. "k8s.io/apimachinery/pkg/util/validation"
  29. "k8s.io/kubernetes/pkg/kubectl/generate"
  30. )
  31. type DeploymentV1Beta1 struct{}
  32. func (DeploymentV1Beta1) ParamNames() []generate.GeneratorParam {
  33. return []generate.GeneratorParam{
  34. {Name: "labels", Required: false},
  35. {Name: "default-name", Required: false},
  36. {Name: "name", Required: true},
  37. {Name: "replicas", Required: true},
  38. {Name: "image", Required: true},
  39. {Name: "image-pull-policy", Required: false},
  40. {Name: "port", Required: false},
  41. {Name: "hostport", Required: false},
  42. {Name: "stdin", Required: false},
  43. {Name: "tty", Required: false},
  44. {Name: "command", Required: false},
  45. {Name: "args", Required: false},
  46. {Name: "env", Required: false},
  47. {Name: "requests", Required: false},
  48. {Name: "limits", Required: false},
  49. {Name: "serviceaccount", Required: false},
  50. }
  51. }
  52. func (DeploymentV1Beta1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
  53. args, err := getArgs(genericParams)
  54. if err != nil {
  55. return nil, err
  56. }
  57. envs, err := getEnvs(genericParams)
  58. if err != nil {
  59. return nil, err
  60. }
  61. params, err := getParams(genericParams)
  62. if err != nil {
  63. return nil, err
  64. }
  65. name, err := getName(params)
  66. if err != nil {
  67. return nil, err
  68. }
  69. labels, err := getLabels(params, name)
  70. if err != nil {
  71. return nil, err
  72. }
  73. count, err := strconv.Atoi(params["replicas"])
  74. if err != nil {
  75. return nil, err
  76. }
  77. podSpec, err := makePodSpec(params, name)
  78. if err != nil {
  79. return nil, err
  80. }
  81. imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
  82. if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
  83. return nil, err
  84. }
  85. if err := updatePodPorts(params, podSpec); err != nil {
  86. return nil, err
  87. }
  88. count32 := int32(count)
  89. deployment := extensionsv1beta1.Deployment{
  90. ObjectMeta: metav1.ObjectMeta{
  91. Name: name,
  92. Labels: labels,
  93. },
  94. Spec: extensionsv1beta1.DeploymentSpec{
  95. Replicas: &count32,
  96. Selector: &metav1.LabelSelector{MatchLabels: labels},
  97. Template: v1.PodTemplateSpec{
  98. ObjectMeta: metav1.ObjectMeta{
  99. Labels: labels,
  100. },
  101. Spec: *podSpec,
  102. },
  103. },
  104. }
  105. return &deployment, nil
  106. }
  107. type DeploymentAppsV1Beta1 struct{}
  108. func (DeploymentAppsV1Beta1) ParamNames() []generate.GeneratorParam {
  109. return []generate.GeneratorParam{
  110. {Name: "labels", Required: false},
  111. {Name: "default-name", Required: false},
  112. {Name: "name", Required: true},
  113. {Name: "replicas", Required: true},
  114. {Name: "image", Required: true},
  115. {Name: "image-pull-policy", Required: false},
  116. {Name: "port", Required: false},
  117. {Name: "hostport", Required: false},
  118. {Name: "stdin", Required: false},
  119. {Name: "tty", Required: false},
  120. {Name: "command", Required: false},
  121. {Name: "args", Required: false},
  122. {Name: "env", Required: false},
  123. {Name: "requests", Required: false},
  124. {Name: "limits", Required: false},
  125. {Name: "serviceaccount", Required: false},
  126. }
  127. }
  128. func (DeploymentAppsV1Beta1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
  129. args, err := getArgs(genericParams)
  130. if err != nil {
  131. return nil, err
  132. }
  133. envs, err := getEnvs(genericParams)
  134. if err != nil {
  135. return nil, err
  136. }
  137. params, err := getParams(genericParams)
  138. if err != nil {
  139. return nil, err
  140. }
  141. name, err := getName(params)
  142. if err != nil {
  143. return nil, err
  144. }
  145. labels, err := getLabels(params, name)
  146. if err != nil {
  147. return nil, err
  148. }
  149. count, err := strconv.Atoi(params["replicas"])
  150. if err != nil {
  151. return nil, err
  152. }
  153. podSpec, err := makePodSpec(params, name)
  154. if err != nil {
  155. return nil, err
  156. }
  157. imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
  158. if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
  159. return nil, err
  160. }
  161. if err := updatePodPorts(params, podSpec); err != nil {
  162. return nil, err
  163. }
  164. count32 := int32(count)
  165. deployment := appsv1beta1.Deployment{
  166. ObjectMeta: metav1.ObjectMeta{
  167. Name: name,
  168. Labels: labels,
  169. },
  170. Spec: appsv1beta1.DeploymentSpec{
  171. Replicas: &count32,
  172. Selector: &metav1.LabelSelector{MatchLabels: labels},
  173. Template: v1.PodTemplateSpec{
  174. ObjectMeta: metav1.ObjectMeta{
  175. Labels: labels,
  176. },
  177. Spec: *podSpec,
  178. },
  179. },
  180. }
  181. return &deployment, nil
  182. }
  183. type DeploymentAppsV1 struct{}
  184. func (DeploymentAppsV1) ParamNames() []generate.GeneratorParam {
  185. return []generate.GeneratorParam{
  186. {Name: "labels", Required: false},
  187. {Name: "default-name", Required: false},
  188. {Name: "name", Required: true},
  189. {Name: "replicas", Required: true},
  190. {Name: "image", Required: true},
  191. {Name: "image-pull-policy", Required: false},
  192. {Name: "port", Required: false},
  193. {Name: "hostport", Required: false},
  194. {Name: "stdin", Required: false},
  195. {Name: "tty", Required: false},
  196. {Name: "command", Required: false},
  197. {Name: "args", Required: false},
  198. {Name: "env", Required: false},
  199. {Name: "requests", Required: false},
  200. {Name: "limits", Required: false},
  201. {Name: "serviceaccount", Required: false},
  202. }
  203. }
  204. func (DeploymentAppsV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
  205. args, err := getArgs(genericParams)
  206. if err != nil {
  207. return nil, err
  208. }
  209. envs, err := getEnvs(genericParams)
  210. if err != nil {
  211. return nil, err
  212. }
  213. params, err := getParams(genericParams)
  214. if err != nil {
  215. return nil, err
  216. }
  217. name, err := getName(params)
  218. if err != nil {
  219. return nil, err
  220. }
  221. labels, err := getLabels(params, name)
  222. if err != nil {
  223. return nil, err
  224. }
  225. count, err := strconv.Atoi(params["replicas"])
  226. if err != nil {
  227. return nil, err
  228. }
  229. podSpec, err := makePodSpec(params, name)
  230. if err != nil {
  231. return nil, err
  232. }
  233. imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
  234. if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
  235. return nil, err
  236. }
  237. if err := updatePodPorts(params, podSpec); err != nil {
  238. return nil, err
  239. }
  240. count32 := int32(count)
  241. deployment := appsv1.Deployment{
  242. ObjectMeta: metav1.ObjectMeta{
  243. Name: name,
  244. Labels: labels,
  245. },
  246. Spec: appsv1.DeploymentSpec{
  247. Replicas: &count32,
  248. Selector: &metav1.LabelSelector{MatchLabels: labels},
  249. Template: v1.PodTemplateSpec{
  250. ObjectMeta: metav1.ObjectMeta{
  251. Labels: labels,
  252. },
  253. Spec: *podSpec,
  254. },
  255. },
  256. }
  257. return &deployment, nil
  258. }
  259. // getLabels returns map of labels.
  260. func getLabels(params map[string]string, name string) (map[string]string, error) {
  261. labelString, found := params["labels"]
  262. var labels map[string]string
  263. var err error
  264. if found && len(labelString) > 0 {
  265. labels, err = generate.ParseLabels(labelString)
  266. if err != nil {
  267. return nil, err
  268. }
  269. } else {
  270. labels = map[string]string{
  271. "run": name,
  272. }
  273. }
  274. return labels, nil
  275. }
  276. // getName returns the name of newly created resource.
  277. func getName(params map[string]string) (string, error) {
  278. name, found := params["name"]
  279. if !found || len(name) == 0 {
  280. name, found = params["default-name"]
  281. if !found || len(name) == 0 {
  282. return "", fmt.Errorf("'name' is a required parameter")
  283. }
  284. }
  285. return name, nil
  286. }
  287. // getParams returns map of generic parameters.
  288. func getParams(genericParams map[string]interface{}) (map[string]string, error) {
  289. params := map[string]string{}
  290. for key, value := range genericParams {
  291. strVal, isString := value.(string)
  292. if !isString {
  293. return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
  294. }
  295. params[key] = strVal
  296. }
  297. return params, nil
  298. }
  299. // getArgs returns arguments for the container command.
  300. func getArgs(genericParams map[string]interface{}) ([]string, error) {
  301. args := []string{}
  302. val, found := genericParams["args"]
  303. if found {
  304. var isArray bool
  305. args, isArray = val.([]string)
  306. if !isArray {
  307. return nil, fmt.Errorf("expected []string, found: %v", val)
  308. }
  309. delete(genericParams, "args")
  310. }
  311. return args, nil
  312. }
  313. // getEnvs returns environment variables.
  314. func getEnvs(genericParams map[string]interface{}) ([]v1.EnvVar, error) {
  315. var envs []v1.EnvVar
  316. envStrings, found := genericParams["env"]
  317. if found {
  318. if envStringArray, isArray := envStrings.([]string); isArray {
  319. var err error
  320. envs, err = parseEnvs(envStringArray)
  321. if err != nil {
  322. return nil, err
  323. }
  324. delete(genericParams, "env")
  325. } else {
  326. return nil, fmt.Errorf("expected []string, found: %v", envStrings)
  327. }
  328. }
  329. return envs, nil
  330. }
  331. type JobV1 struct{}
  332. func (JobV1) ParamNames() []generate.GeneratorParam {
  333. return []generate.GeneratorParam{
  334. {Name: "labels", Required: false},
  335. {Name: "default-name", Required: false},
  336. {Name: "name", Required: true},
  337. {Name: "image", Required: true},
  338. {Name: "image-pull-policy", Required: false},
  339. {Name: "port", Required: false},
  340. {Name: "hostport", Required: false},
  341. {Name: "stdin", Required: false},
  342. {Name: "leave-stdin-open", Required: false},
  343. {Name: "tty", Required: false},
  344. {Name: "command", Required: false},
  345. {Name: "args", Required: false},
  346. {Name: "env", Required: false},
  347. {Name: "requests", Required: false},
  348. {Name: "limits", Required: false},
  349. {Name: "restart", Required: false},
  350. {Name: "serviceaccount", Required: false},
  351. }
  352. }
  353. func (JobV1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
  354. args, err := getArgs(genericParams)
  355. if err != nil {
  356. return nil, err
  357. }
  358. envs, err := getEnvs(genericParams)
  359. if err != nil {
  360. return nil, err
  361. }
  362. params, err := getParams(genericParams)
  363. if err != nil {
  364. return nil, err
  365. }
  366. name, err := getName(params)
  367. if err != nil {
  368. return nil, err
  369. }
  370. labels, err := getLabels(params, name)
  371. if err != nil {
  372. return nil, err
  373. }
  374. podSpec, err := makePodSpec(params, name)
  375. if err != nil {
  376. return nil, err
  377. }
  378. imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
  379. if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
  380. return nil, err
  381. }
  382. leaveStdinOpen, err := generate.GetBool(params, "leave-stdin-open", false)
  383. if err != nil {
  384. return nil, err
  385. }
  386. podSpec.Containers[0].StdinOnce = !leaveStdinOpen && podSpec.Containers[0].Stdin
  387. if err := updatePodPorts(params, podSpec); err != nil {
  388. return nil, err
  389. }
  390. restartPolicy := v1.RestartPolicy(params["restart"])
  391. if len(restartPolicy) == 0 {
  392. restartPolicy = v1.RestartPolicyNever
  393. }
  394. podSpec.RestartPolicy = restartPolicy
  395. job := batchv1.Job{
  396. ObjectMeta: metav1.ObjectMeta{
  397. Name: name,
  398. Labels: labels,
  399. },
  400. Spec: batchv1.JobSpec{
  401. Template: v1.PodTemplateSpec{
  402. ObjectMeta: metav1.ObjectMeta{
  403. Labels: labels,
  404. },
  405. Spec: *podSpec,
  406. },
  407. },
  408. }
  409. return &job, nil
  410. }
  411. type CronJobV2Alpha1 struct{}
  412. func (CronJobV2Alpha1) ParamNames() []generate.GeneratorParam {
  413. return []generate.GeneratorParam{
  414. {Name: "labels", Required: false},
  415. {Name: "default-name", Required: false},
  416. {Name: "name", Required: true},
  417. {Name: "image", Required: true},
  418. {Name: "image-pull-policy", Required: false},
  419. {Name: "port", Required: false},
  420. {Name: "hostport", Required: false},
  421. {Name: "stdin", Required: false},
  422. {Name: "leave-stdin-open", Required: false},
  423. {Name: "tty", Required: false},
  424. {Name: "command", Required: false},
  425. {Name: "args", Required: false},
  426. {Name: "env", Required: false},
  427. {Name: "requests", Required: false},
  428. {Name: "limits", Required: false},
  429. {Name: "restart", Required: false},
  430. {Name: "schedule", Required: true},
  431. {Name: "serviceaccount", Required: false},
  432. }
  433. }
  434. func (CronJobV2Alpha1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
  435. args, err := getArgs(genericParams)
  436. if err != nil {
  437. return nil, err
  438. }
  439. envs, err := getEnvs(genericParams)
  440. if err != nil {
  441. return nil, err
  442. }
  443. params, err := getParams(genericParams)
  444. if err != nil {
  445. return nil, err
  446. }
  447. name, err := getName(params)
  448. if err != nil {
  449. return nil, err
  450. }
  451. labels, err := getLabels(params, name)
  452. if err != nil {
  453. return nil, err
  454. }
  455. podSpec, err := makePodSpec(params, name)
  456. if err != nil {
  457. return nil, err
  458. }
  459. imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
  460. if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
  461. return nil, err
  462. }
  463. leaveStdinOpen, err := generate.GetBool(params, "leave-stdin-open", false)
  464. if err != nil {
  465. return nil, err
  466. }
  467. podSpec.Containers[0].StdinOnce = !leaveStdinOpen && podSpec.Containers[0].Stdin
  468. if err := updatePodPorts(params, podSpec); err != nil {
  469. return nil, err
  470. }
  471. restartPolicy := v1.RestartPolicy(params["restart"])
  472. if len(restartPolicy) == 0 {
  473. restartPolicy = v1.RestartPolicyNever
  474. }
  475. podSpec.RestartPolicy = restartPolicy
  476. cronJob := batchv2alpha1.CronJob{
  477. ObjectMeta: metav1.ObjectMeta{
  478. Name: name,
  479. Labels: labels,
  480. },
  481. Spec: batchv2alpha1.CronJobSpec{
  482. Schedule: params["schedule"],
  483. ConcurrencyPolicy: batchv2alpha1.AllowConcurrent,
  484. JobTemplate: batchv2alpha1.JobTemplateSpec{
  485. Spec: batchv1.JobSpec{
  486. Template: v1.PodTemplateSpec{
  487. ObjectMeta: metav1.ObjectMeta{
  488. Labels: labels,
  489. },
  490. Spec: *podSpec,
  491. },
  492. },
  493. },
  494. },
  495. }
  496. return &cronJob, nil
  497. }
  498. type CronJobV1Beta1 struct{}
  499. func (CronJobV1Beta1) ParamNames() []generate.GeneratorParam {
  500. return []generate.GeneratorParam{
  501. {Name: "labels", Required: false},
  502. {Name: "default-name", Required: false},
  503. {Name: "name", Required: true},
  504. {Name: "image", Required: true},
  505. {Name: "image-pull-policy", Required: false},
  506. {Name: "port", Required: false},
  507. {Name: "hostport", Required: false},
  508. {Name: "stdin", Required: false},
  509. {Name: "leave-stdin-open", Required: false},
  510. {Name: "tty", Required: false},
  511. {Name: "command", Required: false},
  512. {Name: "args", Required: false},
  513. {Name: "env", Required: false},
  514. {Name: "requests", Required: false},
  515. {Name: "limits", Required: false},
  516. {Name: "restart", Required: false},
  517. {Name: "schedule", Required: true},
  518. {Name: "serviceaccount", Required: false},
  519. }
  520. }
  521. func (CronJobV1Beta1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
  522. args, err := getArgs(genericParams)
  523. if err != nil {
  524. return nil, err
  525. }
  526. envs, err := getEnvs(genericParams)
  527. if err != nil {
  528. return nil, err
  529. }
  530. params, err := getParams(genericParams)
  531. if err != nil {
  532. return nil, err
  533. }
  534. name, err := getName(params)
  535. if err != nil {
  536. return nil, err
  537. }
  538. labels, err := getLabels(params, name)
  539. if err != nil {
  540. return nil, err
  541. }
  542. podSpec, err := makePodSpec(params, name)
  543. if err != nil {
  544. return nil, err
  545. }
  546. imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
  547. if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
  548. return nil, err
  549. }
  550. leaveStdinOpen, err := generate.GetBool(params, "leave-stdin-open", false)
  551. if err != nil {
  552. return nil, err
  553. }
  554. podSpec.Containers[0].StdinOnce = !leaveStdinOpen && podSpec.Containers[0].Stdin
  555. if err := updatePodPorts(params, podSpec); err != nil {
  556. return nil, err
  557. }
  558. restartPolicy := v1.RestartPolicy(params["restart"])
  559. if len(restartPolicy) == 0 {
  560. restartPolicy = v1.RestartPolicyNever
  561. }
  562. podSpec.RestartPolicy = restartPolicy
  563. cronJob := batchv1beta1.CronJob{
  564. ObjectMeta: metav1.ObjectMeta{
  565. Name: name,
  566. Labels: labels,
  567. },
  568. Spec: batchv1beta1.CronJobSpec{
  569. Schedule: params["schedule"],
  570. ConcurrencyPolicy: batchv1beta1.AllowConcurrent,
  571. JobTemplate: batchv1beta1.JobTemplateSpec{
  572. Spec: batchv1.JobSpec{
  573. Template: v1.PodTemplateSpec{
  574. ObjectMeta: metav1.ObjectMeta{
  575. Labels: labels,
  576. },
  577. Spec: *podSpec,
  578. },
  579. },
  580. },
  581. },
  582. }
  583. return &cronJob, nil
  584. }
  585. type BasicReplicationController struct{}
  586. func (BasicReplicationController) ParamNames() []generate.GeneratorParam {
  587. return []generate.GeneratorParam{
  588. {Name: "labels", Required: false},
  589. {Name: "default-name", Required: false},
  590. {Name: "name", Required: true},
  591. {Name: "replicas", Required: true},
  592. {Name: "image", Required: true},
  593. {Name: "image-pull-policy", Required: false},
  594. {Name: "port", Required: false},
  595. {Name: "hostport", Required: false},
  596. {Name: "stdin", Required: false},
  597. {Name: "tty", Required: false},
  598. {Name: "command", Required: false},
  599. {Name: "args", Required: false},
  600. {Name: "env", Required: false},
  601. {Name: "requests", Required: false},
  602. {Name: "limits", Required: false},
  603. {Name: "serviceaccount", Required: false},
  604. }
  605. }
  606. // populateResourceListV1 takes strings of form <resourceName1>=<value1>,<resourceName1>=<value2>
  607. // and returns ResourceList.
  608. func populateResourceListV1(spec string) (v1.ResourceList, error) {
  609. // empty input gets a nil response to preserve generator test expected behaviors
  610. if spec == "" {
  611. return nil, nil
  612. }
  613. result := v1.ResourceList{}
  614. resourceStatements := strings.Split(spec, ",")
  615. for _, resourceStatement := range resourceStatements {
  616. parts := strings.Split(resourceStatement, "=")
  617. if len(parts) != 2 {
  618. return nil, fmt.Errorf("Invalid argument syntax %v, expected <resource>=<value>", resourceStatement)
  619. }
  620. resourceName := v1.ResourceName(parts[0])
  621. resourceQuantity, err := resource.ParseQuantity(parts[1])
  622. if err != nil {
  623. return nil, err
  624. }
  625. result[resourceName] = resourceQuantity
  626. }
  627. return result, nil
  628. }
  629. // HandleResourceRequirementsV1 parses the limits and requests parameters if specified
  630. // and returns ResourceRequirements.
  631. func HandleResourceRequirementsV1(params map[string]string) (v1.ResourceRequirements, error) {
  632. result := v1.ResourceRequirements{}
  633. limits, err := populateResourceListV1(params["limits"])
  634. if err != nil {
  635. return result, err
  636. }
  637. result.Limits = limits
  638. requests, err := populateResourceListV1(params["requests"])
  639. if err != nil {
  640. return result, err
  641. }
  642. result.Requests = requests
  643. return result, nil
  644. }
  645. // makePodSpec returns PodSpec filled with passed parameters.
  646. func makePodSpec(params map[string]string, name string) (*v1.PodSpec, error) {
  647. stdin, err := generate.GetBool(params, "stdin", false)
  648. if err != nil {
  649. return nil, err
  650. }
  651. tty, err := generate.GetBool(params, "tty", false)
  652. if err != nil {
  653. return nil, err
  654. }
  655. resourceRequirements, err := HandleResourceRequirementsV1(params)
  656. if err != nil {
  657. return nil, err
  658. }
  659. spec := v1.PodSpec{
  660. ServiceAccountName: params["serviceaccount"],
  661. Containers: []v1.Container{
  662. {
  663. Name: name,
  664. Image: params["image"],
  665. Stdin: stdin,
  666. TTY: tty,
  667. Resources: resourceRequirements,
  668. },
  669. },
  670. }
  671. return &spec, nil
  672. }
  673. func (BasicReplicationController) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
  674. args, err := getArgs(genericParams)
  675. if err != nil {
  676. return nil, err
  677. }
  678. envs, err := getEnvs(genericParams)
  679. if err != nil {
  680. return nil, err
  681. }
  682. params, err := getParams(genericParams)
  683. if err != nil {
  684. return nil, err
  685. }
  686. name, err := getName(params)
  687. if err != nil {
  688. return nil, err
  689. }
  690. labels, err := getLabels(params, name)
  691. if err != nil {
  692. return nil, err
  693. }
  694. count, err := strconv.Atoi(params["replicas"])
  695. if err != nil {
  696. return nil, err
  697. }
  698. podSpec, err := makePodSpec(params, name)
  699. if err != nil {
  700. return nil, err
  701. }
  702. imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
  703. if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
  704. return nil, err
  705. }
  706. if err := updatePodPorts(params, podSpec); err != nil {
  707. return nil, err
  708. }
  709. count32 := int32(count)
  710. controller := v1.ReplicationController{
  711. ObjectMeta: metav1.ObjectMeta{
  712. Name: name,
  713. Labels: labels,
  714. },
  715. Spec: v1.ReplicationControllerSpec{
  716. Replicas: &count32,
  717. Selector: labels,
  718. Template: &v1.PodTemplateSpec{
  719. ObjectMeta: metav1.ObjectMeta{
  720. Labels: labels,
  721. },
  722. Spec: *podSpec,
  723. },
  724. },
  725. }
  726. return &controller, nil
  727. }
  728. // updatePodContainers updates PodSpec.Containers with passed parameters.
  729. func updatePodContainers(params map[string]string, args []string, envs []v1.EnvVar, imagePullPolicy v1.PullPolicy, podSpec *v1.PodSpec) error {
  730. if len(args) > 0 {
  731. command, err := generate.GetBool(params, "command", false)
  732. if err != nil {
  733. return err
  734. }
  735. if command {
  736. podSpec.Containers[0].Command = args
  737. } else {
  738. podSpec.Containers[0].Args = args
  739. }
  740. }
  741. if len(envs) > 0 {
  742. podSpec.Containers[0].Env = envs
  743. }
  744. if len(imagePullPolicy) > 0 {
  745. // imagePullPolicy should be valid here since we have verified it before.
  746. podSpec.Containers[0].ImagePullPolicy = imagePullPolicy
  747. }
  748. return nil
  749. }
  750. // updatePodContainers updates PodSpec.Containers.Ports with passed parameters.
  751. func updatePodPorts(params map[string]string, podSpec *v1.PodSpec) (err error) {
  752. port := -1
  753. hostPort := -1
  754. if len(params["port"]) > 0 {
  755. port, err = strconv.Atoi(params["port"])
  756. if err != nil {
  757. return err
  758. }
  759. }
  760. if len(params["hostport"]) > 0 {
  761. hostPort, err = strconv.Atoi(params["hostport"])
  762. if err != nil {
  763. return err
  764. }
  765. if hostPort > 0 && port < 0 {
  766. return fmt.Errorf("--hostport requires --port to be specified")
  767. }
  768. }
  769. // Don't include the port if it was not specified.
  770. if len(params["port"]) > 0 {
  771. podSpec.Containers[0].Ports = []v1.ContainerPort{
  772. {
  773. ContainerPort: int32(port),
  774. },
  775. }
  776. if hostPort > 0 {
  777. podSpec.Containers[0].Ports[0].HostPort = int32(hostPort)
  778. }
  779. }
  780. return nil
  781. }
  782. type BasicPod struct{}
  783. func (BasicPod) ParamNames() []generate.GeneratorParam {
  784. return []generate.GeneratorParam{
  785. {Name: "labels", Required: false},
  786. {Name: "default-name", Required: false},
  787. {Name: "name", Required: true},
  788. {Name: "image", Required: true},
  789. {Name: "image-pull-policy", Required: false},
  790. {Name: "port", Required: false},
  791. {Name: "hostport", Required: false},
  792. {Name: "stdin", Required: false},
  793. {Name: "leave-stdin-open", Required: false},
  794. {Name: "tty", Required: false},
  795. {Name: "restart", Required: false},
  796. {Name: "command", Required: false},
  797. {Name: "args", Required: false},
  798. {Name: "env", Required: false},
  799. {Name: "requests", Required: false},
  800. {Name: "limits", Required: false},
  801. {Name: "serviceaccount", Required: false},
  802. }
  803. }
  804. func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
  805. args, err := getArgs(genericParams)
  806. if err != nil {
  807. return nil, err
  808. }
  809. envs, err := getEnvs(genericParams)
  810. if err != nil {
  811. return nil, err
  812. }
  813. params, err := getParams(genericParams)
  814. if err != nil {
  815. return nil, err
  816. }
  817. name, err := getName(params)
  818. if err != nil {
  819. return nil, err
  820. }
  821. labels, err := getLabels(params, name)
  822. if err != nil {
  823. return nil, err
  824. }
  825. stdin, err := generate.GetBool(params, "stdin", false)
  826. if err != nil {
  827. return nil, err
  828. }
  829. leaveStdinOpen, err := generate.GetBool(params, "leave-stdin-open", false)
  830. if err != nil {
  831. return nil, err
  832. }
  833. tty, err := generate.GetBool(params, "tty", false)
  834. if err != nil {
  835. return nil, err
  836. }
  837. resourceRequirements, err := HandleResourceRequirementsV1(params)
  838. if err != nil {
  839. return nil, err
  840. }
  841. restartPolicy := v1.RestartPolicy(params["restart"])
  842. if len(restartPolicy) == 0 {
  843. restartPolicy = v1.RestartPolicyAlways
  844. }
  845. pod := v1.Pod{
  846. ObjectMeta: metav1.ObjectMeta{
  847. Name: name,
  848. Labels: labels,
  849. },
  850. Spec: v1.PodSpec{
  851. ServiceAccountName: params["serviceaccount"],
  852. Containers: []v1.Container{
  853. {
  854. Name: name,
  855. Image: params["image"],
  856. Stdin: stdin,
  857. StdinOnce: !leaveStdinOpen && stdin,
  858. TTY: tty,
  859. Resources: resourceRequirements,
  860. },
  861. },
  862. DNSPolicy: v1.DNSClusterFirst,
  863. RestartPolicy: restartPolicy,
  864. },
  865. }
  866. imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
  867. if err = updatePodContainers(params, args, envs, imagePullPolicy, &pod.Spec); err != nil {
  868. return nil, err
  869. }
  870. if err := updatePodPorts(params, &pod.Spec); err != nil {
  871. return nil, err
  872. }
  873. return &pod, nil
  874. }
  875. // parseEnvs converts string into EnvVar objects.
  876. func parseEnvs(envArray []string) ([]v1.EnvVar, error) {
  877. envs := make([]v1.EnvVar, 0, len(envArray))
  878. for _, env := range envArray {
  879. pos := strings.Index(env, "=")
  880. if pos == -1 {
  881. return nil, fmt.Errorf("invalid env: %v", env)
  882. }
  883. name := env[:pos]
  884. value := env[pos+1:]
  885. if len(name) == 0 {
  886. return nil, fmt.Errorf("invalid env: %v", env)
  887. }
  888. if len(validation.IsEnvVarName(name)) != 0 {
  889. return nil, fmt.Errorf("invalid env: %v", env)
  890. }
  891. envVar := v1.EnvVar{Name: name, Value: value}
  892. envs = append(envs, envVar)
  893. }
  894. return envs, nil
  895. }