#!/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