2020-09-10 15:30:15 +00:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
|
|
# This script can be used to prepare a kind cluster and deploy the app.
|
|
|
|
# You can call this script again to redeploy the app.
|
2020-09-11 00:36:22 +00:00
|
|
|
# It will also output instructions on how to run the integration.
|
2020-09-10 15:30:15 +00:00
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
2020-09-11 00:36:22 +00:00
|
|
|
#
|
|
|
|
# Helper functions
|
|
|
|
#
|
2020-09-08 16:29:34 +00:00
|
|
|
TILT_MODE=${TILT_MODE:-no}
|
|
|
|
function tilt_mode() {
|
|
|
|
if [[ "$TILT_MODE" == "yes" ]]; then
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2020-09-10 15:30:15 +00:00
|
|
|
function log_note() {
|
|
|
|
GREEN='\033[0;32m'
|
|
|
|
NC='\033[0m'
|
2020-10-14 23:58:43 +00:00
|
|
|
if [[ ${COLORTERM:-unknown} =~ ^(truecolor|24bit)$ ]]; then
|
2020-09-10 20:37:25 +00:00
|
|
|
echo -e "${GREEN}$*${NC}"
|
2020-09-10 15:30:15 +00:00
|
|
|
else
|
2020-09-10 20:37:25 +00:00
|
|
|
echo "$*"
|
2020-09-10 15:30:15 +00:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
function log_error() {
|
|
|
|
RED='\033[0;31m'
|
|
|
|
NC='\033[0m'
|
2020-10-14 23:58:43 +00:00
|
|
|
if [[ ${COLORTERM:-unknown} =~ ^(truecolor|24bit)$ ]]; then
|
2020-09-10 20:37:25 +00:00
|
|
|
echo -e "🙁${RED} Error: $* ${NC}"
|
2020-09-10 15:30:15 +00:00
|
|
|
else
|
2020-09-10 20:37:25 +00:00
|
|
|
echo ":( Error: $*"
|
2020-09-10 15:30:15 +00:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2020-09-11 15:19:49 +00:00
|
|
|
function check_dependency() {
|
|
|
|
if ! command -v "$1" >/dev/null; then
|
|
|
|
log_error "Missing dependency..."
|
|
|
|
log_error "$2"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2020-09-11 00:36:22 +00:00
|
|
|
#
|
|
|
|
# Handle argument parsing and help message
|
|
|
|
#
|
2020-09-10 15:30:15 +00:00
|
|
|
help=no
|
|
|
|
skip_build=no
|
2020-10-07 00:53:29 +00:00
|
|
|
clean_kind=no
|
2020-09-10 15:30:15 +00:00
|
|
|
|
|
|
|
while (("$#")); do
|
|
|
|
case "$1" in
|
|
|
|
-h | --help)
|
|
|
|
help=yes
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
-s | --skip-build)
|
|
|
|
skip_build=yes
|
|
|
|
shift
|
|
|
|
;;
|
2020-10-07 00:53:29 +00:00
|
|
|
-c | --clean)
|
|
|
|
clean_kind=yes
|
|
|
|
shift
|
|
|
|
;;
|
2020-09-10 15:30:15 +00:00
|
|
|
-*)
|
|
|
|
log_error "Unsupported flag $1" >&2
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
*)
|
2020-09-11 15:19:49 +00:00
|
|
|
log_error "Unsupported positional arg $1" >&2
|
|
|
|
exit 1
|
2020-09-10 15:30:15 +00:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
|
|
|
if [[ "$help" == "yes" ]]; then
|
|
|
|
me="$(basename "${BASH_SOURCE[0]}")"
|
2020-09-11 15:19:49 +00:00
|
|
|
log_note "Usage:"
|
|
|
|
log_note " $me [flags]"
|
|
|
|
log_note
|
|
|
|
log_note "Flags:"
|
|
|
|
log_note " -h, --help: print this usage"
|
|
|
|
log_note " -s, --skip-build: reuse the most recently built image of the app instead of building"
|
2020-09-10 15:30:15 +00:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2020-09-11 15:19:49 +00:00
|
|
|
pinniped_path="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
|
cd "$pinniped_path" || exit 1
|
2020-09-10 15:30:15 +00:00
|
|
|
|
2020-09-11 00:36:22 +00:00
|
|
|
#
|
|
|
|
# Check for dependencies
|
|
|
|
#
|
2020-09-11 15:19:49 +00:00
|
|
|
check_dependency docker "Please install docker. See https://docs.docker.com/get-docker"
|
|
|
|
check_dependency kind "Please install kind. e.g. 'brew install kind' for MacOS"
|
|
|
|
check_dependency ytt "Please install ytt. e.g. 'brew tap k14s/tap && brew install ytt' for MacOS"
|
|
|
|
check_dependency kapp "Please install kapp. e.g. 'brew tap k14s/tap && brew install kapp' for MacOS"
|
|
|
|
check_dependency kubectl "Please install kubectl. e.g. 'brew install kubectl' for MacOS"
|
|
|
|
check_dependency htpasswd "Please install htpasswd. Should be pre-installed on MacOS. Usually found in 'apache2-utils' package for linux."
|
2020-09-10 15:30:15 +00:00
|
|
|
|
2020-09-13 17:22:27 +00:00
|
|
|
# Require kubectl >= 1.18.x
|
|
|
|
if [ "$(kubectl version --client=true --short | cut -d '.' -f 2)" -lt 18 ]; then
|
2020-10-07 00:53:29 +00:00
|
|
|
log_error "kubectl >= 1.18.x is required, you have $(kubectl version --client=true --short | cut -d ':' -f2)"
|
2020-09-13 17:22:27 +00:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
if ! tilt_mode; then
|
2020-10-07 15:37:33 +00:00
|
|
|
if [[ "$clean_kind" == "yes" ]]; then
|
|
|
|
log_note "Deleting running kind clusters to prepare from a clean slate..."
|
2020-10-09 21:25:34 +00:00
|
|
|
kind delete cluster --name pinniped
|
2020-09-10 15:30:15 +00:00
|
|
|
fi
|
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
#
|
|
|
|
# Setup kind and build the app
|
|
|
|
#
|
|
|
|
log_note "Checking for running kind clusters..."
|
2020-10-09 21:25:34 +00:00
|
|
|
if ! kind get clusters | grep -q -e '^pinniped$'; then
|
2020-09-08 16:29:34 +00:00
|
|
|
log_note "Creating a kind cluster..."
|
2020-10-13 21:09:13 +00:00
|
|
|
# single-node.yaml exposes node port 31234 as 127.0.0.1:12345 and port 31235 as 127.0.0.1:12346
|
2020-10-09 21:25:34 +00:00
|
|
|
kind create cluster --config "$pinniped_path/hack/lib/kind-config/single-node.yaml" --name pinniped
|
2020-09-08 16:29:34 +00:00
|
|
|
else
|
|
|
|
if ! kubectl cluster-info | grep master | grep -q 127.0.0.1; then
|
|
|
|
log_error "Seems like your kubeconfig is not targeting a local cluster."
|
|
|
|
log_error "Exiting to avoid accidentally running tests against a real cluster."
|
|
|
|
exit 1
|
|
|
|
fi
|
2020-09-10 15:30:15 +00:00
|
|
|
fi
|
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
registry="docker.io"
|
|
|
|
repo="test/build"
|
|
|
|
registry_repo="$registry/$repo"
|
|
|
|
tag=$(uuidgen) # always a new tag to force K8s to reload the image on redeploy
|
|
|
|
|
|
|
|
if [[ "$skip_build" == "yes" ]]; then
|
|
|
|
most_recent_tag=$(docker images "$repo" --format "{{.Tag}}" | head -1)
|
|
|
|
if [[ -n "$most_recent_tag" ]]; then
|
|
|
|
tag="$most_recent_tag"
|
|
|
|
do_build=no
|
|
|
|
else
|
|
|
|
# Oops, there was no previous build. Need to build anyway.
|
|
|
|
do_build=yes
|
|
|
|
fi
|
2020-09-10 15:30:15 +00:00
|
|
|
else
|
|
|
|
do_build=yes
|
|
|
|
fi
|
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
registry_repo_tag="${registry_repo}:${tag}"
|
2020-09-10 15:30:15 +00:00
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
if [[ "$do_build" == "yes" ]]; then
|
|
|
|
# Rebuild the code
|
|
|
|
log_note "Docker building the app..."
|
|
|
|
docker build . --tag "$registry_repo_tag"
|
|
|
|
fi
|
2020-09-10 15:30:15 +00:00
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
# Load it into the cluster
|
|
|
|
log_note "Loading the app's container image into the kind cluster..."
|
2020-10-09 21:25:34 +00:00
|
|
|
kind load docker-image "$registry_repo_tag" --name pinniped
|
2020-09-10 15:30:15 +00:00
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
manifest=/tmp/manifest.yaml
|
2020-09-10 15:30:15 +00:00
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
#
|
|
|
|
# Deploy local-user-authenticator
|
|
|
|
#
|
2020-10-09 17:00:22 +00:00
|
|
|
pushd deploy/local-user-authenticator >/dev/null
|
2020-09-10 15:30:15 +00:00
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
log_note "Deploying the local-user-authenticator app to the cluster..."
|
|
|
|
ytt --file . \
|
|
|
|
--data-value "image_repo=$registry_repo" \
|
|
|
|
--data-value "image_tag=$tag" >"$manifest"
|
2020-09-11 00:36:22 +00:00
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
kubectl apply --dry-run=client -f "$manifest" # Validate manifest schema.
|
|
|
|
kapp deploy --yes --app local-user-authenticator --diff-changes --file "$manifest"
|
2020-09-11 00:36:22 +00:00
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
popd >/dev/null
|
|
|
|
|
2020-10-13 21:09:13 +00:00
|
|
|
#
|
|
|
|
# Deploy dex
|
|
|
|
#
|
|
|
|
pushd test/deploy/dex >/dev/null
|
|
|
|
|
|
|
|
log_note "Deploying Dex to the cluster..."
|
|
|
|
ytt --file . >"$manifest"
|
|
|
|
kubectl apply --dry-run=client -f "$manifest" # Validate manifest schema.
|
|
|
|
kapp deploy --yes --app dex --diff-changes --file "$manifest"
|
|
|
|
|
|
|
|
popd >/dev/null
|
2020-09-08 16:29:34 +00:00
|
|
|
fi
|
2020-09-11 00:36:22 +00:00
|
|
|
|
|
|
|
test_username="test-username"
|
|
|
|
test_groups="test-group-0,test-group-1"
|
|
|
|
set +o pipefail
|
|
|
|
test_password="$(cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-z0-9' | fold -w 32 | head -n 1)"
|
|
|
|
set -o pipefail
|
|
|
|
if [[ ${#test_password} -ne 32 ]]; then
|
2020-09-11 15:19:49 +00:00
|
|
|
log_error "Could not create test user's random password"
|
2020-09-11 00:36:22 +00:00
|
|
|
exit 1
|
|
|
|
fi
|
2020-09-11 14:09:13 +00:00
|
|
|
log_note "Creating test user '$test_username'..."
|
2020-09-11 00:36:22 +00:00
|
|
|
kubectl create secret generic "$test_username" \
|
|
|
|
--namespace local-user-authenticator \
|
|
|
|
--from-literal=groups="$test_groups" \
|
|
|
|
--from-literal=passwordHash="$(htpasswd -nbBC 10 x "$test_password" | sed -e "s/^x://")" \
|
|
|
|
--dry-run=client \
|
|
|
|
--output yaml |
|
|
|
|
kubectl apply -f -
|
|
|
|
|
2020-10-06 00:28:19 +00:00
|
|
|
#
|
|
|
|
# Deploy the Pinniped Supervisor
|
|
|
|
#
|
2020-10-07 00:53:29 +00:00
|
|
|
supervisor_app_name="pinniped-supervisor"
|
2020-10-09 23:00:11 +00:00
|
|
|
supervisor_namespace="supervisor"
|
2020-10-15 17:14:23 +00:00
|
|
|
supervisor_custom_labels="{mySupervisorCustomLabelName: mySupervisorCustomLabelValue}"
|
2020-10-07 00:53:29 +00:00
|
|
|
|
2020-10-09 21:25:34 +00:00
|
|
|
if ! tilt_mode; then
|
|
|
|
pushd deploy/supervisor >/dev/null
|
2020-10-06 00:28:19 +00:00
|
|
|
|
2020-10-09 21:25:34 +00:00
|
|
|
log_note "Deploying the Pinniped Supervisor app to the cluster..."
|
|
|
|
ytt --file . \
|
|
|
|
--data-value "app_name=$supervisor_app_name" \
|
|
|
|
--data-value "namespace=$supervisor_namespace" \
|
|
|
|
--data-value "image_repo=$registry_repo" \
|
2020-10-10 01:07:13 +00:00
|
|
|
--data-value "image_tag=$tag" \
|
2020-10-15 17:14:23 +00:00
|
|
|
--data-value-yaml "custom_labels=$supervisor_custom_labels" \
|
2020-10-10 01:07:13 +00:00
|
|
|
--data-value-yaml 'service_nodeport_port=31234' >"$manifest"
|
2020-10-06 00:28:19 +00:00
|
|
|
|
2020-10-09 21:25:34 +00:00
|
|
|
kapp deploy --yes --app "$supervisor_app_name" --diff-changes --file "$manifest"
|
2020-10-06 00:28:19 +00:00
|
|
|
|
2020-10-09 21:25:34 +00:00
|
|
|
popd >/dev/null
|
|
|
|
fi
|
2020-10-06 00:28:19 +00:00
|
|
|
|
|
|
|
#
|
2020-10-15 17:14:23 +00:00
|
|
|
# Deploy the Pinniped Concierge
|
2020-10-06 00:28:19 +00:00
|
|
|
#
|
2020-10-09 21:25:34 +00:00
|
|
|
concierge_app_name="pinniped-concierge"
|
2020-10-09 23:00:11 +00:00
|
|
|
concierge_namespace="concierge"
|
2020-09-11 00:36:22 +00:00
|
|
|
webhook_url="https://local-user-authenticator.local-user-authenticator.svc/authenticate"
|
Rename many of resources that are created in Kubernetes by Pinniped
New resource naming conventions:
- Do not repeat the Kind in the name,
e.g. do not call it foo-cluster-role-binding, just call it foo
- Names will generally start with a prefix to identify our component,
so when a user lists all objects of that kind, they can tell to which
component it is related,
e.g. `kubectl get configmaps` would list one named "pinniped-config"
- It should be possible for an operator to make the word "pinniped"
mostly disappear if they choose, by specifying the app_name in
values.yaml, to the extent that is practical (but not from APIService
names because those are hardcoded in golang)
- Each role/clusterrole and its corresponding binding have the same name
- Pinniped resource names that must be known by the server golang code
are passed to the code at run time via ConfigMap, rather than
hardcoded in the golang code. This also allows them to be prepended
with the app_name from values.yaml while creating the ConfigMap.
- Since the CLI `get-kubeconfig` command cannot guess the name of the
CredentialIssuerConfig resource in advance anymore, it lists all
CredentialIssuerConfig in the app's namespace and returns an error
if there is not exactly one found, and then uses that one regardless
of its name
2020-09-18 22:56:50 +00:00
|
|
|
webhook_ca_bundle="$(kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator -o 'jsonpath={.data.caCertificate}')"
|
2020-09-11 00:36:22 +00:00
|
|
|
discovery_url="$(TERM=dumb kubectl cluster-info | awk '/Kubernetes master/ {print $NF}')"
|
2020-10-15 17:14:23 +00:00
|
|
|
concierge_custom_labels="{myConciergeCustomLabelName: myConciergeCustomLabelValue}"
|
2020-09-11 00:36:22 +00:00
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
if ! tilt_mode; then
|
2020-10-09 17:00:22 +00:00
|
|
|
pushd deploy/concierge >/dev/null
|
2020-09-11 00:36:22 +00:00
|
|
|
|
2020-10-15 17:14:23 +00:00
|
|
|
log_note "Deploying the Pinniped Concierge app to the cluster..."
|
2020-09-08 16:29:34 +00:00
|
|
|
ytt --file . \
|
2020-10-09 21:25:34 +00:00
|
|
|
--data-value "app_name=$concierge_app_name" \
|
|
|
|
--data-value "namespace=$concierge_namespace" \
|
2020-10-15 17:14:23 +00:00
|
|
|
--data-value-yaml "custom_labels=$concierge_custom_labels" \
|
2020-09-08 16:29:34 +00:00
|
|
|
--data-value "image_repo=$registry_repo" \
|
|
|
|
--data-value "image_tag=$tag" \
|
|
|
|
--data-value "discovery_url=$discovery_url" >"$manifest"
|
2020-09-11 00:36:22 +00:00
|
|
|
|
2020-10-09 21:25:34 +00:00
|
|
|
kapp deploy --yes --app "$concierge_app_name" --diff-changes --file "$manifest"
|
2020-09-11 00:36:22 +00:00
|
|
|
|
2020-09-08 16:29:34 +00:00
|
|
|
popd >/dev/null
|
|
|
|
fi
|
2020-09-11 00:36:22 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# Create the environment file
|
|
|
|
#
|
|
|
|
kind_capabilities_file="$pinniped_path/test/cluster_capabilities/kind.yaml"
|
|
|
|
pinniped_cluster_capability_file_content=$(cat "$kind_capabilities_file")
|
|
|
|
|
|
|
|
cat <<EOF >/tmp/integration-test-env
|
2020-10-10 01:07:13 +00:00
|
|
|
# The following env vars should be set before running 'go test -v -count 1 ./test/integration'
|
2020-10-09 21:25:34 +00:00
|
|
|
export PINNIPED_TEST_CONCIERGE_NAMESPACE=${concierge_namespace}
|
|
|
|
export PINNIPED_TEST_CONCIERGE_APP_NAME=${concierge_app_name}
|
2020-10-15 17:14:23 +00:00
|
|
|
export PINNIPED_TEST_CONCIERGE_CUSTOM_LABELS='${concierge_custom_labels}'
|
2020-09-11 00:10:27 +00:00
|
|
|
export PINNIPED_TEST_USER_USERNAME=${test_username}
|
|
|
|
export PINNIPED_TEST_USER_GROUPS=${test_groups}
|
|
|
|
export PINNIPED_TEST_USER_TOKEN=${test_username}:${test_password}
|
2020-09-22 00:55:04 +00:00
|
|
|
export PINNIPED_TEST_WEBHOOK_ENDPOINT=${webhook_url}
|
|
|
|
export PINNIPED_TEST_WEBHOOK_CA_BUNDLE=${webhook_ca_bundle}
|
2020-10-09 17:11:47 +00:00
|
|
|
export PINNIPED_TEST_SUPERVISOR_NAMESPACE=${supervisor_namespace}
|
|
|
|
export PINNIPED_TEST_SUPERVISOR_APP_NAME=${supervisor_app_name}
|
2020-10-15 17:14:23 +00:00
|
|
|
export PINNIPED_TEST_SUPERVISOR_CUSTOM_LABELS='${supervisor_custom_labels}'
|
2020-10-10 01:07:13 +00:00
|
|
|
export PINNIPED_TEST_SUPERVISOR_ADDRESS="127.0.0.1:12345"
|
2020-10-13 21:09:13 +00:00
|
|
|
export PINNIPED_TEST_CLI_OIDC_ISSUER=http://127.0.0.1:12346/dex
|
|
|
|
export PINNIPED_TEST_CLI_OIDC_CLIENT_ID=pinniped-cli
|
|
|
|
export PINNIPED_TEST_CLI_OIDC_LOCALHOST_PORT=48095
|
|
|
|
export PINNIPED_TEST_CLI_OIDC_USERNAME=pinny@example.com
|
|
|
|
export PINNIPED_TEST_CLI_OIDC_PASSWORD=password
|
2020-09-10 15:30:15 +00:00
|
|
|
|
2020-10-09 17:11:47 +00:00
|
|
|
read -r -d '' PINNIPED_TEST_CLUSTER_CAPABILITY_YAML << PINNIPED_TEST_CLUSTER_CAPABILITY_YAML_EOF || true
|
2020-09-10 15:30:15 +00:00
|
|
|
${pinniped_cluster_capability_file_content}
|
2020-10-09 17:11:47 +00:00
|
|
|
PINNIPED_TEST_CLUSTER_CAPABILITY_YAML_EOF
|
2020-09-10 15:30:15 +00:00
|
|
|
|
2020-10-09 17:11:47 +00:00
|
|
|
export PINNIPED_TEST_CLUSTER_CAPABILITY_YAML
|
2020-09-10 15:30:15 +00:00
|
|
|
EOF
|
|
|
|
|
2020-09-11 00:36:22 +00:00
|
|
|
#
|
|
|
|
# Print instructions for next steps
|
|
|
|
#
|
|
|
|
goland_vars=$(grep -v '^#' /tmp/integration-test-env | grep -E '^export .+=' | sed 's/export //g' | tr '\n' ';')
|
|
|
|
|
|
|
|
log_note
|
2020-09-11 15:19:49 +00:00
|
|
|
log_note "🚀 Ready to run integration tests! For example..."
|
2020-09-11 00:36:22 +00:00
|
|
|
log_note " cd $pinniped_path"
|
2020-10-07 00:53:29 +00:00
|
|
|
log_note ' source /tmp/integration-test-env && go test -v -count 1 ./test/integration'
|
2020-09-11 00:36:22 +00:00
|
|
|
log_note
|
2020-09-11 15:19:49 +00:00
|
|
|
log_note 'Want to run integration tests in GoLand? Copy/paste this "Environment" value for GoLand run configurations:'
|
2020-10-09 17:11:47 +00:00
|
|
|
log_note " ${goland_vars}PINNIPED_TEST_CLUSTER_CAPABILITY_FILE=${kind_capabilities_file}"
|
2020-09-11 00:36:22 +00:00
|
|
|
log_note
|
2020-09-08 16:29:34 +00:00
|
|
|
|
|
|
|
if ! tilt_mode; then
|
|
|
|
log_note "You can rerun this script to redeploy local production code changes while you are working."
|
|
|
|
log_note
|
2020-10-09 21:25:34 +00:00
|
|
|
log_note "To delete the deployments, run:"
|
|
|
|
log_note " kapp delete -a local-user-authenticator -y && kapp delete -a $concierge_app_name -y && kapp delete -a $supervisor_app_name -y"
|
|
|
|
log_note "When you're finished, use 'kind delete cluster --name pinniped' to tear down the cluster."
|
2020-09-08 16:29:34 +00:00
|
|
|
fi
|