run.go 22 KB

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