apply.sh 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #!/usr/bin/env bash
  2. # Copyright 2018 The Kubernetes Authors.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. set -o errexit
  16. set -o nounset
  17. set -o pipefail
  18. # Runs tests related to kubectl apply.
  19. run_kubectl_apply_tests() {
  20. set -o nounset
  21. set -o errexit
  22. create_and_use_new_namespace
  23. kube::log::status "Testing kubectl apply"
  24. ## kubectl apply should create the resource that doesn't exist yet
  25. # Pre-Condition: no POD exists
  26. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  27. # Command: apply a pod "test-pod" (doesn't exist) should create this pod
  28. kubectl apply -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  29. # Post-Condition: pod "test-pod" is created
  30. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  31. # Post-Condition: pod "test-pod" has configuration annotation
  32. grep -q kubectl.kubernetes.io/last-applied-configuration <<< "$(kubectl get pods test-pod -o yaml "${kube_flags[@]:?}")"
  33. # Clean up
  34. kubectl delete pods test-pod "${kube_flags[@]:?}"
  35. ### set-last-applied
  36. # Pre-Condition: no POD exists
  37. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  38. # Command: create "test-pod" (doesn't exist) should create this pod without last-applied annotation
  39. kubectl create -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  40. # Post-Condition: pod "test-pod" is created
  41. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  42. # Pre-Condition: pod "test-pod" does not have configuration annotation
  43. ! grep -q kubectl.kubernetes.io/last-applied-configuration <<< "$(kubectl get pods test-pod -o yaml "${kube_flags[@]:?}")" || exit 1
  44. # Dry-run set-last-applied
  45. kubectl apply set-last-applied --dry-run=client -f hack/testdata/pod.yaml --create-annotation=true "${kube_flags[@]:?}"
  46. kubectl apply set-last-applied --dry-run=server -f hack/testdata/pod.yaml --create-annotation=true "${kube_flags[@]:?}"
  47. ! grep -q kubectl.kubernetes.io/last-applied-configuration <<< "$(kubectl get pods test-pod -o yaml "${kube_flags[@]:?}")" || exit 1
  48. # Command
  49. kubectl apply set-last-applied -f hack/testdata/pod.yaml --create-annotation=true "${kube_flags[@]:?}"
  50. # Post-Condition: pod "test-pod" has configuration annotation
  51. grep -q kubectl.kubernetes.io/last-applied-configuration <<< "$(kubectl get pods test-pod -o yaml "${kube_flags[@]:?}")"
  52. # Clean up
  53. kubectl delete pods test-pod "${kube_flags[@]:?}"
  54. ## kubectl apply should be able to clear defaulted fields.
  55. # Pre-Condition: no deployment exists
  56. kube::test::get_object_assert deployments "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  57. # Command: apply a deployment "test-deployment-retainkeys" (doesn't exist) should create this deployment
  58. kubectl apply -f hack/testdata/retainKeys/deployment/deployment-before.yaml "${kube_flags[@]:?}"
  59. # Post-Condition: deployment "test-deployment-retainkeys" created
  60. kube::test::get_object_assert deployments "{{range.items}}{{${id_field:?}}}{{end}}" 'test-deployment-retainkeys'
  61. # Post-Condition: deployment "test-deployment-retainkeys" has defaulted fields
  62. grep -q RollingUpdate <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  63. grep -q maxSurge <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  64. grep -q maxUnavailable <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  65. grep -q emptyDir <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  66. # Command: apply a deployment "test-deployment-retainkeys" should clear
  67. # defaulted fields and successfully update the deployment
  68. [[ "$(kubectl apply -f hack/testdata/retainKeys/deployment/deployment-after.yaml "${kube_flags[@]:?}")" ]]
  69. # Post-Condition: deployment "test-deployment-retainkeys" has updated fields
  70. grep -q Recreate <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  71. ! grep -q RollingUpdate <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")" || exit 1
  72. grep -q hostPath <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  73. ! grep -q emptyDir <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")" || exit 1
  74. # Clean up
  75. kubectl delete deployments test-deployment-retainkeys "${kube_flags[@]:?}"
  76. ## kubectl apply -f with label selector should only apply matching objects
  77. # Pre-Condition: no POD exists
  78. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  79. # apply
  80. kubectl apply -l unique-label=bingbang -f hack/testdata/filter "${kube_flags[@]:?}"
  81. # check right pod exists
  82. kube::test::get_object_assert 'pods selector-test-pod' "{{${labels_field:?}.name}}" 'selector-test-pod'
  83. # check wrong pod doesn't exist
  84. output_message=$(! kubectl get pods selector-test-pod-dont-apply 2>&1 "${kube_flags[@]:?}")
  85. kube::test::if_has_string "${output_message}" 'pods "selector-test-pod-dont-apply" not found'
  86. # cleanup
  87. kubectl delete pods selector-test-pod
  88. ## kubectl apply --dry-run=server
  89. # Pre-Condition: no POD exists
  90. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  91. # apply dry-run
  92. kubectl apply --server-dry-run -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  93. kubectl apply --dry-run=true -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  94. kubectl apply --dry-run=client -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  95. kubectl apply --dry-run=server -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  96. # No pod exists
  97. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  98. # apply non dry-run creates the pod
  99. kubectl apply -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  100. # apply changes
  101. kubectl apply --dry-run=server -f hack/testdata/pod-apply.yaml "${kube_flags[@]:?}"
  102. # Post-Condition: label still has initial value
  103. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  104. # clean-up
  105. kubectl delete -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  106. ## kubectl apply dry-run on CR
  107. # Create CRD
  108. kubectl "${kube_flags_with_token[@]:?}" create -f - << __EOF__
  109. {
  110. "kind": "CustomResourceDefinition",
  111. "apiVersion": "apiextensions.k8s.io/v1beta1",
  112. "metadata": {
  113. "name": "resources.mygroup.example.com"
  114. },
  115. "spec": {
  116. "group": "mygroup.example.com",
  117. "version": "v1alpha1",
  118. "scope": "Namespaced",
  119. "names": {
  120. "plural": "resources",
  121. "singular": "resource",
  122. "kind": "Kind",
  123. "listKind": "KindList"
  124. }
  125. }
  126. }
  127. __EOF__
  128. # Dry-run create the CR
  129. kubectl "${kube_flags[@]:?}" apply --dry-run=server -f hack/testdata/CRD/resource.yaml "${kube_flags[@]:?}"
  130. # Make sure that the CR doesn't exist
  131. ! kubectl "${kube_flags[@]:?}" get resource/myobj || exit 1
  132. # clean-up
  133. kubectl "${kube_flags[@]:?}" delete customresourcedefinition resources.mygroup.example.com
  134. ## kubectl apply --prune
  135. # Pre-Condition: no POD exists
  136. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  137. # apply a
  138. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  139. # check right pod exists
  140. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  141. # check wrong pod doesn't exist
  142. output_message=$(! kubectl get pods b 2>&1 "${kube_flags[@]:?}")
  143. kube::test::if_has_string "${output_message}" 'pods "b" not found'
  144. # apply b
  145. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/b.yaml "${kube_flags[@]:?}"
  146. # check right pod exists
  147. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  148. # check wrong pod doesn't exist
  149. output_message=$(! kubectl get pods a 2>&1 "${kube_flags[@]:?}")
  150. kube::test::if_has_string "${output_message}" 'pods "a" not found'
  151. kubectl delete pods a
  152. kubectl delete pods b
  153. # apply a
  154. kubectl apply --namespace nsb -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  155. # apply b with namespace
  156. kubectl apply --namespace nsb --prune -l prune-group=true -f hack/testdata/prune/b.yaml "${kube_flags[@]:?}"
  157. # check right pod exists
  158. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  159. # check wrong pod doesn't exist
  160. output_message=$(! kubectl get pods a 2>&1 "${kube_flags[@]:?}")
  161. kube::test::if_has_string "${output_message}" 'pods "a" not found'
  162. # cleanup
  163. kubectl delete pods b
  164. # same thing without prune for a sanity check
  165. # Pre-Condition: no POD exists
  166. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  167. # apply a
  168. kubectl apply -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  169. # check right pod exists
  170. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  171. # check wrong pod doesn't exist
  172. output_message=$(! kubectl get pods b 2>&1 "${kube_flags[@]:?}")
  173. kube::test::if_has_string "${output_message}" 'pods "b" not found'
  174. # apply b
  175. kubectl apply -l prune-group=true -f hack/testdata/prune/b.yaml "${kube_flags[@]:?}"
  176. # check both pods exist
  177. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  178. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  179. # check wrong pod doesn't exist
  180. # cleanup
  181. kubectl delete pod/a pod/b
  182. ## kubectl apply --prune requires a --all flag to select everything
  183. output_message=$(! kubectl apply --prune -f hack/testdata/prune 2>&1 "${kube_flags[@]:?}")
  184. kube::test::if_has_string "${output_message}" \
  185. 'all resources selected for prune without explicitly passing --all'
  186. # should apply everything
  187. kubectl apply --all --prune -f hack/testdata/prune
  188. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  189. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  190. kubectl delete pod/a pod/b
  191. ## kubectl apply --prune should fallback to delete for non reapable types
  192. kubectl apply --all --prune -f hack/testdata/prune-reap/a.yml 2>&1 "${kube_flags[@]:?}"
  193. kube::test::get_object_assert 'pvc a-pvc' "{{${id_field:?}}}" 'a-pvc'
  194. kubectl apply --all --prune -f hack/testdata/prune-reap/b.yml 2>&1 "${kube_flags[@]:?}"
  195. kube::test::get_object_assert 'pvc b-pvc' "{{${id_field:?}}}" 'b-pvc'
  196. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  197. kubectl delete pvc b-pvc 2>&1 "${kube_flags[@]:?}"
  198. ## kubectl apply --prune --prune-whitelist
  199. # Pre-Condition: no POD exists
  200. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  201. # apply pod a
  202. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  203. # check right pod exists
  204. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  205. # apply svc and don't prune pod a by overwriting whitelist
  206. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/svc.yaml --prune-whitelist core/v1/Service 2>&1 "${kube_flags[@]:?}"
  207. kube::test::get_object_assert 'service prune-svc' "{{${id_field:?}}}" 'prune-svc'
  208. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  209. # apply svc and prune pod a with default whitelist
  210. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/svc.yaml 2>&1 "${kube_flags[@]:?}"
  211. kube::test::get_object_assert 'service prune-svc' "{{${id_field:?}}}" 'prune-svc'
  212. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  213. # cleanup
  214. kubectl delete svc prune-svc 2>&1 "${kube_flags[@]:?}"
  215. ## kubectl apply -f some.yml --force
  216. # Pre-condition: no service exists
  217. kube::test::get_object_assert services "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  218. # apply service a
  219. kubectl apply -f hack/testdata/service-revision1.yaml "${kube_flags[@]:?}"
  220. # check right service exists
  221. kube::test::get_object_assert 'services a' "{{${id_field:?}}}" 'a'
  222. # change immutable field and apply service a
  223. output_message=$(! kubectl apply -f hack/testdata/service-revision2.yaml 2>&1 "${kube_flags[@]:?}")
  224. kube::test::if_has_string "${output_message}" 'field is immutable'
  225. # apply --force to recreate resources for immutable fields
  226. kubectl apply -f hack/testdata/service-revision2.yaml --force "${kube_flags[@]:?}"
  227. # check immutable field exists
  228. kube::test::get_object_assert 'services a' "{{.spec.clusterIP}}" '10.0.0.12'
  229. # cleanup
  230. kubectl delete -f hack/testdata/service-revision2.yaml "${kube_flags[@]:?}"
  231. ## kubectl apply -k somedir
  232. kubectl apply -k hack/testdata/kustomize
  233. kube::test::get_object_assert 'configmap test-the-map' "{{${id_field}}}" 'test-the-map'
  234. kube::test::get_object_assert 'deployment test-the-deployment' "{{${id_field}}}" 'test-the-deployment'
  235. kube::test::get_object_assert 'service test-the-service' "{{${id_field}}}" 'test-the-service'
  236. # cleanup
  237. kubectl delete -k hack/testdata/kustomize
  238. ## kubectl apply --kustomize somedir
  239. kubectl apply --kustomize hack/testdata/kustomize
  240. kube::test::get_object_assert 'configmap test-the-map' "{{${id_field}}}" 'test-the-map'
  241. kube::test::get_object_assert 'deployment test-the-deployment' "{{${id_field}}}" 'test-the-deployment'
  242. kube::test::get_object_assert 'service test-the-service' "{{${id_field}}}" 'test-the-service'
  243. # cleanup
  244. kubectl delete --kustomize hack/testdata/kustomize
  245. set +o nounset
  246. set +o errexit
  247. }
  248. # Runs tests related to kubectl apply (server-side)
  249. run_kubectl_apply_tests() {
  250. set -o nounset
  251. set -o errexit
  252. create_and_use_new_namespace
  253. kube::log::status "Testing kubectl apply --server-side"
  254. ## kubectl apply should create the resource that doesn't exist yet
  255. # Pre-Condition: no POD exists
  256. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  257. # Command: apply a pod "test-pod" (doesn't exist) should create this pod
  258. kubectl apply --server-side -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  259. # Post-Condition: pod "test-pod" is created
  260. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  261. # Clean up
  262. kubectl delete pods test-pod "${kube_flags[@]:?}"
  263. ## kubectl apply --dry-run=server
  264. # Pre-Condition: no POD exists
  265. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  266. # apply dry-run
  267. kubectl apply --server-side --dry-run=server -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  268. # No pod exists
  269. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  270. # apply non dry-run creates the pod
  271. kubectl apply --server-side -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  272. # apply changes
  273. kubectl apply --server-side --dry-run=server -f hack/testdata/pod-apply.yaml "${kube_flags[@]:?}"
  274. # Post-Condition: label still has initial value
  275. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  276. # clean-up
  277. kubectl delete -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  278. ## kubectl apply dry-run on CR
  279. # Create CRD
  280. kubectl "${kube_flags_with_token[@]}" create -f - << __EOF__
  281. {
  282. "kind": "CustomResourceDefinition",
  283. "apiVersion": "apiextensions.k8s.io/v1beta1",
  284. "metadata": {
  285. "name": "resources.mygroup.example.com"
  286. },
  287. "spec": {
  288. "group": "mygroup.example.com",
  289. "version": "v1alpha1",
  290. "scope": "Namespaced",
  291. "names": {
  292. "plural": "resources",
  293. "singular": "resource",
  294. "kind": "Kind",
  295. "listKind": "KindList"
  296. }
  297. }
  298. }
  299. __EOF__
  300. # Dry-run create the CR
  301. kubectl "${kube_flags[@]:?}" apply --server-side --dry-run=server -f hack/testdata/CRD/resource.yaml "${kube_flags[@]:?}"
  302. # Make sure that the CR doesn't exist
  303. ! kubectl "${kube_flags[@]:?}" get resource/myobj || exit 1
  304. # clean-up
  305. kubectl "${kube_flags[@]:?}" delete customresourcedefinition resources.mygroup.example.com
  306. set +o nounset
  307. set +o errexit
  308. }