k8s.io/kubernetes@v1.29.3/test/cmd/apps.sh (about)

     1  #!/usr/bin/env bash
     2  
     3  # Copyright 2018 The Kubernetes Authors.
     4  #
     5  # Licensed under the Apache License, Version 2.0 (the "License");
     6  # you may not use this file except in compliance with the License.
     7  # You may obtain a copy of the License at
     8  #
     9  #     http://www.apache.org/licenses/LICENSE-2.0
    10  #
    11  # Unless required by applicable law or agreed to in writing, software
    12  # distributed under the License is distributed on an "AS IS" BASIS,
    13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  # See the License for the specific language governing permissions and
    15  # limitations under the License.
    16  
    17  set -o errexit
    18  set -o nounset
    19  set -o pipefail
    20  
    21  run_daemonset_tests() {
    22    set -o nounset
    23    set -o errexit
    24  
    25    create_and_use_new_namespace
    26    kube::log::status "Testing kubectl(v1:daemonsets)"
    27  
    28    ### Create a rolling update DaemonSet
    29    # Pre-condition: no DaemonSet exists
    30    kube::test::get_object_assert daemonsets "{{range.items}}{{${id_field:?}}}:{{end}}" ''
    31    # Command
    32    kubectl apply -f hack/testdata/rollingupdate-daemonset.yaml "${kube_flags[@]:?}"
    33    # Template Generation should be 1
    34    kube::test::get_object_assert 'daemonsets bind' "{{${generation_field:?}}}" '1'
    35    kubectl apply -f hack/testdata/rollingupdate-daemonset.yaml "${kube_flags[@]:?}"
    36    # Template Generation should stay 1
    37    kube::test::get_object_assert 'daemonsets bind' "{{${generation_field:?}}}" '1'
    38    # Test set commands
    39    kubectl set image daemonsets/bind "${kube_flags[@]:?}" "*=registry.k8s.io/pause:test-cmd"
    40    kube::test::get_object_assert 'daemonsets bind' "{{${generation_field:?}}}" '2'
    41    kubectl set env daemonsets/bind "${kube_flags[@]:?}" foo=bar
    42    kube::test::get_object_assert 'daemonsets bind' "{{${generation_field:?}}}" '3'
    43    kubectl set resources daemonsets/bind "${kube_flags[@]:?}" --limits=cpu=200m,memory=512Mi
    44    kube::test::get_object_assert 'daemonsets bind' "{{${generation_field:?}}}" '4'
    45    # pod has field for kubectl set field manager
    46    output_message=$(kubectl get daemonsets bind --show-managed-fields -o=jsonpath='{.metadata.managedFields[*].manager}' "${kube_flags[@]:?}" 2>&1)
    47    kube::test::if_has_string "${output_message}" 'kubectl-set'
    48    # Describe command should respect the chunk size parameter
    49    kube::test::describe_resource_chunk_size_assert daemonsets pods,events
    50  
    51    # Rollout restart should change generation
    52    kubectl rollout restart daemonset/bind "${kube_flags[@]:?}"
    53    kube::test::get_object_assert 'daemonsets bind' "{{${generation_field:?}}}" '5'
    54  
    55    # Clean up
    56    kubectl delete -f hack/testdata/rollingupdate-daemonset.yaml "${kube_flags[@]:?}"
    57  
    58    set +o nounset
    59    set +o errexit
    60  }
    61  
    62  run_daemonset_history_tests() {
    63    set -o nounset
    64    set -o errexit
    65  
    66    create_and_use_new_namespace
    67    kube::log::status "Testing kubectl(v1:daemonsets, v1:controllerrevisions)"
    68  
    69    ### Test rolling back a DaemonSet
    70    # Pre-condition: no DaemonSet or its pods exists
    71    kube::test::get_object_assert daemonsets "{{range.items}}{{${id_field:?}}}:{{end}}" ''
    72    # Command
    73    # Create a DaemonSet (revision 1)
    74    kubectl apply -f hack/testdata/rollingupdate-daemonset.yaml --record "${kube_flags[@]:?}"
    75    kube::test::wait_object_assert controllerrevisions "{{range.items}}{{${annotations_field:?}}}:{{end}}" ".*rollingupdate-daemonset.yaml --record.*"
    76    # Rollback to revision 1 - should be no-op
    77    kubectl rollout undo daemonset --to-revision=1 "${kube_flags[@]:?}"
    78    kube::test::get_object_assert daemonset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_PAUSE_V2}:"
    79    kube::test::get_object_assert daemonset "{{range.items}}{{${container_len:?}}}{{end}}" "1"
    80    # Update the DaemonSet (revision 2)
    81    kubectl apply -f hack/testdata/rollingupdate-daemonset-rv2.yaml --record "${kube_flags[@]:?}"
    82    kube::test::wait_object_assert daemonset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DAEMONSET_R2}:"
    83    kube::test::wait_object_assert daemonset "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_DAEMONSET_R2_2}:"
    84    kube::test::get_object_assert daemonset "{{range.items}}{{${container_len:?}}}{{end}}" "2"
    85    kube::test::wait_object_assert controllerrevisions "{{range.items}}{{${annotations_field:?}}}:{{end}}" ".*rollingupdate-daemonset-rv2.yaml --record.*"
    86    # Get rollout history
    87    output_message=$(kubectl rollout history daemonset)
    88    kube::test::if_has_string "${output_message}" "daemonset.apps/bind"
    89    kube::test::if_has_string "${output_message}" "REVISION  CHANGE-CAUSE"
    90    kube::test::if_has_string "${output_message}" "1         kubectl apply"
    91    kube::test::if_has_string "${output_message}" "2         kubectl apply"
    92    # Get rollout history for a single revision
    93    output_message=$(kubectl rollout history daemonset --revision=1)
    94    kube::test::if_has_string "${output_message}" "daemonset.apps/bind with revision #1"
    95    kube::test::if_has_string "${output_message}" "Pod Template:"
    96    kube::test::if_has_string "${output_message}" "${IMAGE_PAUSE_V2}"
    97    # Get rollout history for a different single revision
    98    output_message=$(kubectl rollout history daemonset --revision=2)
    99    kube::test::if_has_string "${output_message}" "daemonset.apps/bind with revision #2"
   100    kube::test::if_has_string "${output_message}" "Pod Template:"
   101    kube::test::if_has_string "${output_message}" "${IMAGE_DAEMONSET_R2}"
   102    kube::test::if_has_string "${output_message}" "${IMAGE_DAEMONSET_R2_2}"
   103    # Rollback to revision 1 with dry-run - should be no-op
   104    kubectl rollout undo daemonset --dry-run=client "${kube_flags[@]:?}"
   105    kubectl rollout undo daemonset --dry-run=server "${kube_flags[@]:?}"
   106    kube::test::get_object_assert daemonset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DAEMONSET_R2}:"
   107    kube::test::get_object_assert daemonset "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_DAEMONSET_R2_2}:"
   108    kube::test::get_object_assert daemonset "{{range.items}}{{${container_len:?}}}{{end}}" "2"
   109    # Rollback to revision 1
   110    kubectl rollout undo daemonset --to-revision=1 "${kube_flags[@]:?}"
   111    kube::test::wait_object_assert daemonset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_PAUSE_V2}:"
   112    kube::test::get_object_assert daemonset "{{range.items}}{{${container_len:?}}}{{end}}" "1"
   113    # Get rollout history
   114    output_message=$(kubectl rollout history daemonset)
   115    kube::test::if_has_string "${output_message}" "daemonset.apps/bind"
   116    kube::test::if_has_string "${output_message}" "REVISION  CHANGE-CAUSE"
   117    kube::test::if_has_string "${output_message}" "2         kubectl apply"
   118    kube::test::if_has_string "${output_message}" "3         kubectl apply"
   119    # Rollback to revision 1000000 - should fail
   120    output_message=$(! kubectl rollout undo daemonset --to-revision=1000000 "${kube_flags[@]:?}" 2>&1)
   121    kube::test::if_has_string "${output_message}" "unable to find specified revision"
   122    kube::test::get_object_assert daemonset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_PAUSE_V2}:"
   123    kube::test::get_object_assert daemonset "{{range.items}}{{${container_len:?}}}{{end}}" "1"
   124    # Rollback to last revision
   125    kubectl rollout undo daemonset "${kube_flags[@]:?}"
   126    kube::test::wait_object_assert daemonset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DAEMONSET_R2}:"
   127    kube::test::wait_object_assert daemonset "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_DAEMONSET_R2_2}:"
   128    kube::test::get_object_assert daemonset "{{range.items}}{{${container_len:?}}}{{end}}" "2"
   129    # Get rollout history
   130    output_message=$(kubectl rollout history daemonset)
   131    kube::test::if_has_string "${output_message}" "daemonset.apps/bind"
   132    kube::test::if_has_string "${output_message}" "REVISION  CHANGE-CAUSE"
   133    kube::test::if_has_string "${output_message}" "3         kubectl apply"
   134    kube::test::if_has_string "${output_message}" "4         kubectl apply"
   135    # Clean up
   136    kubectl delete -f hack/testdata/rollingupdate-daemonset.yaml "${kube_flags[@]:?}"
   137  
   138    set +o nounset
   139    set +o errexit
   140  }
   141  
   142  run_kubectl_apply_deployments_tests() {
   143    set -o nounset
   144    set -o errexit
   145  
   146    create_and_use_new_namespace
   147    kube::log::status "Testing kubectl apply deployments"
   148    ## kubectl apply should propagate user defined null values
   149    # Pre-Condition: no Deployments, ReplicaSets, Pods exist
   150    kube::test::get_object_assert deployments "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   151    kube::test::get_object_assert replicasets "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   152    kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   153    # apply base deployment
   154    kubectl apply -f hack/testdata/null-propagation/deployment-l1.yaml "${kube_flags[@]:?}"
   155    # check right deployment exists
   156    kube::test::get_object_assert 'deployments my-depl' "{{${id_field:?}}}" 'my-depl'
   157    # check right labels exists
   158    kube::test::get_object_assert 'deployments my-depl' "{{.spec.template.metadata.labels.l1}}" 'l1'
   159    kube::test::get_object_assert 'deployments my-depl' "{{.spec.selector.matchLabels.l1}}" 'l1'
   160    kube::test::get_object_assert 'deployments my-depl' "{{.metadata.labels.l1}}" 'l1'
   161  
   162    # apply new deployment with new template labels
   163    kubectl apply -f hack/testdata/null-propagation/deployment-l2.yaml "${kube_flags[@]:?}"
   164    # check right labels exists
   165    kube::test::get_object_assert 'deployments my-depl' "{{.spec.template.metadata.labels.l1}}" 'l1'
   166    kube::test::get_object_assert 'deployments my-depl' "{{.spec.selector.matchLabels.l1}}" 'l1'
   167    kube::test::get_object_assert 'deployments my-depl' "{{.metadata.labels.l1}}" '<no value>'
   168  
   169    # cleanup
   170    # need to explicitly remove replicasets and pods because we changed the deployment selector and orphaned things
   171    kubectl delete deployments,rs,pods --all --cascade=orphan --grace-period=0
   172    # Post-Condition: no Deployments, ReplicaSets, Pods exist
   173    kube::test::wait_object_assert deployments "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   174    kube::test::wait_object_assert replicasets "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   175    kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   176  
   177    # kubectl apply deployment --overwrite=true --force=true
   178    # Pre-Condition: no deployment exists
   179    kube::test::get_object_assert deployments "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   180    # apply deployment nginx
   181    kubectl apply -f hack/testdata/deployment-label-change1.yaml "${kube_flags[@]:?}"
   182    # check right deployment exists
   183    kube::test::get_object_assert 'deployment nginx' "{{${id_field:?}}}" 'nginx'
   184    # apply deployment with new labels and a conflicting resourceVersion
   185    output_message=$(! kubectl apply -f hack/testdata/deployment-label-change2.yaml 2>&1 "${kube_flags[@]:?}")
   186    kube::test::if_has_string "${output_message}" 'Error from server (Conflict)'
   187    # apply deployment with --force and --overwrite will succeed
   188    kubectl apply -f hack/testdata/deployment-label-change2.yaml --overwrite=true  --force=true --grace-period=10
   189    # check the changed deployment
   190    output_message=$(kubectl apply view-last-applied deploy/nginx -o json 2>&1 "${kube_flags[@]:?}" |grep nginx2)
   191    kube::test::if_has_string "${output_message}" '"name": "nginx2"'
   192    # applying a resource (with --force) that is both conflicting and invalid will
   193    # cause the server to only return a "Conflict" error when we attempt to patch.
   194    # This means that we will delete the existing resource after receiving 5 conflict
   195    # errors in a row from the server, and will attempt to create the modified
   196    # resource that we are passing to "apply". Since the modified resource is also
   197    # invalid, we will receive an invalid error when we attempt to create it, after
   198    # having deleted the old resource. Ensure that when this case is reached, the
   199    # old resource is restored once again, and the validation error is printed.
   200    output_message=$(! kubectl apply -f hack/testdata/deployment-label-change3.yaml --force 2>&1 "${kube_flags[@]:?}")
   201    kube::test::if_has_string "${output_message}" 'Invalid value'
   202    # Ensure that the old object has been restored
   203    kube::test::get_object_assert 'deployment nginx' "{{${template_labels:?}}}" 'nginx2'
   204    # cleanup
   205    kubectl delete deployments --all --grace-period=10
   206  
   207    set +o nounset
   208    set +o errexit
   209  }
   210  
   211  run_deployment_tests() {
   212    set -o nounset
   213    set -o errexit
   214  
   215    create_and_use_new_namespace
   216    kube::log::status "Testing deployments"
   217    # Test kubectl create deployment (using default - old generator)
   218    kubectl create deployment test-nginx-extensions --image=registry.k8s.io/nginx:test-cmd
   219    # Post-Condition: Deployment "nginx" is created.
   220    kube::test::get_object_assert 'deploy test-nginx-extensions' "{{${container_name_field:?}}}" 'nginx'
   221    # and old generator was used, iow. old defaults are applied
   222    output_message=$(kubectl get deployment.apps/test-nginx-extensions -o jsonpath='{.spec.revisionHistoryLimit}')
   223    kube::test::if_has_not_string "${output_message}" '2'
   224    # Ensure we can interact with deployments through apps endpoints
   225    output_message=$(kubectl get deployment.apps -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]:?}")
   226    kube::test::if_has_string "${output_message}" 'apps/v1'
   227    # Clean up
   228    kubectl delete deployment test-nginx-extensions "${kube_flags[@]:?}"
   229  
   230    # Test kubectl create deployment
   231    kubectl create deployment test-nginx-apps --image=registry.k8s.io/nginx:test-cmd
   232    # Post-Condition: Deployment "nginx" is created.
   233    kube::test::get_object_assert 'deploy test-nginx-apps' "{{${container_name_field:?}}}" 'nginx'
   234    # and new generator was used, iow. new defaults are applied
   235    output_message=$(kubectl get deployment/test-nginx-apps -o jsonpath='{.spec.revisionHistoryLimit}')
   236    kube::test::if_has_string "${output_message}" '10'
   237    # Ensure we can interact with deployments through apps endpoints
   238    output_message=$(kubectl get deployment.apps -o=jsonpath='{.items[0].apiVersion}' 2>&1 "${kube_flags[@]:?}")
   239    kube::test::if_has_string "${output_message}" 'apps/v1'
   240    # Describe command (resource only) should print detailed information
   241    kube::test::describe_resource_assert rs "Name:" "Pod Template:" "Labels:" "Selector:" "Controlled By" "Replicas:" "Pods Status:" "Volumes:"
   242    # Describe command (resource only) should print detailed information
   243    kube::test::describe_resource_assert pods "Name:" "Image:" "Node:" "Labels:" "Status:" "Controlled By"
   244    # Describe command should respect the chunk size parameter
   245    kube::test::describe_resource_chunk_size_assert deployments replicasets,events
   246    # Clean up
   247    kubectl delete deployment test-nginx-apps "${kube_flags[@]:?}"
   248  
   249    ### Test kubectl create deployment with image and command
   250    # Pre-Condition: No deployment exists.
   251    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   252    # Dry-run command
   253    kubectl create deployment nginx-with-command --dry-run=client --image=registry.k8s.io/nginx:test-cmd -- /bin/sleep infinity
   254    kubectl create deployment nginx-with-command --dry-run=server --image=registry.k8s.io/nginx:test-cmd -- /bin/sleep infinity
   255    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   256    # Command
   257    kubectl create deployment nginx-with-command --image=registry.k8s.io/nginx:test-cmd -- /bin/sleep infinity
   258    # Post-Condition: Deployment "nginx" is created.
   259    kube::test::get_object_assert 'deploy nginx-with-command' "{{${container_name_field:?}}}" 'nginx'
   260    # Clean up
   261    kubectl delete deployment nginx-with-command "${kube_flags[@]:?}"
   262  
   263    ### Test kubectl create deployment should not fail validation
   264    # Pre-Condition: No deployment exists.
   265    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   266    # Command
   267    kubectl create -f hack/testdata/deployment-with-UnixUserID.yaml "${kube_flags[@]:?}"
   268    # Post-Condition: Deployment "deployment-with-unixuserid" is created.
   269    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" 'deployment-with-unixuserid:'
   270    # Clean up
   271    kubectl delete deployment deployment-with-unixuserid "${kube_flags[@]:?}"
   272  
   273    ### Test cascading deletion
   274    ## Test that rs is deleted when deployment is deleted.
   275    # Pre-condition: no deployment exists
   276    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   277    # Create deployment
   278    kubectl create -f test/fixtures/doc-yaml/user-guide/deployment.yaml "${kube_flags[@]:?}"
   279    # Wait for rs to come up.
   280    kube::test::wait_object_assert rs "{{range.items}}{{${rs_replicas_field:?}}}{{end}}" '3'
   281    # Deleting the deployment should delete the rs.
   282    # using empty value in cascade flag to make sure the backward compatibility.
   283    kubectl delete deployment nginx-deployment "${kube_flags[@]:?}" --cascade
   284    kube::test::wait_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   285  
   286    ## Test that rs is not deleted when deployment is deleted with cascading strategy set to orphan.
   287    # Pre-condition: no deployment and rs exist
   288    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   289    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   290    # Create deployment
   291    kubectl create deployment nginx-deployment --image=registry.k8s.io/nginx:test-cmd
   292    # Wait for rs to come up.
   293    kube::test::wait_object_assert rs "{{range.items}}{{${rs_replicas_field:?}}}{{end}}" '1'
   294    # Delete the deployment with cascading strategy set to orphan.
   295    kubectl delete deployment nginx-deployment "${kube_flags[@]:?}" --cascade=orphan
   296    # Wait for the deployment to be deleted and then verify that rs is not
   297    # deleted.
   298    kube::test::wait_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   299    kube::test::get_object_assert rs "{{range.items}}{{${rs_replicas_field:?}}}{{end}}" '1'
   300    # Cleanup
   301    # Find the name of the rs to be deleted.
   302    output_message=$(kubectl get rs "${kube_flags[@]:?}" -o template --template="{{range.items}}{{${id_field:?}}}{{end}}")
   303    kubectl delete rs "${output_message}" "${kube_flags[@]:?}"
   304  
   305    ### Auto scale deployment
   306    # Pre-condition: no deployment exists
   307    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   308    # Pre-condition: no hpa exists
   309    kube::test::get_object_assert 'hpa' "{{range.items}}{{ if eq $id_field \"nginx-deployment\" }}found{{end}}{{end}}:" ':'
   310    # Command
   311    kubectl create -f test/fixtures/doc-yaml/user-guide/deployment.yaml "${kube_flags[@]:?}"
   312    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" 'nginx-deployment:'
   313    # Dry-run autoscale
   314    kubectl-with-retry autoscale deployment nginx-deployment --dry-run=client "${kube_flags[@]:?}" --min=2 --max=3
   315    kubectl-with-retry autoscale deployment nginx-deployment --dry-run=server "${kube_flags[@]:?}" --min=2 --max=3
   316    kube::test::get_object_assert 'hpa' "{{range.items}}{{ if eq $id_field \"nginx-deployment\" }}found{{end}}{{end}}:" ':'
   317    # autoscale 2~3 pods, no CPU utilization specified
   318    kubectl-with-retry autoscale deployment nginx-deployment "${kube_flags[@]:?}" --min=2 --max=3
   319    kube::test::get_object_assert 'hpa nginx-deployment' "{{${hpa_min_field:?}}} {{${hpa_max_field:?}}} {{${hpa_cpu_field:?}}}" '2 3 80'
   320    # Describe command should respect the chunk size parameter
   321    kube::test::describe_resource_chunk_size_assert horizontalpodautoscalers events
   322    # Clean up
   323    # Note that we should delete hpa first, otherwise it may fight with the deployment reaper.
   324    kubectl delete hpa nginx-deployment "${kube_flags[@]:?}"
   325    kubectl delete deployment.apps nginx-deployment "${kube_flags[@]:?}"
   326  
   327    ### Rollback a deployment
   328    # Pre-condition: no deployment exists
   329    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   330    # Command
   331    # Create a deployment (revision 1)
   332    kubectl create -f hack/testdata/deployment-revision1.yaml "${kube_flags[@]:?}"
   333    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" 'nginx:'
   334    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   335    # Rollback to revision 1 - should be no-op
   336    kubectl rollout undo deployment nginx --to-revision=1 "${kube_flags[@]:?}"
   337    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   338    # Update the deployment (revision 2)
   339    kubectl apply -f hack/testdata/deployment-revision2.yaml "${kube_flags[@]:?}"
   340    kube::test::get_object_assert deployment.apps "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
   341    # Rollback to revision 1 with dry-run - should be no-op
   342    kubectl rollout undo deployment nginx --dry-run=client "${kube_flags[@]:?}" | grep "test-cmd"
   343    kubectl rollout undo deployment nginx --dry-run=server "${kube_flags[@]:?}"
   344    kube::test::get_object_assert deployment.apps "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
   345    # Rollback to revision 1
   346    kubectl rollout undo deployment nginx --to-revision=1 "${kube_flags[@]:?}"
   347    sleep 1
   348    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   349    # Rollback to revision 1000000 - should be no-op
   350    ! kubectl rollout undo deployment nginx --to-revision=1000000 "${kube_flags[@]:?}" || exit 1
   351    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   352    # Rollback to last revision
   353    kubectl rollout undo deployment nginx "${kube_flags[@]:?}"
   354    sleep 1
   355    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
   356    # Pause the deployment
   357    kubectl-with-retry rollout pause deployment nginx "${kube_flags[@]:?}"
   358    # A paused deployment cannot be rolled back
   359    ! kubectl rollout undo deployment nginx "${kube_flags[@]:?}" || exit 1
   360    # A paused deployment cannot be restarted
   361    ! kubectl rollout restart deployment nginx "${kube_flags[@]:?}" || exit 1
   362    # Resume the deployment
   363    kubectl-with-retry rollout resume deployment nginx "${kube_flags[@]:?}"
   364    # The resumed deployment can now be rolled back
   365    kubectl rollout undo deployment nginx "${kube_flags[@]:?}"
   366    # Check that the new replica set has all old revisions stored in an annotation
   367    newrs="$(kubectl describe deployment nginx | grep NewReplicaSet | awk '{print $2}')"
   368    kubectl get rs "${newrs}" -o yaml | grep "deployment.kubernetes.io/revision-history: 1,3"
   369    # Check that trying to watch the status of a superseded revision returns an error
   370    ! kubectl rollout status deployment/nginx --revision=3 || exit 1
   371    # Restarting the deployment creates a new replicaset
   372    kubectl rollout restart deployment/nginx
   373    sleep 1
   374    newrs="$(kubectl describe deployment nginx | grep NewReplicaSet | awk '{print $2}')"
   375    rs="$(kubectl get rs "${newrs}" -o yaml)"
   376    kube::test::if_has_string "${rs}" "deployment.kubernetes.io/revision: \"6\""
   377    # Deployment has field for kubectl rollout field manager
   378    output_message=$(kubectl get deployment nginx --show-managed-fields -o=jsonpath='{.metadata.managedFields[*].manager}' "${kube_flags[@]:?}" 2>&1)
   379    kube::test::if_has_string "${output_message}" 'kubectl-rollout'
   380    # Create second deployment
   381    ${SED} "s/name: nginx$/name: nginx2/" hack/testdata/deployment-revision1.yaml | kubectl create -f - "${kube_flags[@]:?}"
   382    # Deletion of both deployments should not be blocked
   383    kubectl delete deployment nginx2 "${kube_flags[@]:?}"
   384    # Clean up
   385    kubectl delete deployment nginx "${kube_flags[@]:?}"
   386  
   387    ### Set image of a deployment
   388    # Pre-condition: no deployment exists
   389    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   390    # Create a deployment
   391    kubectl create -f hack/testdata/deployment-multicontainer.yaml "${kube_flags[@]:?}"
   392    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" 'nginx-deployment:'
   393    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   394    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PERL}:"
   395    # Dry-run set the deployment's image
   396    kubectl set image deployment nginx-deployment nginx="${IMAGE_DEPLOYMENT_R2}" --dry-run=client "${kube_flags[@]:?}"
   397    kubectl set image deployment nginx-deployment nginx="${IMAGE_DEPLOYMENT_R2}" --dry-run=server "${kube_flags[@]:?}"
   398    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   399    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PERL}:"
   400    # Set the deployment's image
   401    kubectl set image deployment nginx-deployment nginx="${IMAGE_DEPLOYMENT_R2}" "${kube_flags[@]:?}"
   402    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
   403    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PERL}:"
   404    # Set non-existing container should fail
   405    ! kubectl set image deployment nginx-deployment redis=redis "${kube_flags[@]:?}" || exit 1
   406    # Set image of deployments without specifying name
   407    kubectl set image deployments --all nginx="${IMAGE_DEPLOYMENT_R1}" "${kube_flags[@]:?}"
   408    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   409    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PERL}:"
   410    # Set image of a deployment specified by file
   411    kubectl set image -f hack/testdata/deployment-multicontainer.yaml nginx="${IMAGE_DEPLOYMENT_R2}" "${kube_flags[@]:?}"
   412    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
   413    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PERL}:"
   414    # Set image of a local file without talking to the server
   415    kubectl set image -f hack/testdata/deployment-multicontainer.yaml nginx="${IMAGE_DEPLOYMENT_R1}" "${kube_flags[@]:?}" --local -o yaml
   416    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
   417    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PERL}:"
   418    # Set image of all containers of the deployment
   419    kubectl set image deployment nginx-deployment "*=${IMAGE_DEPLOYMENT_R1}" "${kube_flags[@]:?}"
   420    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   421    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   422    # Set image of all containers of the deployment again when image not change
   423    kubectl set image deployment nginx-deployment "*=${IMAGE_DEPLOYMENT_R1}" "${kube_flags[@]:?}"
   424    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   425    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   426    # Clean up
   427    kubectl delete deployment nginx-deployment "${kube_flags[@]:?}"
   428  
   429    ### Set env of a deployment
   430    # Pre-condition: no deployment exists
   431    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   432    # Create a deployment
   433    kubectl create -f hack/testdata/deployment-multicontainer.yaml "${kube_flags[@]:?}"
   434    kubectl create -f hack/testdata/configmap.yaml "${kube_flags[@]:?}"
   435    kubectl create -f hack/testdata/secret.yaml "${kube_flags[@]:?}"
   436    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" 'nginx-deployment:'
   437    #configmap is special here due to controller will create kube-root-ca.crt for each namespace automatically
   438    kube::test::get_object_assert 'configmaps/test-set-env-config' "{{${id_field:?}}}" 'test-set-env-config'
   439    kube::test::get_object_assert secret "{{range.items}}{{${id_field:?}}}:{{end}}" 'test-set-env-secret:'
   440    # Set env of deployments by configmap from keys
   441    kubectl set env deployment nginx-deployment --keys=key-2 --from=configmap/test-set-env-config "${kube_flags[@]:?}"
   442    # Assert correct value in deployment env
   443    kube::test::get_object_assert 'deploy nginx-deployment' "{{ (index (index .spec.template.spec.containers 0).env 0).name}}" 'KEY_2'
   444    # Assert single value in deployment env
   445    kube::test::get_object_assert 'deploy nginx-deployment' "{{ len (index .spec.template.spec.containers 0).env }}" '1'
   446    # Dry-run set env
   447    kubectl set env deployment nginx-deployment --dry-run=client --from=configmap/test-set-env-config "${kube_flags[@]:?}"
   448    kubectl set env deployment nginx-deployment --dry-run=server --from=configmap/test-set-env-config "${kube_flags[@]:?}"
   449    kube::test::get_object_assert 'deploy nginx-deployment' "{{ len (index .spec.template.spec.containers 0).env }}" '1'
   450    # Set env of deployments by configmap
   451    kubectl set env deployment nginx-deployment --from=configmap/test-set-env-config "${kube_flags[@]:?}"
   452    # Assert all values in deployment env
   453    kube::test::get_object_assert 'deploy nginx-deployment' "{{ len (index .spec.template.spec.containers 0).env }}" '2'
   454    # Set env of deployments for all container
   455    kubectl set env deployment nginx-deployment env=prod "${kube_flags[@]:?}"
   456    # Set env of deployments for specific container
   457    kubectl set env deployment nginx-deployment superenv=superprod -c=nginx "${kube_flags[@]:?}"
   458    # Set env of deployments by secret from keys
   459    kubectl set env deployment nginx-deployment --keys=username --from=secret/test-set-env-secret "${kube_flags[@]:?}"
   460    # Set env of deployments by secret
   461    kubectl set env deployment nginx-deployment --from=secret/test-set-env-secret "${kube_flags[@]:?}"
   462    # Remove specific env of deployment
   463    kubectl set env deployment nginx-deployment env-
   464    # Assert that we cannot use standard input for both resource and environment variable
   465    output_message="$(echo SOME_ENV_VAR_KEY=SOME_ENV_VAR_VAL | kubectl set env -f - - "${kube_flags[@]:?}" 2>&1 || true)"
   466    kube::test::if_has_string "${output_message}" 'standard input cannot be used for multiple arguments'
   467    # Clean up
   468    kubectl delete deployment nginx-deployment "${kube_flags[@]:?}"
   469    kubectl delete configmap test-set-env-config "${kube_flags[@]:?}"
   470    kubectl delete secret test-set-env-secret "${kube_flags[@]:?}"
   471  
   472    ### Get rollout history
   473    # Pre-condition: no deployment exists
   474    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   475    # Create a deployment
   476    kubectl create -f hack/testdata/deployment-multicontainer.yaml "${kube_flags[@]:?}"
   477    kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" 'nginx-deployment:'
   478    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R1}:"
   479    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PERL}:"
   480    # Set the deployment's image
   481    kubectl set image deployment nginx-deployment nginx="${IMAGE_DEPLOYMENT_R2}" "${kube_flags[@]:?}"
   482    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
   483    kube::test::get_object_assert deployment "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PERL}:"
   484    # Get rollout history
   485    output_message=$(kubectl rollout history deployment nginx-deployment)
   486    kube::test::if_has_string "${output_message}" "deployment.apps/nginx-deployment"
   487    kube::test::if_has_string "${output_message}" "REVISION  CHANGE-CAUSE"
   488    kube::test::if_has_string "${output_message}" "1         <none>"
   489    kube::test::if_has_string "${output_message}" "2         <none>"
   490    kube::test::if_has_not_string "${output_message}" "3         <none>"
   491    # Get rollout history for a single revision
   492    output_message=$(kubectl rollout history deployment nginx-deployment --revision=1)
   493    kube::test::if_has_string "${output_message}" "deployment.apps/nginx-deployment with revision #1"
   494    kube::test::if_has_string "${output_message}" "Pod Template:"
   495    kube::test::if_has_string "${output_message}" "${IMAGE_DEPLOYMENT_R1}"
   496    kube::test::if_has_string "${output_message}" "${IMAGE_PERL}"
   497    # Get rollout history for a different single revision
   498    output_message=$(kubectl rollout history deployment nginx-deployment --revision=2)
   499    kube::test::if_has_string "${output_message}" "deployment.apps/nginx-deployment with revision #2"
   500    kube::test::if_has_string "${output_message}" "Pod Template:"
   501    kube::test::if_has_string "${output_message}" "${IMAGE_DEPLOYMENT_R2}"
   502    kube::test::if_has_string "${output_message}" "${IMAGE_PERL}"
   503    # Clean up
   504    kubectl delete deployment nginx-deployment "${kube_flags[@]:?}"
   505  
   506    set +o nounset
   507    set +o errexit
   508  }
   509  
   510  run_statefulset_history_tests() {
   511    set -o nounset
   512    set -o errexit
   513  
   514    create_and_use_new_namespace
   515    kube::log::status "Testing kubectl(v1:statefulsets, v1:controllerrevisions)"
   516  
   517    ### Test rolling back a StatefulSet
   518    # Pre-condition: no statefulset or its pods exists
   519    kube::test::get_object_assert statefulset "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   520    # Command
   521    # Create a StatefulSet (revision 1)
   522    kubectl apply -f hack/testdata/rollingupdate-statefulset.yaml --record "${kube_flags[@]:?}"
   523    kube::test::wait_object_assert controllerrevisions "{{range.items}}{{${annotations_field:?}}}:{{end}}" ".*rollingupdate-statefulset.yaml --record.*"
   524    # Rollback to revision 1 - should be no-op
   525    kubectl rollout undo statefulset --to-revision=1 "${kube_flags[@]:?}"
   526    kube::test::get_object_assert statefulset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_STATEFULSET_R1}:"
   527    kube::test::get_object_assert statefulset "{{range.items}}{{${container_len:?}}}{{end}}" "1"
   528    # Update the statefulset (revision 2)
   529    kubectl apply -f hack/testdata/rollingupdate-statefulset-rv2.yaml --record "${kube_flags[@]:?}"
   530    kube::test::wait_object_assert statefulset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_STATEFULSET_R2}:"
   531    kube::test::wait_object_assert statefulset "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PAUSE_V2}:"
   532    kube::test::get_object_assert statefulset "{{range.items}}{{${container_len:?}}}{{end}}" "2"
   533    kube::test::wait_object_assert controllerrevisions "{{range.items}}{{${annotations_field:?}}}:{{end}}" ".*rollingupdate-statefulset-rv2.yaml --record.*"
   534    # Get rollout history
   535    output_message=$(kubectl rollout history statefulset)
   536    kube::test::if_has_string "${output_message}" "statefulset.apps/nginx"
   537    kube::test::if_has_string "${output_message}" "REVISION  CHANGE-CAUSE"
   538    kube::test::if_has_string "${output_message}" "1         kubectl apply"
   539    kube::test::if_has_string "${output_message}" "2         kubectl apply"
   540    # Get rollout history for a single revision
   541    output_message=$(kubectl rollout history statefulset --revision=1)
   542    kube::test::if_has_string "${output_message}" "statefulset.apps/nginx with revision #1"
   543    kube::test::if_has_string "${output_message}" "Pod Template:"
   544    kube::test::if_has_string "${output_message}" "${IMAGE_STATEFULSET_R1}"
   545    # Get rollout history for a different single revision
   546    output_message=$(kubectl rollout history statefulset --revision=2)
   547    kube::test::if_has_string "${output_message}" "statefulset.apps/nginx with revision #2"
   548    kube::test::if_has_string "${output_message}" "Pod Template:"
   549    kube::test::if_has_string "${output_message}" "${IMAGE_STATEFULSET_R2}"
   550    kube::test::if_has_string "${output_message}" "${IMAGE_PAUSE_V2}"
   551    # Rollback to revision 1 with dry-run - should be no-op
   552    kubectl rollout undo statefulset --dry-run=client "${kube_flags[@]:?}"
   553    kubectl rollout undo statefulset --dry-run=server "${kube_flags[@]:?}"
   554    kube::test::get_object_assert statefulset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_STATEFULSET_R2}:"
   555    kube::test::get_object_assert statefulset "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PAUSE_V2}:"
   556    kube::test::get_object_assert statefulset "{{range.items}}{{${container_len:?}}}{{end}}" "2"
   557    # Rollback to revision 1
   558    kubectl rollout undo statefulset --to-revision=1 "${kube_flags[@]:?}"
   559    kube::test::wait_object_assert statefulset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_STATEFULSET_R1}:"
   560    kube::test::get_object_assert statefulset "{{range.items}}{{${container_len:?}}}{{end}}" "1"
   561    # Get rollout history
   562    output_message=$(kubectl rollout history statefulset)
   563    kube::test::if_has_string "${output_message}" "statefulset.apps/nginx"
   564    kube::test::if_has_string "${output_message}" "REVISION  CHANGE-CAUSE"
   565    kube::test::if_has_string "${output_message}" "2         kubectl apply"
   566    kube::test::if_has_string "${output_message}" "3         kubectl apply"
   567    # Rollback to revision 1000000 - should fail
   568    output_message=$(! kubectl rollout undo statefulset --to-revision=1000000 "${kube_flags[@]:?}" 2>&1)
   569    kube::test::if_has_string "${output_message}" "unable to find specified revision"
   570    kube::test::get_object_assert statefulset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_STATEFULSET_R1}:"
   571    kube::test::get_object_assert statefulset "{{range.items}}{{${container_len:?}}}{{end}}" "1"
   572    # Rollback to last revision
   573    kubectl rollout undo statefulset "${kube_flags[@]:?}"
   574    kube::test::wait_object_assert statefulset "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_STATEFULSET_R2}:"
   575    kube::test::wait_object_assert statefulset "{{range.items}}{{${image_field1:?}}}:{{end}}" "${IMAGE_PAUSE_V2}:"
   576    kube::test::get_object_assert statefulset "{{range.items}}{{${container_len:?}}}{{end}}" "2"
   577    # Get rollout history
   578    output_message=$(kubectl rollout history statefulset)
   579    kube::test::if_has_string "${output_message}" "statefulset.apps/nginx"
   580    kube::test::if_has_string "${output_message}" "REVISION  CHANGE-CAUSE"
   581    kube::test::if_has_string "${output_message}" "3         kubectl apply"
   582    kube::test::if_has_string "${output_message}" "4         kubectl apply"
   583    # Clean up - delete newest configuration
   584    kubectl delete -f hack/testdata/rollingupdate-statefulset-rv2.yaml "${kube_flags[@]:?}"
   585    # Post-condition: no pods from statefulset controller
   586    wait-for-pods-with-label "app=nginx-statefulset" ""
   587  
   588    set +o nounset
   589    set +o errexit
   590  }
   591  
   592  run_stateful_set_tests() {
   593    set -o nounset
   594    set -o errexit
   595  
   596    create_and_use_new_namespace
   597    kube::log::status "Testing kubectl(v1:statefulsets)"
   598  
   599    ### Create and stop statefulset, make sure it doesn't leak pods
   600    # Pre-condition: no statefulset exists
   601    kube::test::get_object_assert statefulset "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   602    # Command: create statefulset
   603    kubectl create -f hack/testdata/rollingupdate-statefulset.yaml "${kube_flags[@]:?}"
   604  
   605    # Describe command should respect the chunk size parameter
   606    kube::test::describe_resource_chunk_size_assert statefulsets pods,events
   607  
   608    ### Scale statefulset test with current-replicas and replicas
   609    # Pre-condition: 0 replicas
   610    kube::test::get_object_assert 'statefulset nginx' "{{${statefulset_replicas_field:?}}}" '0'
   611    kube::test::wait_object_assert 'statefulset nginx' "{{${statefulset_observed_generation:?}}}" '1'
   612    # Command: Scale up
   613    kubectl scale --current-replicas=0 --replicas=1 statefulset nginx "${kube_flags[@]:?}"
   614    # Post-condition: 1 replica, named nginx-0
   615    kube::test::get_object_assert 'statefulset nginx' "{{${statefulset_replicas_field:?}}}" '1'
   616    kube::test::wait_object_assert 'statefulset nginx' "{{${statefulset_observed_generation:?}}}" '2'
   617    # Typically we'd wait and confirm that N>1 replicas are up, but this framework
   618    # doesn't start  the scheduler, so pet-0 will block all others.
   619    # TODO: test robust scaling in an e2e.
   620    wait-for-pods-with-label "app=nginx-statefulset" "nginx-0"
   621  
   622    # Rollout restart should change generation
   623    kubectl rollout restart statefulset nginx "${kube_flags[@]}"
   624    kube::test::get_object_assert 'statefulset nginx' "{{$statefulset_observed_generation}}" '3'
   625  
   626    ### Clean up
   627    kubectl delete -f hack/testdata/rollingupdate-statefulset.yaml "${kube_flags[@]:?}"
   628    # Post-condition: no pods from statefulset controller
   629    wait-for-pods-with-label "app=nginx-statefulset" ""
   630  
   631    set +o nounset
   632    set +o errexit
   633  
   634  }
   635  
   636  run_rs_tests() {
   637    set -o nounset
   638    set -o errexit
   639  
   640    create_and_use_new_namespace
   641    kube::log::status "Testing kubectl(v1:replicasets)"
   642  
   643    ### Create and stop a replica set, make sure it doesn't leak pods
   644    # Pre-condition: no replica set exists
   645    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   646    # Command
   647    kubectl create -f hack/testdata/frontend-replicaset.yaml "${kube_flags[@]:?}"
   648    kube::log::status "Deleting rs"
   649    kubectl delete rs frontend "${kube_flags[@]:?}"
   650    # Post-condition: no pods from frontend replica set
   651    kube::test::wait_object_assert "pods -l tier=frontend" "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   652  
   653    ### Create and then delete a replica set with cascading strategy set to orphan, make sure it doesn't delete pods.
   654    # Pre-condition: no replica set exists
   655    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   656    # Command
   657    kubectl create -f hack/testdata/frontend-replicaset.yaml "${kube_flags[@]}"
   658    # wait for all 3 pods to be set up
   659    kube::test::wait_object_assert "pods -l tier=frontend" "{{range.items}}{{${pod_container_name_field:?}}}:{{end}}" 'php-redis:php-redis:php-redis:'
   660    kube::log::status "Deleting rs"
   661    kubectl delete rs frontend "${kube_flags[@]:?}" --cascade=orphan
   662    # Wait for the rs to be deleted.
   663    kube::test::wait_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   664    # Post-condition: All 3 pods still remain from frontend replica set
   665    kube::test::get_object_assert "pods -l tier=frontend" "{{range.items}}{{$pod_container_name_field}}:{{end}}" 'php-redis:php-redis:php-redis:'
   666    # Cleanup
   667    kubectl delete pods -l "tier=frontend" "${kube_flags[@]:?}"
   668    kube::test::get_object_assert pods "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   669  
   670    ### Create replica set frontend from YAML
   671    # Pre-condition: no replica set exists
   672    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   673    # Command
   674    kubectl create -f hack/testdata/frontend-replicaset.yaml "${kube_flags[@]:?}"
   675    # Post-condition: frontend replica set is created
   676    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" 'frontend:'
   677    # Describe command should print detailed information
   678    kube::test::describe_object_assert rs 'frontend' "Name:" "Pod Template:" "Labels:" "Selector:" "Replicas:" "Pods Status:" "Volumes:"
   679    # Describe command should print events information by default
   680    kube::test::describe_object_events_assert rs 'frontend'
   681    # Describe command should not print events information when show-events=false
   682    kube::test::describe_object_events_assert rs 'frontend' false
   683    # Describe command should print events information when show-events=true
   684    kube::test::describe_object_events_assert rs 'frontend' true
   685    # Describe command (resource only) should print detailed information
   686    kube::test::describe_resource_assert rs "Name:" "Pod Template:" "Labels:" "Selector:" "Replicas:" "Pods Status:" "Volumes:"
   687    # Describe command should print events information by default
   688    kube::test::describe_resource_events_assert rs
   689    # Describe command should not print events information when show-events=false
   690    kube::test::describe_resource_events_assert rs false
   691    # Describe command should print events information when show-events=true
   692    kube::test::describe_resource_events_assert rs true
   693    # Describe command (resource only) should print detailed information
   694    kube::test::describe_resource_assert pods "Name:" "Image:" "Node:" "Labels:" "Status:" "Controlled By"
   695    # Describe command should respect the chunk size parameter
   696    kube::test::describe_resource_chunk_size_assert replicasets pods,events
   697  
   698    ### Scale replica set frontend with current-replicas and replicas
   699    # Pre-condition: 3 replicas
   700    kube::test::get_object_assert 'rs frontend' "{{${rs_replicas_field:?}}}" '3'
   701    # Dry-run Command
   702    kubectl scale --dry-run=client --current-replicas=3 --replicas=2 replicasets frontend "${kube_flags[@]:?}"
   703    kubectl scale --dry-run=server --current-replicas=3 --replicas=2 replicasets frontend "${kube_flags[@]:?}"
   704    kube::test::get_object_assert 'rs frontend' "{{${rs_replicas_field:?}}}" '3'
   705    # Command
   706    kubectl scale --current-replicas=3 --replicas=2 replicasets frontend "${kube_flags[@]:?}"
   707    # Post-condition: 2 replicas
   708    kube::test::get_object_assert 'rs frontend' "{{${rs_replicas_field:?}}}" '2'
   709  
   710    # Set up three deploy, two deploy have same label
   711    kubectl create -f hack/testdata/scale-deploy-1.yaml "${kube_flags[@]:?}"
   712    kubectl create -f hack/testdata/scale-deploy-2.yaml "${kube_flags[@]:?}"
   713    kubectl create -f hack/testdata/scale-deploy-3.yaml "${kube_flags[@]:?}"
   714    kube::test::get_object_assert 'deploy scale-1' "{{.spec.replicas}}" '1'
   715    kube::test::get_object_assert 'deploy scale-2' "{{.spec.replicas}}" '1'
   716    kube::test::get_object_assert 'deploy scale-3' "{{.spec.replicas}}" '1'
   717    # Test kubectl scale --all with dry run
   718    kubectl scale deploy --replicas=3 --all --dry-run=client
   719    kubectl scale deploy --replicas=3 --all --dry-run=server
   720    kube::test::get_object_assert 'deploy scale-1' "{{.spec.replicas}}" '1'
   721    kube::test::get_object_assert 'deploy scale-2' "{{.spec.replicas}}" '1'
   722    kube::test::get_object_assert 'deploy scale-3' "{{.spec.replicas}}" '1'
   723    # Test kubectl scale --selector
   724    kubectl scale deploy --replicas=2 -l run=hello
   725    kube::test::get_object_assert 'deploy scale-1' "{{.spec.replicas}}" '2'
   726    kube::test::get_object_assert 'deploy scale-2' "{{.spec.replicas}}" '2'
   727    kube::test::get_object_assert 'deploy scale-3' "{{.spec.replicas}}" '1'
   728    # Test kubectl scale --all
   729    kubectl scale deploy --replicas=3 --all
   730    kube::test::get_object_assert 'deploy scale-1' "{{.spec.replicas}}" '3'
   731    kube::test::get_object_assert 'deploy scale-2' "{{.spec.replicas}}" '3'
   732    kube::test::get_object_assert 'deploy scale-3' "{{.spec.replicas}}" '3'
   733    # Clean-up
   734    kubectl delete rs frontend "${kube_flags[@]:?}"
   735    kubectl delete deploy scale-1 scale-2 scale-3 "${kube_flags[@]:?}"
   736  
   737    ### Expose replica set as service
   738    kubectl create -f hack/testdata/frontend-replicaset.yaml "${kube_flags[@]:?}"
   739    # Pre-condition: 3 replicas
   740    kube::test::get_object_assert 'rs frontend' "{{${rs_replicas_field:?}}}" '3'
   741    # Command
   742    kubectl expose rs frontend --port=80 "${kube_flags[@]:?}"
   743    # Post-condition: service exists and the port is unnamed
   744    kube::test::get_object_assert 'service frontend' "{{${port_name:?}}} {{${port_field:?}}}" '<no value> 80'
   745    # Cleanup services
   746    kubectl delete service frontend "${kube_flags[@]:?}"
   747  
   748    # Test set commands
   749    # Pre-condition: frontend replica set exists at generation 1
   750    kube::test::get_object_assert 'rs frontend' "{{${generation_field:?}}}" '1'
   751    kubectl set image rs/frontend "${kube_flags[@]:?}" "*=registry.k8s.io/pause:test-cmd"
   752    kube::test::get_object_assert 'rs frontend' "{{${generation_field:?}}}" '2'
   753    kubectl set env rs/frontend "${kube_flags[@]:?}" foo=bar
   754    kube::test::get_object_assert 'rs frontend' "{{${generation_field:?}}}" '3'
   755    kubectl set resources rs/frontend --dry-run=client "${kube_flags[@]:?}" --limits=cpu=200m,memory=512Mi
   756    kubectl set resources rs/frontend --dry-run=server "${kube_flags[@]:?}" --limits=cpu=200m,memory=512Mi
   757    kube::test::get_object_assert 'rs frontend' "{{${generation_field:?}}}" '3'
   758    kubectl set resources rs/frontend "${kube_flags[@]:?}" --limits=cpu=200m,memory=512Mi
   759    kube::test::get_object_assert 'rs frontend' "{{${generation_field:?}}}" '4'
   760    kubectl set serviceaccount rs/frontend --dry-run=client "${kube_flags[@]:?}" serviceaccount1
   761    kubectl set serviceaccount rs/frontend --dry-run=server "${kube_flags[@]:?}" serviceaccount1
   762    kube::test::get_object_assert 'rs frontend' "{{${generation_field:?}}}" '4'
   763    kubectl set serviceaccount rs/frontend "${kube_flags[@]:?}" serviceaccount1
   764    kube::test::get_object_assert 'rs frontend' "{{${generation_field:?}}}" '5'
   765  
   766    # RS has field for kubectl set field manager
   767    output_message=$(kubectl get rs frontend --show-managed-fields -o=jsonpath='{.metadata.managedFields[*].manager}' "${kube_flags[@]:?}" 2>&1)
   768    kube::test::if_has_string "${output_message}" 'kubectl-set'
   769  
   770    ### Delete replica set with id
   771    # Pre-condition: frontend replica set exists
   772    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" 'frontend:'
   773    # Command
   774    kubectl delete rs frontend "${kube_flags[@]:?}"
   775    # Post-condition: no replica set exists
   776    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   777  
   778    ### Create two replica sets
   779    # Pre-condition: no replica set exists
   780    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   781    # Command
   782    kubectl create -f hack/testdata/frontend-replicaset.yaml "${kube_flags[@]:?}"
   783    kubectl create -f hack/testdata/redis-slave-replicaset.yaml "${kube_flags[@]:?}"
   784    # Post-condition: frontend and redis-slave
   785    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" 'frontend:redis-slave:'
   786  
   787    ### Delete multiple replica sets at once
   788    # Pre-condition: frontend and redis-slave
   789    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" 'frontend:redis-slave:'
   790    # Command
   791    kubectl delete rs frontend redis-slave "${kube_flags[@]:?}" # delete multiple replica sets at once
   792    # Post-condition: no replica set exists
   793    kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   794  
   795    if kube::test::if_supports_resource "horizontalpodautoscalers" ; then
   796      ### Auto scale replica set
   797      # Pre-condition: no replica set exists
   798      kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
   799      # Command
   800      kubectl create -f hack/testdata/frontend-replicaset.yaml "${kube_flags[@]:?}"
   801      kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" 'frontend:'
   802      # autoscale 1~2 pods, CPU utilization 70%, replica set specified by file
   803      kubectl autoscale -f hack/testdata/frontend-replicaset.yaml "${kube_flags[@]:?}" --max=2 --cpu-percent=70
   804      kube::test::get_object_assert 'hpa frontend' "{{${hpa_min_field:?}}} {{${hpa_max_field:?}}} {{${hpa_cpu_field:?}}}" '1 2 70'
   805      kubectl delete hpa frontend "${kube_flags[@]:?}"
   806      # autoscale 2~3 pods, no CPU utilization specified, replica set specified by name
   807      kubectl autoscale rs frontend "${kube_flags[@]:?}" --min=2 --max=3
   808      kube::test::get_object_assert 'hpa frontend' "{{${hpa_min_field:?}}} {{${hpa_max_field:?}}} {{${hpa_cpu_field:?}}}" '2 3 80'
   809      # HorizontalPodAutoscaler has field for kubectl autoscale field manager
   810      output_message=$(kubectl get hpa frontend -o=jsonpath='{.metadata.managedFields[*].manager}' "${kube_flags[@]:?}" 2>&1)
   811      kube::test::if_has_string "${output_message}" 'kubectl-autoscale'
   812      # Clean up
   813      kubectl delete hpa frontend "${kube_flags[@]:?}"
   814      # autoscale without specifying --max should fail
   815      ! kubectl autoscale rs frontend "${kube_flags[@]:?}" || exit 1
   816      # Clean up
   817      kubectl delete rs frontend "${kube_flags[@]:?}"
   818    fi
   819  
   820    set +o nounset
   821    set +o errexit
   822  }