apply.sh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. ## kubectl apply should be able to clear defaulted fields.
  36. # Pre-Condition: no deployment exists
  37. kube::test::get_object_assert deployments "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  38. # Command: apply a deployment "test-deployment-retainkeys" (doesn't exist) should create this deployment
  39. kubectl apply -f hack/testdata/retainKeys/deployment/deployment-before.yaml "${kube_flags[@]:?}"
  40. # Post-Condition: deployment "test-deployment-retainkeys" created
  41. kube::test::get_object_assert deployments "{{range.items}}{{${id_field:?}}}{{end}}" 'test-deployment-retainkeys'
  42. # Post-Condition: deployment "test-deployment-retainkeys" has defaulted fields
  43. grep -q RollingUpdate <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  44. grep -q maxSurge <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  45. grep -q maxUnavailable <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  46. grep -q emptyDir <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  47. # Command: apply a deployment "test-deployment-retainkeys" should clear
  48. # defaulted fields and successfully update the deployment
  49. [[ "$(kubectl apply -f hack/testdata/retainKeys/deployment/deployment-after.yaml "${kube_flags[@]:?}")" ]]
  50. # Post-Condition: deployment "test-deployment-retainkeys" has updated fields
  51. grep -q Recreate <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  52. ! grep -q RollingUpdate <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  53. grep -q hostPath <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  54. ! grep -q emptyDir <<< "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]:?}")"
  55. # Clean up
  56. kubectl delete deployments test-deployment-retainkeys "${kube_flags[@]:?}"
  57. ## kubectl apply -f with label selector should only apply matching objects
  58. # Pre-Condition: no POD exists
  59. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  60. # apply
  61. kubectl apply -l unique-label=bingbang -f hack/testdata/filter "${kube_flags[@]:?}"
  62. # check right pod exists
  63. kube::test::get_object_assert 'pods selector-test-pod' "{{${labels_field:?}.name}}" 'selector-test-pod'
  64. # check wrong pod doesn't exist
  65. output_message=$(! kubectl get pods selector-test-pod-dont-apply 2>&1 "${kube_flags[@]:?}")
  66. kube::test::if_has_string "${output_message}" 'pods "selector-test-pod-dont-apply" not found'
  67. # cleanup
  68. kubectl delete pods selector-test-pod
  69. ## kubectl apply --server-dry-run
  70. # Pre-Condition: no POD exists
  71. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  72. # apply dry-run
  73. kubectl apply --server-dry-run -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  74. # No pod exists
  75. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  76. # apply non dry-run creates the pod
  77. kubectl apply -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  78. # apply changes
  79. kubectl apply --server-dry-run -f hack/testdata/pod-apply.yaml "${kube_flags[@]:?}"
  80. # Post-Condition: label still has initial value
  81. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  82. # clean-up
  83. kubectl delete -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  84. ## kubectl apply dry-run on CR
  85. # Create CRD
  86. kubectl "${kube_flags_with_token[@]:?}" create -f - << __EOF__
  87. {
  88. "kind": "CustomResourceDefinition",
  89. "apiVersion": "apiextensions.k8s.io/v1beta1",
  90. "metadata": {
  91. "name": "resources.mygroup.example.com"
  92. },
  93. "spec": {
  94. "group": "mygroup.example.com",
  95. "version": "v1alpha1",
  96. "scope": "Namespaced",
  97. "names": {
  98. "plural": "resources",
  99. "singular": "resource",
  100. "kind": "Kind",
  101. "listKind": "KindList"
  102. }
  103. }
  104. }
  105. __EOF__
  106. # Dry-run create the CR
  107. kubectl "${kube_flags[@]:?}" apply --server-dry-run -f hack/testdata/CRD/resource.yaml "${kube_flags[@]:?}"
  108. # Make sure that the CR doesn't exist
  109. ! kubectl "${kube_flags[@]:?}" get resource/myobj
  110. # clean-up
  111. kubectl "${kube_flags[@]:?}" delete customresourcedefinition resources.mygroup.example.com
  112. ## kubectl apply --prune
  113. # Pre-Condition: no POD exists
  114. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  115. # apply a
  116. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  117. # check right pod exists
  118. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  119. # check wrong pod doesn't exist
  120. output_message=$(! kubectl get pods b 2>&1 "${kube_flags[@]:?}")
  121. kube::test::if_has_string "${output_message}" 'pods "b" not found'
  122. # apply b
  123. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/b.yaml "${kube_flags[@]:?}"
  124. # check right pod exists
  125. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  126. # check wrong pod doesn't exist
  127. output_message=$(! kubectl get pods a 2>&1 "${kube_flags[@]:?}")
  128. kube::test::if_has_string "${output_message}" 'pods "a" not found'
  129. # cleanup
  130. kubectl delete pods b
  131. # same thing without prune for a sanity check
  132. # Pre-Condition: no POD exists
  133. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  134. # apply a
  135. kubectl apply -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  136. # check right pod exists
  137. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  138. # check wrong pod doesn't exist
  139. output_message=$(! kubectl get pods b 2>&1 "${kube_flags[@]:?}")
  140. kube::test::if_has_string "${output_message}" 'pods "b" not found'
  141. # apply b
  142. kubectl apply -l prune-group=true -f hack/testdata/prune/b.yaml "${kube_flags[@]:?}"
  143. # check both pods exist
  144. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  145. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  146. # check wrong pod doesn't exist
  147. # cleanup
  148. kubectl delete pod/a pod/b
  149. ## kubectl apply --prune requires a --all flag to select everything
  150. output_message=$(! kubectl apply --prune -f hack/testdata/prune 2>&1 "${kube_flags[@]:?}")
  151. kube::test::if_has_string "${output_message}" \
  152. 'all resources selected for prune without explicitly passing --all'
  153. # should apply everything
  154. kubectl apply --all --prune -f hack/testdata/prune
  155. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  156. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  157. kubectl delete pod/a pod/b
  158. ## kubectl apply --prune should fallback to delete for non reapable types
  159. kubectl apply --all --prune -f hack/testdata/prune-reap/a.yml 2>&1 "${kube_flags[@]:?}"
  160. kube::test::get_object_assert 'pvc a-pvc' "{{${id_field:?}}}" 'a-pvc'
  161. kubectl apply --all --prune -f hack/testdata/prune-reap/b.yml 2>&1 "${kube_flags[@]:?}"
  162. kube::test::get_object_assert 'pvc b-pvc' "{{${id_field:?}}}" 'b-pvc'
  163. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  164. kubectl delete pvc b-pvc 2>&1 "${kube_flags[@]:?}"
  165. ## kubectl apply --prune --prune-whitelist
  166. # Pre-Condition: no POD exists
  167. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  168. # apply pod a
  169. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  170. # check right pod exists
  171. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  172. # apply svc and don't prune pod a by overwriting whitelist
  173. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/svc.yaml --prune-whitelist core/v1/Service 2>&1 "${kube_flags[@]:?}"
  174. kube::test::get_object_assert 'service prune-svc' "{{${id_field:?}}}" 'prune-svc'
  175. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  176. # apply svc and prune pod a with default whitelist
  177. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/svc.yaml 2>&1 "${kube_flags[@]:?}"
  178. kube::test::get_object_assert 'service prune-svc' "{{${id_field:?}}}" 'prune-svc'
  179. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  180. # cleanup
  181. kubectl delete svc prune-svc 2>&1 "${kube_flags[@]:?}"
  182. ## kubectl apply -f some.yml --force
  183. # Pre-condition: no service exists
  184. kube::test::get_object_assert services "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  185. # apply service a
  186. kubectl apply -f hack/testdata/service-revision1.yaml "${kube_flags[@]:?}"
  187. # check right service exists
  188. kube::test::get_object_assert 'services a' "{{${id_field:?}}}" 'a'
  189. # change immutable field and apply service a
  190. output_message=$(! kubectl apply -f hack/testdata/service-revision2.yaml 2>&1 "${kube_flags[@]:?}")
  191. kube::test::if_has_string "${output_message}" 'field is immutable'
  192. # apply --force to recreate resources for immutable fields
  193. kubectl apply -f hack/testdata/service-revision2.yaml --force "${kube_flags[@]:?}"
  194. # check immutable field exists
  195. kube::test::get_object_assert 'services a' "{{.spec.clusterIP}}" '10.0.0.12'
  196. # cleanup
  197. kubectl delete -f hack/testdata/service-revision2.yaml "${kube_flags[@]:?}"
  198. ## kubectl apply -k somedir
  199. kubectl apply -k hack/testdata/kustomize
  200. kube::test::get_object_assert 'configmap test-the-map' "{{${id_field}}}" 'test-the-map'
  201. kube::test::get_object_assert 'deployment test-the-deployment' "{{${id_field}}}" 'test-the-deployment'
  202. kube::test::get_object_assert 'service test-the-service' "{{${id_field}}}" 'test-the-service'
  203. # cleanup
  204. kubectl delete -k hack/testdata/kustomize
  205. ## kubectl apply --kustomize somedir
  206. kubectl apply --kustomize hack/testdata/kustomize
  207. kube::test::get_object_assert 'configmap test-the-map' "{{${id_field}}}" 'test-the-map'
  208. kube::test::get_object_assert 'deployment test-the-deployment' "{{${id_field}}}" 'test-the-deployment'
  209. kube::test::get_object_assert 'service test-the-service' "{{${id_field}}}" 'test-the-service'
  210. # cleanup
  211. kubectl delete --kustomize hack/testdata/kustomize
  212. set +o nounset
  213. set +o errexit
  214. }
  215. # Runs tests related to kubectl apply (server-side)
  216. run_kubectl_apply_tests() {
  217. set -o nounset
  218. set -o errexit
  219. create_and_use_new_namespace
  220. kube::log::status "Testing kubectl apply --experimental-server-side"
  221. ## kubectl apply should create the resource that doesn't exist yet
  222. # Pre-Condition: no POD exists
  223. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  224. # Command: apply a pod "test-pod" (doesn't exist) should create this pod
  225. kubectl apply --experimental-server-side -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  226. # Post-Condition: pod "test-pod" is created
  227. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  228. # Clean up
  229. kubectl delete pods test-pod "${kube_flags[@]:?}"
  230. ## kubectl apply --server-dry-run
  231. # Pre-Condition: no POD exists
  232. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  233. # apply dry-run
  234. kubectl apply --experimental-server-side --server-dry-run -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  235. # No pod exists
  236. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  237. # apply non dry-run creates the pod
  238. kubectl apply --experimental-server-side -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  239. # apply changes
  240. kubectl apply --experimental-server-side --server-dry-run -f hack/testdata/pod-apply.yaml "${kube_flags[@]:?}"
  241. # Post-Condition: label still has initial value
  242. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  243. # clean-up
  244. kubectl delete -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  245. ## kubectl apply dry-run on CR
  246. # Create CRD
  247. kubectl "${kube_flags_with_token[@]}" create -f - << __EOF__
  248. {
  249. "kind": "CustomResourceDefinition",
  250. "apiVersion": "apiextensions.k8s.io/v1beta1",
  251. "metadata": {
  252. "name": "resources.mygroup.example.com"
  253. },
  254. "spec": {
  255. "group": "mygroup.example.com",
  256. "version": "v1alpha1",
  257. "scope": "Namespaced",
  258. "names": {
  259. "plural": "resources",
  260. "singular": "resource",
  261. "kind": "Kind",
  262. "listKind": "KindList"
  263. }
  264. }
  265. }
  266. __EOF__
  267. # Dry-run create the CR
  268. kubectl "${kube_flags[@]:?}" apply --experimental-server-side --server-dry-run -f hack/testdata/CRD/resource.yaml "${kube_flags[@]:?}"
  269. # Make sure that the CR doesn't exist
  270. ! kubectl "${kube_flags[@]:?}" get resource/myobj
  271. # clean-up
  272. kubectl "${kube_flags[@]:?}" delete customresourcedefinition resources.mygroup.example.com
  273. set +o nounset
  274. set +o errexit
  275. }