k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/cmd/generic-resources.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_multi_resources_tests() {
    22    set -o nounset
    23    set -o errexit
    24  
    25    create_and_use_new_namespace
    26    kube::log::status "Testing kubectl(v1:multiple resources)"
    27  
    28    FILES="hack/testdata/multi-resource-yaml
    29    hack/testdata/multi-resource-list
    30    hack/testdata/multi-resource-json
    31    hack/testdata/multi-resource-rclist
    32    hack/testdata/multi-resource-svclist"
    33    YAML=".yaml"
    34    JSON=".json"
    35    for file in $FILES; do
    36      if [ -f "${file}${YAML}" ]
    37      then
    38        file=${file}${YAML}
    39        replace_file="${file%.yaml}-modify.yaml"
    40      else
    41        file=${file}${JSON}
    42        replace_file="${file%.json}-modify.json"
    43      fi
    44  
    45      has_svc=true
    46      has_rc=true
    47      two_rcs=false
    48      two_svcs=false
    49      if [[ "${file}" == *rclist* ]]; then
    50        has_svc=false
    51        two_rcs=true
    52      fi
    53      if [[ "${file}" == *svclist* ]]; then
    54        has_rc=false
    55        two_svcs=true
    56      fi
    57  
    58      ### Create, get, describe, replace, label, annotate, and then delete service nginxsvc and replication controller my-nginx from 5 types of files:
    59      ### 1) YAML, separated by ---; 2) JSON, with a List type; 3) JSON, with JSON object concatenation
    60      ### 4) JSON, with a ReplicationControllerList type; 5) JSON, with a ServiceList type
    61      echo "Testing with file ${file} and replace with file ${replace_file}"
    62      # Pre-condition: no service (other than default kubernetes services) or replication controller exists
    63      kube::test::get_object_assert services "{{range.items}}{{${id_field:?}}}:{{end}}" ''
    64      kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" ''
    65      # Command
    66      kubectl create -f "${file}" "${kube_flags[@]:?}"
    67      # Post-condition: mock service (and mock2) exists
    68      if [ "$has_svc" = true ]; then
    69        if [ "$two_svcs" = true ]; then
    70          kube::test::get_object_assert services "{{range.items}}{{$id_field}}:{{end}}" 'mock:mock2:'
    71        else
    72          kube::test::get_object_assert services "{{range.items}}{{$id_field}}:{{end}}" 'mock:'
    73        fi
    74      fi
    75      # Post-condition: mock rc (and mock2) exists
    76      if [ "$has_rc" = true ]; then
    77        if [ "$two_rcs" = true ]; then
    78          kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" 'mock:mock2:'
    79        else
    80          kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" 'mock:'
    81        fi
    82      fi
    83      # Command
    84      kubectl get -f "${file}" "${kube_flags[@]}"
    85      # Command: watching multiple resources should return "not supported" error
    86      WATCH_ERROR_FILE="${KUBE_TEMP}/kubectl-watch-error"
    87      kubectl get -f "${file}" "${kube_flags[@]}" "--watch" 2> "${WATCH_ERROR_FILE}" || true
    88      if ! grep -q "watch is only supported on individual resources and resource collections" "${WATCH_ERROR_FILE}"; then
    89        kube::log::error_exit "kubectl watch multiple resource returns unexpected error or non-error: $(cat "${WATCH_ERROR_FILE}")" "1"
    90      fi
    91      kubectl describe -f "${file}" "${kube_flags[@]}"
    92      # Command
    93      kubectl replace -f "${replace_file}" --force --cascade=background "${kube_flags[@]}"
    94      # Post-condition: mock service (and mock2) and mock rc (and mock2) are replaced
    95      if [ "$has_svc" = true ]; then
    96        kube::test::get_object_assert 'services mock' "{{${labels_field:?}.status}}" 'replaced'
    97        if [ "$two_svcs" = true ]; then
    98          kube::test::get_object_assert 'services mock2' "{{${labels_field}.status}}" 'replaced'
    99        fi
   100      fi
   101      if [ "$has_rc" = true ]; then
   102        kube::test::get_object_assert 'rc mock' "{{${labels_field}.status}}" 'replaced'
   103        if [ "$two_rcs" = true ]; then
   104          kube::test::get_object_assert 'rc mock2' "{{${labels_field}.status}}" 'replaced'
   105        fi
   106      fi
   107      # Command: kubectl edit multiple resources
   108      temp_editor="${KUBE_TEMP}/tmp-editor.sh"
   109      echo -e "#!/usr/bin/env bash\n${SED} -i \"s/status\:\ replaced/status\:\ edited/g\" \$@" > "${temp_editor}"
   110      chmod +x "${temp_editor}"
   111      EDITOR="${temp_editor}" kubectl edit "${kube_flags[@]}" -f "${file}"
   112      # Post-condition: mock service (and mock2) and mock rc (and mock2) are edited
   113      if [ "$has_svc" = true ]; then
   114        kube::test::get_object_assert 'services mock' "{{${labels_field}.status}}" 'edited'
   115        if [ "$two_svcs" = true ]; then
   116          kube::test::get_object_assert 'services mock2' "{{${labels_field}.status}}" 'edited'
   117        fi
   118      fi
   119      if [ "$has_rc" = true ]; then
   120        kube::test::get_object_assert 'rc mock' "{{${labels_field}.status}}" 'edited'
   121        if [ "$two_rcs" = true ]; then
   122          kube::test::get_object_assert 'rc mock2' "{{${labels_field}.status}}" 'edited'
   123        fi
   124      fi
   125      # cleaning
   126      rm "${temp_editor}"
   127      # Command
   128      # We need to set --overwrite, because otherwise, if the first attempt to run "kubectl label"
   129      # fails on some, but not all, of the resources, retries will fail because it tries to modify
   130      # existing labels.
   131      kubectl-with-retry label -f "${file}" labeled=true --overwrite "${kube_flags[@]}"
   132      # Post-condition: mock service and mock rc (and mock2) are labeled
   133      if [ "$has_svc" = true ]; then
   134        kube::test::get_object_assert 'services mock' "{{${labels_field}.labeled}}" 'true'
   135        if [ "$two_svcs" = true ]; then
   136          kube::test::get_object_assert 'services mock2' "{{${labels_field}.labeled}}" 'true'
   137        fi
   138      fi
   139      if [ "$has_rc" = true ]; then
   140        kube::test::get_object_assert 'rc mock' "{{${labels_field}.labeled}}" 'true'
   141        if [ "$two_rcs" = true ]; then
   142          kube::test::get_object_assert 'rc mock2' "{{${labels_field}.labeled}}" 'true'
   143        fi
   144      fi
   145      # Command
   146      # Command
   147      # We need to set --overwrite, because otherwise, if the first attempt to run "kubectl annotate"
   148      # fails on some, but not all, of the resources, retries will fail because it tries to modify
   149      # existing annotations.
   150      kubectl-with-retry annotate -f "${file}" annotated=true --overwrite "${kube_flags[@]}"
   151      # Post-condition: mock service (and mock2) and mock rc (and mock2) are annotated
   152      if [ "$has_svc" = true ]; then
   153        kube::test::get_object_assert 'services mock' "{{${annotations_field:?}.annotated}}" 'true'
   154        if [ "$two_svcs" = true ]; then
   155          kube::test::get_object_assert 'services mock2' "{{${annotations_field}.annotated}}" 'true'
   156        fi
   157      fi
   158      if [ "$has_rc" = true ]; then
   159        kube::test::get_object_assert 'rc mock' "{{${annotations_field}.annotated}}" 'true'
   160        if [ "$two_rcs" = true ]; then
   161          kube::test::get_object_assert 'rc mock2' "{{${annotations_field}.annotated}}" 'true'
   162        fi
   163      fi
   164      # Cleanup resources created
   165      kubectl delete -f "${file}" "${kube_flags[@]}"
   166    done
   167  
   168    #############################
   169    # Multiple Resources via URL#
   170    #############################
   171  
   172    # Pre-condition: no service (other than default kubernetes services) or replication controller exists
   173    kube::test::get_object_assert services "{{range.items}}{{$id_field}}:{{end}}" ''
   174    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" ''
   175  
   176    # Command
   177    kubectl create -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/hack/testdata/multi-resource-yaml.yaml "${kube_flags[@]}"
   178  
   179    # Post-condition: service(mock) and rc(mock) exist
   180    kube::test::get_object_assert services "{{range.items}}{{$id_field}}:{{end}}" 'mock:'
   181    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" 'mock:'
   182  
   183    # Clean up
   184    kubectl delete -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/hack/testdata/multi-resource-yaml.yaml "${kube_flags[@]}"
   185  
   186    # Post-condition: no service (other than default kubernetes services) or replication controller exists
   187    kube::test::get_object_assert services "{{range.items}}{{$id_field}}:{{end}}" ''
   188    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" ''
   189  
   190    set +o nounset
   191    set +o errexit
   192  }
   193  
   194  run_recursive_resources_tests() {
   195    set -o nounset
   196    set -o errexit
   197  
   198    kube::log::status "Testing recursive resources"
   199    ### Create multiple busybox PODs recursively from directory of YAML files
   200    # Pre-condition: no POD exists
   201    create_and_use_new_namespace
   202    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" ''
   203    # Command
   204    output_message=$(! kubectl create -f hack/testdata/recursive/pod --recursive 2>&1 "${kube_flags[@]}")
   205    # Post-condition: busybox0 & busybox1 PODs are created, and since busybox2 is malformed, it should error
   206    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   207    kube::test::if_has_string "${output_message}" 'error validating data: kind not set'
   208  
   209    ## Edit multiple busybox PODs by updating the image field of multiple PODs recursively from a directory. tmp-editor.sh is a fake editor
   210    # Pre-condition: busybox0 & busybox1 PODs exist
   211    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   212    # Command
   213    # shellcheck disable=SC2016  # $1 here is not a Expressions
   214    echo -e '#!/usr/bin/env bash\nsed -i "s/image: busybox/image: prom\/busybox/g" $1' > /tmp/tmp-editor.sh
   215    chmod +x /tmp/tmp-editor.sh
   216    output_message=$(! EDITOR=/tmp/tmp-editor.sh kubectl edit -f hack/testdata/recursive/pod --recursive 2>&1 "${kube_flags[@]}")
   217    # Post-condition: busybox0 & busybox1 PODs are not edited, and since busybox2 is malformed, it should error
   218    # The reason why busybox0 & busybox1 PODs are not edited is because the editor tries to load all objects in
   219    # a list but since it contains invalid objects, it will never open.
   220    kube::test::get_object_assert pods "{{range.items}}{{${image_field:?}}}:{{end}}" 'busybox:busybox:'
   221    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   222    # cleaning
   223    rm /tmp/tmp-editor.sh
   224  
   225    ## Replace multiple busybox PODs recursively from directory of YAML files
   226    # Pre-condition: busybox0 & busybox1 PODs exist
   227    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   228    # Command
   229    output_message=$(! kubectl replace -f hack/testdata/recursive/pod-modify --recursive 2>&1 "${kube_flags[@]}")
   230    # Post-condition: busybox0 & busybox1 PODs are replaced, and since busybox2 is malformed, it should error
   231    kube::test::get_object_assert pods "{{range.items}}{{${labels_field}.status}}:{{end}}" 'replaced:replaced:'
   232    kube::test::if_has_string "${output_message}" 'error validating data: kind not set'
   233  
   234    ## Describe multiple busybox PODs recursively from directory of YAML files
   235    # Pre-condition: busybox0 & busybox1 PODs exist
   236    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   237    # Command
   238    output_message=$(! kubectl describe -f hack/testdata/recursive/pod --recursive 2>&1 "${kube_flags[@]}")
   239    # Post-condition: busybox0 & busybox1 PODs are described, and since busybox2 is malformed, it should error
   240    kube::test::if_has_string "${output_message}" "app=busybox0"
   241    kube::test::if_has_string "${output_message}" "app=busybox1"
   242    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   243  
   244    ## Annotate multiple busybox PODs recursively from directory of YAML files
   245    # Pre-condition: busybox0 & busybox1 PODs exist
   246    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   247    # Command
   248    output_message=$(! kubectl annotate -f hack/testdata/recursive/pod annotatekey='annotatevalue' --recursive 2>&1 "${kube_flags[@]}")
   249    # Post-condition: busybox0 & busybox1 PODs are annotated, and since busybox2 is malformed, it should error
   250    kube::test::get_object_assert pods "{{range.items}}{{${annotations_field}.annotatekey}}:{{end}}" 'annotatevalue:annotatevalue:'
   251    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   252  
   253    ## Apply multiple busybox PODs recursively from directory of YAML files
   254    # Pre-condition: busybox0 & busybox1 PODs exist
   255    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   256    # Command
   257    output_message=$(! kubectl apply -f hack/testdata/recursive/pod-modify --recursive 2>&1 "${kube_flags[@]}")
   258    # Post-condition: busybox0 & busybox1 PODs are updated, and since busybox2 is malformed, it should error
   259    kube::test::get_object_assert pods "{{range.items}}{{${labels_field}.status}}:{{end}}" 'replaced:replaced:'
   260    kube::test::if_has_string "${output_message}" 'error validating data: kind not set'
   261  
   262    ## Get multiple busybox PODs recursively from directory of YAML files
   263    # Pre-condition: busybox0 & busybox1 PODs exist
   264    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   265    # Command
   266    output_message=$(! kubectl get -f hack/testdata/recursive/pod --recursive 2>&1 "${kube_flags[@]}" -o go-template="{{range.items}}{{$id_field}}:{{end}}")
   267    # Post-condition: busybox0 & busybox1 PODs are retrieved, but because busybox2 is malformed, it should not show up
   268    kube::test::if_has_string "${output_message}" "busybox0:busybox1:"
   269    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   270  
   271    ## Label multiple busybox PODs recursively from directory of YAML files
   272    # Pre-condition: busybox0 & busybox1 PODs exist
   273    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   274    # Command
   275    output_message=$(! kubectl label -f hack/testdata/recursive/pod mylabel='myvalue' --recursive 2>&1 "${kube_flags[@]}")
   276    echo "${output_message}"
   277    # Post-condition: busybox0 & busybox1 PODs are labeled, but because busybox2 is malformed, it should not show up
   278    kube::test::get_object_assert pods "{{range.items}}{{${labels_field}.mylabel}}:{{end}}" 'myvalue:myvalue:'
   279    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   280  
   281    ## Patch multiple busybox PODs recursively from directory of YAML files
   282    # Pre-condition: busybox0 & busybox1 PODs exist
   283    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   284    # Command
   285    output_message=$(! kubectl patch -f hack/testdata/recursive/pod -p='{"spec":{"containers":[{"name":"busybox","image":"prom/busybox"}]}}' --recursive 2>&1 "${kube_flags[@]}")
   286    echo "${output_message}"
   287    # Post-condition: busybox0 & busybox1 PODs are patched, but because busybox2 is malformed, it should not show up
   288    kube::test::get_object_assert pods "{{range.items}}{{$image_field}}:{{end}}" 'prom/busybox:prom/busybox:'
   289    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   290  
   291    ### Delete multiple busybox PODs recursively from directory of YAML files
   292    # Pre-condition: busybox0 & busybox1 PODs exist
   293    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   294    # Command
   295    output_message=$(! kubectl delete -f hack/testdata/recursive/pod --recursive --grace-period=0 --force 2>&1 "${kube_flags[@]}")
   296    # Post-condition: busybox0 & busybox1 PODs are deleted, and since busybox2 is malformed, it should error
   297    kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" ''
   298    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   299  
   300    ### Create replication controller recursively from directory of YAML files
   301    # Pre-condition: no replication controller exists
   302    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" ''
   303    # Command
   304    ! kubectl create -f hack/testdata/recursive/rc --recursive "${kube_flags[@]}" || exit 1
   305    # Post-condition: frontend replication controller is created
   306    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   307  
   308    ### Autoscale multiple replication controllers recursively from directory of YAML files
   309    # Pre-condition: busybox0 & busybox1 replication controllers exist & 1
   310    # replica each
   311    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   312    kube::test::get_object_assert 'rc busybox0' "{{${rc_replicas_field:?}}}" '1'
   313    kube::test::get_object_assert 'rc busybox1' "{{$rc_replicas_field}}" '1'
   314    # Command
   315    output_message=$(! kubectl autoscale --min=1 --max=2 -f hack/testdata/recursive/rc --recursive 2>&1 "${kube_flags[@]}")
   316    # Post-condition: busybox0 & busybox replication controllers are autoscaled
   317    # with min. of 1 replica & max of 2 replicas, and since busybox2 is malformed, it should error
   318    kube::test::get_object_assert 'hpa busybox0' "{{${hpa_min_field:?}}} {{${hpa_max_field:?}}} {{${hpa_cpu_field:?}}}" '1 2 80'
   319    kube::test::get_object_assert 'hpa busybox1' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '1 2 80'
   320    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   321    kubectl delete hpa busybox0 "${kube_flags[@]}"
   322    kubectl delete hpa busybox1 "${kube_flags[@]}"
   323  
   324    ### Expose multiple replication controllers as service recursively from directory of YAML files
   325    # Pre-condition: busybox0 & busybox1 replication controllers exist & 1
   326    # replica each
   327    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   328    kube::test::get_object_assert 'rc busybox0' "{{$rc_replicas_field}}" '1'
   329    kube::test::get_object_assert 'rc busybox1' "{{$rc_replicas_field}}" '1'
   330    # Command
   331    output_message=$(! kubectl expose -f hack/testdata/recursive/rc --recursive --port=80 2>&1 "${kube_flags[@]}")
   332    # Post-condition: service exists and the port is unnamed
   333    kube::test::get_object_assert 'service busybox0' "{{${port_name:?}}} {{${port_field:?}}}" '<no value> 80'
   334    kube::test::get_object_assert 'service busybox1' "{{$port_name}} {{$port_field}}" '<no value> 80'
   335    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   336  
   337    ### Scale multiple replication controllers recursively from directory of YAML files
   338    # Pre-condition: busybox0 & busybox1 replication controllers exist & 1
   339    # replica each
   340    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   341    kube::test::get_object_assert 'rc busybox0' "{{$rc_replicas_field}}" '1'
   342    kube::test::get_object_assert 'rc busybox1' "{{$rc_replicas_field}}" '1'
   343    # Command
   344    output_message=$(! kubectl scale --current-replicas=1 --replicas=2 -f hack/testdata/recursive/rc --recursive 2>&1 "${kube_flags[@]}")
   345    # Post-condition: busybox0 & busybox1 replication controllers are scaled to 2 replicas, and since busybox2 is malformed, it should error
   346    kube::test::get_object_assert 'rc busybox0' "{{$rc_replicas_field}}" '2'
   347    kube::test::get_object_assert 'rc busybox1' "{{$rc_replicas_field}}" '2'
   348    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   349  
   350    ### Delete multiple busybox replication controllers recursively from directory of YAML files
   351    # Pre-condition: busybox0 & busybox1 PODs exist
   352    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   353    # Command
   354    output_message=$(! kubectl delete -f hack/testdata/recursive/rc --recursive --grace-period=0 --force 2>&1 "${kube_flags[@]}")
   355    # Post-condition: busybox0 & busybox1 replication controllers are deleted, and since busybox2 is malformed, it should error
   356    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" ''
   357    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   358  
   359    ### Rollout on multiple deployments recursively
   360    # Pre-condition: no deployments exist
   361    kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" ''
   362    # Command
   363    # Create deployments (revision 1) recursively from directory of YAML files
   364    ! kubectl create -f hack/testdata/recursive/deployment --recursive "${kube_flags[@]}" || exit 1
   365    kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx0-deployment:nginx1-deployment:'
   366    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_NGINX}:${IMAGE_NGINX}:"
   367    ## Rollback the deployments to revision 1 recursively
   368    output_message=$(! kubectl rollout undo -f hack/testdata/recursive/deployment --recursive --to-revision=1 2>&1 "${kube_flags[@]}")
   369    # Post-condition: nginx0 & nginx1 should be a no-op, and since nginx2 is malformed, it should error
   370    kube::test::get_object_assert deployment "{{range.items}}{{${image_field0:?}}}:{{end}}" "${IMAGE_NGINX}:${IMAGE_NGINX}:"
   371    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   372    ## Pause the deployments recursively
   373    # shellcheck disable=SC2034  # PRESERVE_ERR_FILE is used in kubectl-with-retry
   374    PRESERVE_ERR_FILE=true
   375    kubectl-with-retry rollout pause -f hack/testdata/recursive/deployment --recursive "${kube_flags[@]}"
   376    output_message=$(cat "${ERROR_FILE}")
   377    # Post-condition: nginx0 & nginx1 should both have paused set to true, and since nginx2 is malformed, it should error
   378    kube::test::get_object_assert deployment "{{range.items}}{{.spec.paused}}:{{end}}" "true:true:"
   379    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   380    ## Resume the deployments recursively
   381    kubectl-with-retry rollout resume -f hack/testdata/recursive/deployment --recursive "${kube_flags[@]}"
   382    output_message=$(cat "${ERROR_FILE}")
   383    # Post-condition: nginx0 & nginx1 should both have paused set to nothing, and since nginx2 is malformed, it should error
   384    kube::test::get_object_assert deployment "{{range.items}}{{.spec.paused}}:{{end}}" "<no value>:<no value>:"
   385    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   386    ## Fetch rollout status for multiple resources
   387    output_message=$(! kubectl rollout status -f hack/testdata/recursive/deployment/deployment --timeout=1s 2>&1 "${kube_flags[@]:?}")
   388    # Post-condition: nginx1 should both exist and nginx2 should error
   389    kube::test::if_has_string "${output_message}" "Waiting for deployment \"nginx1-deployment\" rollout to finish"
   390    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   391    ## Fetch rollout status for deployments recursively
   392    output_message=$(! kubectl rollout status -f hack/testdata/recursive/deployment -R --timeout=1s 2>&1 "${kube_flags[@]:?}")
   393    # Post-condition: nginx0 & nginx1 should both exist, nginx2 should error
   394    kube::test::if_has_string "${output_message}" "Waiting for deployment \"nginx0-deployment\" rollout to finish"
   395    kube::test::if_has_string "${output_message}" "Waiting for deployment \"nginx1-deployment\" rollout to finish"
   396    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   397    ## Retrieve the rollout history of the deployments recursively
   398    output_message=$(! kubectl rollout history -f hack/testdata/recursive/deployment --recursive 2>&1 "${kube_flags[@]}")
   399    # Post-condition: nginx0 & nginx1 should both have a history, and since nginx2 is malformed, it should error
   400    kube::test::if_has_string "${output_message}" "nginx0-deployment"
   401    kube::test::if_has_string "${output_message}" "nginx1-deployment"
   402    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   403    # Clean up
   404    unset PRESERVE_ERR_FILE
   405    rm "${ERROR_FILE}"
   406    ! kubectl delete -f hack/testdata/recursive/deployment --recursive "${kube_flags[@]}" --grace-period=0 --force || exit 1
   407    sleep 1
   408  
   409    ### Rollout on multiple replication controllers recursively - these tests ensure that rollouts cannot be performed on resources that don't support it
   410    # Pre-condition: no replication controller exists
   411    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" ''
   412    # Command
   413    # Create replication controllers recursively from directory of YAML files
   414    ! kubectl create -f hack/testdata/recursive/rc --recursive "${kube_flags[@]}" || exit 1
   415    kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" 'busybox0:busybox1:'
   416    # Command
   417    ## Attempt to rollback the replication controllers to revision 1 recursively
   418    output_message=$(! kubectl rollout undo -f hack/testdata/recursive/rc --recursive --to-revision=1 2>&1 "${kube_flags[@]}")
   419    # Post-condition: busybox0 & busybox1 should error as they are RC's, and since busybox2 is malformed, it should error
   420    kube::test::if_has_string "${output_message}" 'no rollbacker has been implemented for "ReplicationController"'
   421    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   422    ## Attempt to pause the replication controllers recursively
   423    output_message=$(! kubectl rollout pause -f hack/testdata/recursive/rc --recursive 2>&1 "${kube_flags[@]}")
   424    # Post-condition: busybox0 & busybox1 should error as they are RC's, and since busybox2 is malformed, it should error
   425    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   426    kube::test::if_has_string "${output_message}" 'replicationcontrollers "busybox0" pausing is not supported'
   427    kube::test::if_has_string "${output_message}" 'replicationcontrollers "busybox1" pausing is not supported'
   428    ## Attempt to resume the replication controllers recursively
   429    output_message=$(! kubectl rollout resume -f hack/testdata/recursive/rc --recursive 2>&1 "${kube_flags[@]}")
   430    # Post-condition: busybox0 & busybox1 should error as they are RC's, and since busybox2 is malformed, it should error
   431    kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
   432    kube::test::if_has_string "${output_message}" 'replicationcontrollers "busybox0" resuming is not supported'
   433    kube::test::if_has_string "${output_message}" 'replicationcontrollers "busybox1" resuming is not supported'
   434    # Clean up
   435    ! kubectl delete -f hack/testdata/recursive/rc --recursive "${kube_flags[@]}" --grace-period=0 --force || exit 1
   436    sleep 1
   437  
   438    set +o nounset
   439    set +o errexit
   440  }
   441  
   442  run_lists_tests() {
   443    set -o nounset
   444    set -o errexit
   445  
   446    create_and_use_new_namespace
   447    kube::log::status "Testing kubectl(v1:lists)"
   448  
   449    ### Create a List with objects from multiple versions
   450    # Command
   451    kubectl create -f hack/testdata/list.yaml "${kube_flags[@]}"
   452  
   453    ### Delete the List with objects from multiple versions
   454    # Command
   455    kubectl delete service/list-service-test deployment/list-deployment-test
   456  
   457    set +o nounset
   458    set +o errexit
   459  }