apply.sh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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[@]:?}")" || exit 1
  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[@]:?}")" || exit 1
  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 || exit 1
  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. kubectl delete pods a
  130. kubectl delete pods b
  131. # apply a
  132. kubectl apply --namespace nsb -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  133. # apply b with namespace
  134. kubectl apply --namespace nsb --prune -l prune-group=true -f hack/testdata/prune/b.yaml "${kube_flags[@]:?}"
  135. # check right pod exists
  136. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  137. # check wrong pod doesn't exist
  138. output_message=$(! kubectl get pods a 2>&1 "${kube_flags[@]:?}")
  139. kube::test::if_has_string "${output_message}" 'pods "a" not found'
  140. # cleanup
  141. kubectl delete pods b
  142. # same thing without prune for a sanity check
  143. # Pre-Condition: no POD exists
  144. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  145. # apply a
  146. kubectl apply -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  147. # check right pod exists
  148. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  149. # check wrong pod doesn't exist
  150. output_message=$(! kubectl get pods b 2>&1 "${kube_flags[@]:?}")
  151. kube::test::if_has_string "${output_message}" 'pods "b" not found'
  152. # apply b
  153. kubectl apply -l prune-group=true -f hack/testdata/prune/b.yaml "${kube_flags[@]:?}"
  154. # check both pods exist
  155. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  156. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  157. # check wrong pod doesn't exist
  158. # cleanup
  159. kubectl delete pod/a pod/b
  160. ## kubectl apply --prune requires a --all flag to select everything
  161. output_message=$(! kubectl apply --prune -f hack/testdata/prune 2>&1 "${kube_flags[@]:?}")
  162. kube::test::if_has_string "${output_message}" \
  163. 'all resources selected for prune without explicitly passing --all'
  164. # should apply everything
  165. kubectl apply --all --prune -f hack/testdata/prune
  166. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  167. kube::test::get_object_assert 'pods b' "{{${id_field:?}}}" 'b'
  168. kubectl delete pod/a pod/b
  169. ## kubectl apply --prune should fallback to delete for non reapable types
  170. kubectl apply --all --prune -f hack/testdata/prune-reap/a.yml 2>&1 "${kube_flags[@]:?}"
  171. kube::test::get_object_assert 'pvc a-pvc' "{{${id_field:?}}}" 'a-pvc'
  172. kubectl apply --all --prune -f hack/testdata/prune-reap/b.yml 2>&1 "${kube_flags[@]:?}"
  173. kube::test::get_object_assert 'pvc b-pvc' "{{${id_field:?}}}" 'b-pvc'
  174. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  175. kubectl delete pvc b-pvc 2>&1 "${kube_flags[@]:?}"
  176. ## kubectl apply --prune --prune-whitelist
  177. # Pre-Condition: no POD exists
  178. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  179. # apply pod a
  180. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/a.yaml "${kube_flags[@]:?}"
  181. # check right pod exists
  182. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  183. # apply svc and don't prune pod a by overwriting whitelist
  184. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/svc.yaml --prune-whitelist core/v1/Service 2>&1 "${kube_flags[@]:?}"
  185. kube::test::get_object_assert 'service prune-svc' "{{${id_field:?}}}" 'prune-svc'
  186. kube::test::get_object_assert 'pods a' "{{${id_field:?}}}" 'a'
  187. # apply svc and prune pod a with default whitelist
  188. kubectl apply --prune -l prune-group=true -f hack/testdata/prune/svc.yaml 2>&1 "${kube_flags[@]:?}"
  189. kube::test::get_object_assert 'service prune-svc' "{{${id_field:?}}}" 'prune-svc'
  190. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  191. # cleanup
  192. kubectl delete svc prune-svc 2>&1 "${kube_flags[@]:?}"
  193. ## kubectl apply -f some.yml --force
  194. # Pre-condition: no service exists
  195. kube::test::get_object_assert services "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  196. # apply service a
  197. kubectl apply -f hack/testdata/service-revision1.yaml "${kube_flags[@]:?}"
  198. # check right service exists
  199. kube::test::get_object_assert 'services a' "{{${id_field:?}}}" 'a'
  200. # change immutable field and apply service a
  201. output_message=$(! kubectl apply -f hack/testdata/service-revision2.yaml 2>&1 "${kube_flags[@]:?}")
  202. kube::test::if_has_string "${output_message}" 'field is immutable'
  203. # apply --force to recreate resources for immutable fields
  204. kubectl apply -f hack/testdata/service-revision2.yaml --force "${kube_flags[@]:?}"
  205. # check immutable field exists
  206. kube::test::get_object_assert 'services a' "{{.spec.clusterIP}}" '10.0.0.12'
  207. # cleanup
  208. kubectl delete -f hack/testdata/service-revision2.yaml "${kube_flags[@]:?}"
  209. ## kubectl apply -k somedir
  210. kubectl apply -k hack/testdata/kustomize
  211. kube::test::get_object_assert 'configmap test-the-map' "{{${id_field}}}" 'test-the-map'
  212. kube::test::get_object_assert 'deployment test-the-deployment' "{{${id_field}}}" 'test-the-deployment'
  213. kube::test::get_object_assert 'service test-the-service' "{{${id_field}}}" 'test-the-service'
  214. # cleanup
  215. kubectl delete -k hack/testdata/kustomize
  216. ## kubectl apply --kustomize somedir
  217. kubectl apply --kustomize hack/testdata/kustomize
  218. kube::test::get_object_assert 'configmap test-the-map' "{{${id_field}}}" 'test-the-map'
  219. kube::test::get_object_assert 'deployment test-the-deployment' "{{${id_field}}}" 'test-the-deployment'
  220. kube::test::get_object_assert 'service test-the-service' "{{${id_field}}}" 'test-the-service'
  221. # cleanup
  222. kubectl delete --kustomize hack/testdata/kustomize
  223. set +o nounset
  224. set +o errexit
  225. }
  226. # Runs tests related to kubectl apply (server-side)
  227. run_kubectl_apply_tests() {
  228. set -o nounset
  229. set -o errexit
  230. create_and_use_new_namespace
  231. kube::log::status "Testing kubectl apply --server-side"
  232. ## kubectl apply should create the resource that doesn't exist yet
  233. # Pre-Condition: no POD exists
  234. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  235. # Command: apply a pod "test-pod" (doesn't exist) should create this pod
  236. kubectl apply --server-side -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  237. # Post-Condition: pod "test-pod" is created
  238. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  239. # Clean up
  240. kubectl delete pods test-pod "${kube_flags[@]:?}"
  241. ## kubectl apply --server-dry-run
  242. # Pre-Condition: no POD exists
  243. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  244. # apply dry-run
  245. kubectl apply --server-side --server-dry-run -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  246. # No pod exists
  247. kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
  248. # apply non dry-run creates the pod
  249. kubectl apply --server-side -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  250. # apply changes
  251. kubectl apply --server-side --server-dry-run -f hack/testdata/pod-apply.yaml "${kube_flags[@]:?}"
  252. # Post-Condition: label still has initial value
  253. kube::test::get_object_assert 'pods test-pod' "{{${labels_field:?}.name}}" 'test-pod-label'
  254. # clean-up
  255. kubectl delete -f hack/testdata/pod.yaml "${kube_flags[@]:?}"
  256. ## kubectl apply dry-run on CR
  257. # Create CRD
  258. kubectl "${kube_flags_with_token[@]}" create -f - << __EOF__
  259. {
  260. "kind": "CustomResourceDefinition",
  261. "apiVersion": "apiextensions.k8s.io/v1beta1",
  262. "metadata": {
  263. "name": "resources.mygroup.example.com"
  264. },
  265. "spec": {
  266. "group": "mygroup.example.com",
  267. "version": "v1alpha1",
  268. "scope": "Namespaced",
  269. "names": {
  270. "plural": "resources",
  271. "singular": "resource",
  272. "kind": "Kind",
  273. "listKind": "KindList"
  274. }
  275. }
  276. }
  277. __EOF__
  278. # Dry-run create the CR
  279. kubectl "${kube_flags[@]:?}" apply --server-side --server-dry-run -f hack/testdata/CRD/resource.yaml "${kube_flags[@]:?}"
  280. # Make sure that the CR doesn't exist
  281. ! kubectl "${kube_flags[@]:?}" get resource/myobj || exit 1
  282. # clean-up
  283. kubectl "${kube_flags[@]:?}" delete customresourcedefinition resources.mygroup.example.com
  284. set +o nounset
  285. set +o errexit
  286. }