k8s.io/kubernetes@v1.29.3/test/cmd/node-management.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  create_test_pods(){
    22    # create test pods we can work with
    23    kubectl create -f - "${kube_flags[@]:?}" << __EOF__
    24  {
    25    "kind": "Pod",
    26    "apiVersion": "v1",
    27    "metadata": {
    28      "name": "test-pod-1",
    29      "labels": {
    30        "e": "f",
    31        "type": "test-pod"
    32      }
    33    },
    34    "spec": {
    35      "nodeName": "127.0.0.1",
    36      "containers": [
    37        {
    38          "name": "container-1",
    39          "resources": {},
    40          "image": "test-image"
    41        }
    42      ]
    43    }
    44  }
    45  __EOF__
    46  
    47    kubectl create -f - "${kube_flags[@]}" << __EOF__
    48  {
    49    "kind": "Pod",
    50    "apiVersion": "v1",
    51    "metadata": {
    52      "name": "test-pod-2",
    53      "labels": {
    54        "c": "d",
    55        "type": "test-pod"
    56      }
    57    },
    58    "spec": {
    59      "nodeName": "127.0.0.1",
    60      "containers": [
    61        {
    62          "name": "container-1",
    63          "resources": {},
    64          "image": "test-image"
    65        }
    66      ]
    67    }
    68  }
    69  __EOF__
    70  }
    71  
    72  delete_test_pods() {
    73    # need to use --force because node is unready
    74    kubectl delete pod/test-pod-1 --force --ignore-not-found
    75    kubectl delete pod/test-pod-2 --force --ignore-not-found
    76  }
    77  
    78  run_cluster_management_tests() {
    79    set -o nounset
    80    set -o errexit
    81  
    82    create_and_use_new_namespace
    83    kube::log::status "Testing cluster-management commands"
    84  
    85    kube::test::get_object_assert nodes "{{range.items}}{{${id_field:?}}}:{{end}}" '127.0.0.1:'
    86  
    87    create_test_pods
    88  
    89    # taint/untaint
    90    # Pre-condition: node doesn't have dedicated=foo:PreferNoSchedule taint
    91    kube::test::get_object_assert "nodes 127.0.0.1" "{{range .spec.taints}}{{if eq .key \"dedicated\"}}{{.key}}={{.value}}:{{.effect}}{{end}}{{end}}" "" # expect no output
    92    # Dry-run
    93    kubectl taint node 127.0.0.1 --dry-run=client dedicated=foo:PreferNoSchedule
    94    kubectl taint node 127.0.0.1 --dry-run=server dedicated=foo:PreferNoSchedule
    95    kube::test::get_object_assert "nodes 127.0.0.1" "{{range .spec.taints}}{{if eq .key \"dedicated\"}}{{.key}}={{.value}}:{{.effect}}{{end}}{{end}}" "" # expect no output
    96    # taint can add a taint (<key>=<value>:<effect>)
    97    kubectl taint node 127.0.0.1 dedicated=foo:PreferNoSchedule
    98    kube::test::get_object_assert "nodes 127.0.0.1" "{{range .spec.taints}}{{if eq .key \"dedicated\"}}{{.key}}={{.value}}:{{.effect}}{{end}}{{end}}" "dedicated=foo:PreferNoSchedule"
    99    # taint can remove a taint
   100    kubectl taint node 127.0.0.1 dedicated-
   101    # taint can add a taint (<key>:<effect>)
   102    kubectl taint node 127.0.0.1 dedicated:PreferNoSchedule
   103    kube::test::get_object_assert "nodes 127.0.0.1" "{{range .spec.taints}}{{if eq .key \"dedicated\"}}{{.key}}={{.value}}:{{.effect}}{{end}}{{end}}" "dedicated=<no value>:PreferNoSchedule"
   104    # Node has field manager for kubectl taint
   105    output_message=$(kubectl get node 127.0.0.1 --show-managed-fields -o=jsonpath='{.metadata.managedFields[*].manager}' "${kube_flags[@]:?}" 2>&1)
   106    kube::test::if_has_string "${output_message}" 'kubectl-taint'
   107    # Dry-run remove a taint
   108    kubectl taint node 127.0.0.1 --dry-run=client dedicated-
   109    kubectl taint node 127.0.0.1 --dry-run=server dedicated-
   110    kube::test::get_object_assert "nodes 127.0.0.1" "{{range .spec.taints}}{{if eq .key \"dedicated\"}}{{.key}}={{.value}}:{{.effect}}{{end}}{{end}}" "dedicated=<no value>:PreferNoSchedule"
   111    # taint can remove a taint
   112    kubectl taint node 127.0.0.1 dedicated-
   113    # Post-condition: node doesn't have dedicated=foo:PreferNoSchedule taint
   114    kube::test::get_object_assert "nodes 127.0.0.1" "{{range .spec.taints}}{{if eq .key \"dedicated\"}}{{.key}}={{.value}}:{{.effect}}{{end}}{{end}}" "" # expect no output
   115  
   116    ### kubectl cordon update with --dry-run does not mark node unschedulable
   117    # Pre-condition: node is schedulable
   118    kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   119    kubectl cordon "127.0.0.1" --dry-run=client
   120    kubectl cordon "127.0.0.1" --dry-run=server
   121    kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   122  
   123    ### kubectl drain update with --dry-run does not mark node unschedulable
   124    # Pre-condition: node is schedulable
   125    kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   126    kubectl drain "127.0.0.1" --dry-run=client --force
   127    kubectl drain "127.0.0.1" --dry-run=server --force
   128    # Post-condition: node still exists, node is still schedulable
   129    kube::test::get_object_assert nodes "{{range.items}}{{$id_field}}:{{end}}" '127.0.0.1:'
   130    kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   131  
   132    ### kubectl drain with --pod-selector only evicts pods that match the given selector
   133    # Pre-condition: node is schedulable
   134    kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   135    # Pre-condition: test-pod-1 and test-pod-2 exist
   136    kube::test::get_object_assert "pods" "{{range .items}}{{.metadata.name}},{{end}}" 'test-pod-1,test-pod-2,'
   137    # dry-run command
   138    kubectl drain "127.0.0.1" --pod-selector 'e in (f)' --dry-run=client --force
   139    kubectl drain "127.0.0.1" --pod-selector 'e in (f)' --dry-run=server --force
   140    kube::test::get_object_assert "pods" "{{range .items}}{{.metadata.name}},{{end}}" 'test-pod-1,test-pod-2,'
   141    # command - need --force because pod is unmanaged and --skip-wait-for-delete-timeout because node is unready
   142    response=$(kubectl drain "127.0.0.1" --force --pod-selector 'e in (f)' --skip-wait-for-delete-timeout=1)
   143    kube::test::if_has_string "${response}" "evicting pod .*/test-pod-1"
   144    # only "test-pod-1" should have been matched and deleted - test-pod-2 should not have a deletion timestamp
   145    kube::test::get_object_assert "pods/test-pod-2" "{{.metadata.deletionTimestamp}}" '<no value>'
   146    # Post-condition: recreate test pods -- they have deletionTimestamp set but will not go away because node is unready
   147    delete_test_pods
   148    create_test_pods
   149    # Post-condition: node is schedulable
   150    kubectl uncordon "127.0.0.1"
   151    kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   152  
   153    ### kubectl uncordon update with --dry-run is a no-op
   154    # Pre-condition: node is already schedulable
   155    kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   156    response=$(kubectl uncordon "127.0.0.1" --dry-run=client)
   157    kube::test::if_has_string "${response}" 'already uncordoned'
   158    response=$(kubectl uncordon "127.0.0.1" --dry-run=server)
   159    kube::test::if_has_string "${response}" 'already uncordoned'
   160    # Post-condition: node is still schedulable
   161    kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   162  
   163    ### kubectl drain command fails when both --selector and a node argument are given
   164    # Pre-condition: node exists and contains label test=label
   165    kubectl label node "127.0.0.1" "test=label"
   166    kube::test::get_object_assert "nodes 127.0.0.1" '{{.metadata.labels.test}}' 'label'
   167    response=$(! kubectl drain "127.0.0.1" --selector test=label 2>&1)
   168    kube::test::if_has_string "${response}" 'cannot specify both a node name'
   169  
   170     ### Test kubectl drain chunk size
   171     # Pre-condition: node exists and contains label test=label
   172     kube::test::get_object_assert "nodes 127.0.0.1" '{{.metadata.labels.test}}' 'label'
   173     # Pre-condition: node is schedulable
   174     kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   175     # Pre-condition: test-pod-1 and test-pod-2 exist
   176     kube::test::get_object_assert "pods" "{{range .items}}{{.metadata.name}},{{end}}" 'test-pod-1,test-pod-2,'
   177     # command - need to use force because pods are unmanaged, dry run (or skip-wait) because node is unready
   178     output_message=$(kubectl --v=6 drain --force --pod-selector type=test-pod --selector test=label --chunk-size=1 --dry-run=client 2>&1 "${kube_flags[@]}")
   179     # Post-condition: Check if we get a limit on node, and both limit and continue on pods
   180     kube::test::if_has_string "${output_message}" "/v1/nodes?labelSelector=test%3Dlabel&limit=1 200 OK"
   181     kube::test::if_has_string "${output_message}" "/v1/pods?fieldSelector=spec.nodeName%3D127.0.0.1&labelSelector=type%3Dtest-pod&limit=1 200 OK"
   182     kube::test::if_has_string "${output_message}" "/v1/pods?continue=.*&fieldSelector=spec.nodeName%3D127.0.0.1&labelSelector=type%3Dtest-pod&limit=1 200 OK"
   183     # Post-condition: Check we evict multiple pages worth of pods
   184     kube::test::if_has_string "${output_message}" "evicting pod .*/test-pod-1"
   185     kube::test::if_has_string "${output_message}" "evicting pod .*/test-pod-2"
   186     # Post-condition: node is schedulable
   187     kubectl uncordon "127.0.0.1"
   188     kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" '<no value>'
   189  
   190     ### Test kubectl drain chunk size defaults to 500
   191     output_message=$(kubectl --v=6 drain --force --selector test=label --dry-run=client 2>&1 "${kube_flags[@]}")
   192     # Post-condition: Check if we get a limit
   193     kube::test::if_has_string "${output_message}" "/v1/nodes?labelSelector=test%3Dlabel&limit=500 200 OK"
   194     kube::test::if_has_string "${output_message}" "/v1/pods?fieldSelector=spec.nodeName%3D127.0.0.1&limit=500 200 OK"
   195  
   196    ### kubectl cordon command fails when no arguments are passed
   197    # Pre-condition: node exists
   198    response=$(! kubectl cordon 2>&1)
   199    kube::test::if_has_string "${response}" 'error\: USAGE\: cordon NODE'
   200  
   201    ### kubectl cordon selects no nodes with an empty --selector=
   202    # Pre-condition: node "127.0.0.1" is uncordoned
   203    kubectl uncordon "127.0.0.1"
   204    response=$(! kubectl cordon --selector= 2>&1)
   205    kube::test::if_has_string "${response}" 'must provide one or more resources'
   206    # test=label matches our node
   207    response=$(kubectl cordon --selector test=label)
   208    kube::test::if_has_string "${response}" 'node/127.0.0.1 cordoned'
   209    # invalid=label does not match any nodes
   210    response=$(kubectl cordon --selector invalid=label)
   211    kube::test::if_has_not_string "${response}" 'cordoned'
   212    # Post-condition: node "127.0.0.1" is cordoned
   213    kube::test::get_object_assert "nodes 127.0.0.1" "{{.spec.unschedulable}}" 'true'
   214  
   215    # Clean up test pods
   216    delete_test_pods
   217  
   218    set +o nounset
   219    set +o errexit
   220  }