k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/experiment/kind-detect-local-e2e.sh (about) 1 #!/bin/sh 2 # Copyright 2018 The Kubernetes Authors. 3 # 4 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # you may not use this file except in compliance with the License. 6 # You may obtain a copy of the License at 7 # 8 # http://www.apache.org/licenses/LICENSE-2.0 9 # 10 # Unless required by applicable law or agreed to in writing, software 11 # distributed under the License is distributed on an "AS IS" BASIS, 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 # See the License for the specific language governing permissions and 14 # limitations under the License. 15 16 # hack script for running a kind e2e 17 # must be run with a kubernetes checkout in $PWD (IE from the checkout) 18 # Usage: SKIP="ginkgo skip regex" FOCUS="ginkgo focus regex" kind-e2e.sh 19 20 set -o errexit -o nounset -o xtrace 21 22 # Settings: 23 # SKIP: ginkgo skip regex 24 # FOCUS: ginkgo focus regex 25 # GA_ONLY: true - limit to GA APIs/features as much as possible 26 # false - (default) APIs and features left at defaults 27 # 28 29 # cleanup logic for cleanup on exit 30 CLEANED_UP=false 31 cleanup() { 32 if [ "$CLEANED_UP" = "true" ]; then 33 return 34 fi 35 # KIND_CREATE_ATTEMPTED is true once we: kind create 36 if [ "${KIND_CREATE_ATTEMPTED:-}" = true ]; then 37 kind "export" logs "${ARTIFACTS}/logs" || true 38 kind delete cluster || true 39 fi 40 rm -f _output/bin/e2e.test || true 41 # remove our tempdir, this needs to be last, or it will prevent kind delete 42 if [ -n "${TMP_DIR:-}" ]; then 43 rm -rf "${TMP_DIR:?}" 44 fi 45 CLEANED_UP=true 46 } 47 48 # setup signal handlers 49 signal_handler() { 50 if [ -n "${GINKGO_PID:-}" ]; then 51 kill -TERM "$GINKGO_PID" || true 52 fi 53 cleanup 54 } 55 trap signal_handler INT TERM 56 57 # build kubernetes / node image, e2e binaries and ginkgo 58 build() { 59 # build the node image w/ kubernetes 60 kind build node-image -v 1 61 # Ginkgo v1 is used by Kubernetes 1.24 and earlier and exists in the vendor directory. 62 # Historically it has been built with the "vendor" prefix. 63 GINKGO_TARGET="vendor/github.com/onsi/ginkgo/ginkgo" 64 if [ ! -d "$GINKGO_TARGET" ]; then 65 # If the directory doesn't exist, then we must be on Kubernetes >= 1.25 with Ginkgo V2. 66 # The "vendor" prefix is no longer needed. 67 GINKGO_TARGET="github.com/onsi/ginkgo/v2/ginkgo" 68 fi 69 # make sure we have e2e requirements 70 make all WHAT="cmd/kubectl test/e2e/e2e.test ${GINKGO_TARGET}" 71 } 72 73 check_structured_log_support() { 74 case "${KUBE_VERSION}" in 75 v1.1[0-8].*) 76 echo "$1 is only supported on versions >= v1.19, got ${KUBE_VERSION}" 77 exit 1 78 ;; 79 esac 80 } 81 82 # up a cluster with kind 83 create_cluster() { 84 # Grab the version of the cluster we're about to start 85 KUBE_VERSION="$(docker run --rm --entrypoint=cat "kindest/node:latest" /kind/version)" 86 87 # Default Log level for all components in test clusters 88 KIND_CLUSTER_LOG_LEVEL=${KIND_CLUSTER_LOG_LEVEL:-4} 89 90 # potentially enable --logging-format 91 CLUSTER_LOG_FORMAT=${CLUSTER_LOG_FORMAT:-} 92 scheduler_extra_args=" \"v\": \"${KIND_CLUSTER_LOG_LEVEL}\"" 93 controllerManager_extra_args=" \"v\": \"${KIND_CLUSTER_LOG_LEVEL}\"" 94 apiServer_extra_args=" \"v\": \"${KIND_CLUSTER_LOG_LEVEL}\"" 95 if [ -n "$CLUSTER_LOG_FORMAT" ]; then 96 check_structured_log_support "CLUSTER_LOG_FORMAT" 97 scheduler_extra_args="${scheduler_extra_args} 98 \"logging-format\": \"${CLUSTER_LOG_FORMAT}\"" 99 controllerManager_extra_args="${controllerManager_extra_args} 100 \"logging-format\": \"${CLUSTER_LOG_FORMAT}\"" 101 apiServer_extra_args="${apiServer_extra_args} 102 \"logging-format\": \"${CLUSTER_LOG_FORMAT}\"" 103 fi 104 kubelet_extra_args=" \"v\": \"${KIND_CLUSTER_LOG_LEVEL}\"" 105 KUBELET_LOG_FORMAT=${KUBELET_LOG_FORMAT:-$CLUSTER_LOG_FORMAT} 106 if [ -n "$KUBELET_LOG_FORMAT" ]; then 107 check_structured_log_support "KUBECTL_LOG_FORMAT" 108 kubelet_extra_args="${kubelet_extra_args} 109 \"logging-format\": \"${KUBELET_LOG_FORMAT}\"" 110 fi 111 112 # JSON map injected into featureGates config 113 feature_gates="{}" 114 # --runtime-config argument value passed to the API server 115 runtime_config="{}" 116 117 case "${GA_ONLY:-false}" in 118 false) 119 feature_gates="{}" 120 runtime_config="{}" 121 ;; 122 true) 123 case "${KUBE_VERSION}" in 124 v1.1[0-7].*) 125 echo "GA_ONLY=true is only supported on versions >= v1.18, got ${KUBE_VERSION}" 126 exit 1 127 ;; 128 v1.18.*) 129 echo "Limiting to GA APIs and features (plus certificates.k8s.io/v1beta1 and RotateKubeletClientCertificate) for ${KUBE_VERSION}" 130 feature_gates='{"AllAlpha":false,"AllBeta":false,"RotateKubeletClientCertificate":true}' 131 runtime_config='{"api/alpha":"false", "api/beta":"false", "certificates.k8s.io/v1beta1":"true"}' 132 ;; 133 *) 134 echo "Limiting to GA APIs and features for ${KUBE_VERSION}" 135 feature_gates='{"AllAlpha":false,"AllBeta":false}' 136 runtime_config='{"api/alpha":"false", "api/beta":"false"}' 137 ;; 138 esac 139 ;; 140 *) 141 echo "\$GA_ONLY set to '${GA_ONLY}'; supported values are true and false (default)" 142 exit 1 143 ;; 144 esac 145 146 # create the config file 147 cat <<EOF > "${ARTIFACTS}/kind-config.yaml" 148 # config for 1 control plane node and 2 workers (necessary for conformance) 149 kind: Cluster 150 apiVersion: kind.x-k8s.io/v1alpha4 151 networking: 152 ipFamily: ${IP_FAMILY:-ipv4} 153 kubeProxyMode: ${KUBE_PROXY_MODE:-iptables} 154 nodes: 155 - role: control-plane 156 - role: worker 157 - role: worker 158 featureGates: ${feature_gates} 159 runtimeConfig: ${runtime_config} 160 kubeadmConfigPatches: 161 - | 162 kind: ClusterConfiguration 163 metadata: 164 name: config 165 apiServer: 166 extraArgs: 167 ${apiServer_extra_args} 168 controllerManager: 169 extraArgs: 170 ${controllerManager_extra_args} 171 scheduler: 172 extraArgs: 173 ${scheduler_extra_args} 174 --- 175 kind: InitConfiguration 176 nodeRegistration: 177 kubeletExtraArgs: 178 ${kubelet_extra_args} 179 --- 180 kind: JoinConfiguration 181 nodeRegistration: 182 kubeletExtraArgs: 183 ${kubelet_extra_args} 184 --- 185 kind: KubeProxyConfiguration 186 detectLocalMode: ${KUBE_PROXY_DETECT_LOCAL_MODE:-ClusterCIDR} 187 detectLocal: 188 interfaceNamePrefix: veth # used only with detectLocalMode "InterfaceNamePrefix" 189 EOF 190 # NOTE: must match the number of workers above 191 NUM_NODES=2 192 # actually create the cluster 193 # TODO(BenTheElder): settle on verbosity for this script 194 KIND_CREATE_ATTEMPTED=true 195 kind create cluster \ 196 --image=kindest/node:latest \ 197 --retain \ 198 --wait=1m \ 199 -v=3 \ 200 "--config=${ARTIFACTS}/kind-config.yaml" 201 202 # Patch kube-proxy to set the verbosity level 203 kubectl patch -n kube-system daemonset/kube-proxy \ 204 --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/command/-", "value": "--v='"${KIND_CLUSTER_LOG_LEVEL}"'" }]' 205 } 206 207 # run e2es with ginkgo-e2e.sh 208 run_tests() { 209 # IPv6 clusters need some CoreDNS changes in order to work in k8s CI: 210 # 1. k8s CI doesn´t offer IPv6 connectivity, so CoreDNS should be configured 211 # to work in an offline environment: 212 # https://github.com/coredns/coredns/issues/2494#issuecomment-457215452 213 # 2. k8s CI adds following domains to resolv.conf search field: 214 # c.k8s-prow-builds.internal google.internal. 215 # CoreDNS should handle those domains and answer with NXDOMAIN instead of SERVFAIL 216 # otherwise pods stops trying to resolve the domain. 217 if [ "${IP_FAMILY:-ipv4}" = "ipv6" ]; then 218 # Get the current config 219 original_coredns=$(kubectl get -oyaml -n=kube-system configmap/coredns) 220 echo "Original CoreDNS config:" 221 echo "${original_coredns}" 222 # Patch it 223 fixed_coredns=$( 224 printf '%s' "${original_coredns}" | sed \ 225 -e 's/^.*kubernetes cluster\.local/& internal/' \ 226 -e '/^.*upstream$/d' \ 227 -e '/^.*fallthrough.*$/d' \ 228 -e '/^.*forward . \/etc\/resolv.conf$/d' \ 229 -e '/^.*loop$/d' \ 230 ) 231 echo "Patched CoreDNS config:" 232 echo "${fixed_coredns}" 233 printf '%s' "${fixed_coredns}" | kubectl apply -f - 234 fi 235 236 # ginkgo regexes 237 SKIP="${SKIP:-}" 238 FOCUS="${FOCUS:-"\\[Conformance\\]"}" 239 # if we set PARALLEL=true, skip serial tests set --ginkgo-parallel 240 if [ "${PARALLEL:-false}" = "true" ]; then 241 export GINKGO_PARALLEL=y 242 if [ -z "${SKIP}" ]; then 243 SKIP="\\[Serial\\]" 244 else 245 SKIP="\\[Serial\\]|${SKIP}" 246 fi 247 fi 248 249 # setting this env prevents ginkgo e2e from trying to run provider setup 250 export KUBERNETES_CONFORMANCE_TEST='y' 251 # setting these is required to make RuntimeClass tests work ... :/ 252 export KUBE_CONTAINER_RUNTIME=remote 253 export KUBE_CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock 254 export KUBE_CONTAINER_RUNTIME_NAME=containerd 255 # ginkgo can take forever to exit, so we run it in the background and save the 256 # PID, bash will not run traps while waiting on a process, but it will while 257 # running a builtin like `wait`, saving the PID also allows us to forward the 258 # interrupt 259 ./hack/ginkgo-e2e.sh \ 260 '--provider=skeleton' "--num-nodes=${NUM_NODES}" \ 261 "--ginkgo.focus=${FOCUS}" "--ginkgo.skip=${SKIP}" \ 262 "--report-dir=${ARTIFACTS}" '--disable-log-dump=true' & 263 GINKGO_PID=$! 264 wait "$GINKGO_PID" 265 } 266 267 main() { 268 # create temp dir and setup cleanup 269 TMP_DIR=$(mktemp -d) 270 271 # ensure artifacts (results) directory exists when not in CI 272 export ARTIFACTS="${ARTIFACTS:-${PWD}/_artifacts}" 273 mkdir -p "${ARTIFACTS}" 274 275 # export the KUBECONFIG to a unique path for testing 276 KUBECONFIG="${HOME}/.kube/kind-test-config" 277 export KUBECONFIG 278 echo "exported KUBECONFIG=${KUBECONFIG}" 279 280 # debug kind version 281 kind version 282 283 # build kubernetes 284 build 285 # in CI attempt to release some memory after building 286 if [ -n "${KUBETEST_IN_DOCKER:-}" ]; then 287 sync || true 288 echo 1 > /proc/sys/vm/drop_caches || true 289 fi 290 291 # create the cluster and run tests 292 res=0 293 create_cluster || res=$? 294 run_tests || res=$? 295 cleanup || res=$? 296 exit $res 297 } 298 299 main