#!/usr/bin/env bash # Copyright 2020 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # These tests enforce behavior of kube-addon-manager functions against a real # cluster. A working Kubernetes cluster must be set up with kubectl configured. # To run with the released version of kubectl, use `make test`. set -o errexit set -o pipefail set -o nounset # Default kubectl to the test users installation if needed. KUBECTL_BIN="${KUBECTL_BIN:-kubectl}" # Disabling shellcheck following files as the full path would be required. # shellcheck disable=SC1091 source "kube-addons.sh" TEST_NS="kube-addon-manager-test" function retry() { local tries=10 while [ "${tries}" -gt 0 ]; do "$@" && return 0; (( tries-- )) sleep 1 done } function setup(){ retry kubectl create namespace "${TEST_NS}" } function teardown() { retry kubectl delete namespace "${TEST_NS}" } function error() { echo -e "\e[31m$*\e[0m" } function echo_green() { echo -e "\e[32m$*\e[0m" } function echo_blue() { echo -e "\e[34m$*\e[0m" } function test_create_resource_reconcile() { local limitrange read -r -d '' limitrange << EOF apiVersion: "v1" kind: "LimitRange" metadata: name: "limits" namespace: "${TEST_NS}" labels: addonmanager.kubernetes.io/mode: Reconcile spec: limits: - type: "Container" defaultRequest: cpu: "100m" EOF # arguments are yaml text, number of tries, delay, name of file, and namespace echo_blue "Creating initial resource to test Reconcile mode" create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if ! (kubectl get limits/limits -n "${TEST_NS}"); then error "failed to create limits w/ reconcile" return 1 elif ! (kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "100m"); then error "limits does not match applied config" return 1 fi # Changes to addons with mode reconcile should be reflected. echo_blue "Changes to manifest should be reflected in the cluster" limitrange="${limitrange//100m/50m}" create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "100m"; then error "failed to update resource, still has 100m" return 1 elif ! (kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "50m"); then error "failed to update resource, 50m limit was not reflected" return 1 fi # Finally, the users configuration will not be respected. echo_blue "Changes the user makes should be overwritten by kube-addon-manager" EDITOR="sed -i 's/50m/600m/'" kubectl edit limits/limits -n ${TEST_NS} if kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "50m"; then error "failed to edit resource with sed -- test is broken" return 1 fi create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if ! ( kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "50m"); then error "failed to update resource, user config was respected when it should have been rewritten" return 1 fi } function test_create_resource_ensureexists() { local limitrange read -r -d '' limitrange << EOF apiVersion: "v1" kind: "LimitRange" metadata: name: "limits" namespace: "${TEST_NS}" labels: addonmanager.kubernetes.io/mode: EnsureExists spec: limits: - type: "Container" defaultRequest: cpu: "100m" EOF # arguments are yaml text, number of tries, delay, name of file, and namespace echo_blue "Creating initial resource to test mode EnsureExists" create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if ! (kubectl get limits/limits -n "${TEST_NS}"); then error "failed to create limits w/ EnsureExists" return 1 elif ! (kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "100m"); then error "limits does not match applied config" return 1 fi # Changes to addons with mode EnsureExists should NOT be reflected. echo_blue "Changes to the manifest should not be reconciled with the cluster" limitrange="${limitrange//100m/50m}" create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "50m"; then error "failed to respect existing resource, was overwritten despite EnsureExists" return 1 fi # the users configuration must be respected echo_blue "User configuration will be persisted for EnsureExists" EDITOR="sed -i 's/100m/600m/'" kubectl edit limits/limits -n ${TEST_NS} if kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "100m"; then error "failed to edit resource with sed -- test is broken" return 1 fi create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "100m"; then error "failed to respect user changes to EnsureExists object" return 1 fi # unless they delete the object, in which case it should return echo_blue "Missing EnsureExists resources will be re-created" kubectl delete limits/limits -n ${TEST_NS} if kubectl get limits/limits -n ${TEST_NS}; then error "failed to delete limitrange" return 1 fi create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if ! kubectl get limits/limits -n ${TEST_NS}; then error "failed to recreate deleted EnsureExists resource" return 1 fi } function test_create_multiresource() { local limitrange read -r -d '' limitrange << EOF apiVersion: "v1" kind: "LimitRange" metadata: name: "limits" namespace: "${TEST_NS}" labels: addonmanager.kubernetes.io/mode: EnsureExists spec: limits: - type: "Container" defaultRequest: cpu: "100m" --- apiVersion: "v1" kind: "LimitRange" metadata: name: "limits2" namespace: "${TEST_NS}" labels: addonmanager.kubernetes.io/mode: Reconcile spec: limits: - type: "Container" defaultRequest: cpu: "100m" EOF # arguments are yaml text, number of tries, delay, name of file, and namespace echo_blue "Creating initial resources from multi-resource manifest" create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if ! (kubectl get limits/limits -n "${TEST_NS}"); then error "failed to create limits w/ EnsureExists" return 1 elif ! (kubectl get limits/limits2 -n "${TEST_NS}"); then error "failed to create limits2 w/ Reconcile" return 1 fi # Changes to addons with mode EnsureExists should NOT be reflected. # However, the mode=Reconcile addon should be changed. echo_blue "Multi-resource manifest changes should apply to EnsureExists, not Reconcile" limitrange="${limitrange//100m/50m}" create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "50m"; then error "failed to respect existing resource, was overwritten despite EnsureExists" return 1 elif kubectl get limits/limits2 -n ${TEST_NS} | grep --silent "100m"; then error "failed to update resource with mode Reconcile" return 1 fi # the users configuration must be respected for EnsureExists echo_blue "Multi-resource manifest should not overwrite user config in EnsureExists" EDITOR="sed -i 's/100m/600m/'" kubectl edit limits/limits -n ${TEST_NS} if kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "100m"; then error "failed to edit resource with sed -- test is broken" return 1 fi create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if kubectl get limits/limits -n ${TEST_NS} -o yaml | grep --silent "100m"; then error "failed to respect user changes to EnsureExists object" return 1 fi # But not for Reconcile. echo_blue "Multi-resource manifest should overwrite user config in EnsureExists" EDITOR="sed -i 's/50m/600m/'" kubectl edit limits/limits2 -n ${TEST_NS} if kubectl get limits/limits2 -n ${TEST_NS} -o yaml | grep --silent "50m"; then error "failed to edit resource with sed -- test is broken" return 1 fi create_resource_from_string "${limitrange}" "10" "1" "limitrange.yaml" "${TEST_NS}" if ! ( kubectl get limits/limits2 -n ${TEST_NS} -o yaml | grep --silent "50m"); then error "failed to update resource, user config was respected when it should have been rewritten" return 1 fi } function test_func() { local -r name="${1}" echo_blue "=== TEST ${name}" setup if ! "${name}"; then failures=$((failures+1)) error "=== FAIL" else echo_green "=== PASS" fi teardown } failures=0 test_func test_create_resource_reconcile test_func test_create_resource_ensureexists test_func test_create_multiresource if [ "${failures}" -gt 0 ]; then error "no. failed tests: ${failures}" error "FAIL" exit 1 else echo_green "PASS" fi