123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- #!/bin/bash
- # Copyright 2014 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.
- # A library of helper functions and constant for the local config.
- # Use the config file specified in $KUBE_CONFIG_FILE, or default to
- # config-default.sh.
- set -e
- SOURCE="${BASH_SOURCE[0]}"
- while [ -h "$SOURCE" ]; do
- DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
- SOURCE="$(readlink "$SOURCE")"
- [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
- done
- DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
- KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
- source "${KUBE_ROOT}/cluster/azure-legacy/${KUBE_CONFIG_FILE-"config-default.sh"}"
- source "${KUBE_ROOT}/cluster/common.sh"
- function prepare-e2e() {
- # (e2e script runs detect-project, I don't think we need to anything)
- # Note: we can't print anything here, or else the test tools will break with the extra output
- return
- }
- function azure_call {
- local -a params=()
- local param
- # the '... in "$@"' is implicit on a for, so doesn't need to be stated.
- for param; do
- params+=("${param}")
- done
- local rc=0
- local stderr
- local count=0
- while [[ count -lt 10 ]]; do
- stderr=$(azure "${params[@]}" 2>&1 >&3) && break
- rc=$?
- if [[ "${stderr}" != *"getaddrinfo ENOTFOUND"* ]]; then
- break
- fi
- count=$(($count + 1))
- done 3>&1
- if [[ "${rc}" -ne 0 ]]; then
- echo "${stderr}" >&2
- return "${rc}"
- fi
- }
- function json_val () {
- python -c 'import json,sys;obj=json.load(sys.stdin);print obj'$1'';
- }
- # Verify prereqs
- function verify-prereqs {
- if [[ -z "$(which azure)" ]]; then
- echo "Couldn't find azure in PATH"
- echo " please install with 'npm install azure-cli'"
- exit 1
- fi
- if [[ -z "$(azure_call account list | grep true)" ]]; then
- echo "Default azure account not set"
- echo " please set with 'azure account set'"
- exit 1
- fi
- account=$(azure_call account list | grep true)
- if which md5 > /dev/null 2>&1; then
- AZ_HSH=$(md5 -q -s "$account")
- else
- AZ_HSH=$(echo -n "$account" | md5sum)
- fi
- AZ_HSH=${AZ_HSH:0:7}
- AZ_STG=kube$AZ_HSH
- echo "==> AZ_STG: $AZ_STG"
- AZ_CS="$AZ_CS_PREFIX-$AZ_HSH"
- echo "==> AZ_CS: $AZ_CS"
- CONTAINER=kube-$TAG
- echo "==> CONTAINER: $CONTAINER"
- }
- # Create a temp dir that'll be deleted at the end of this bash session.
- #
- # Vars set:
- # KUBE_TEMP
- function ensure-temp-dir {
- if [[ -z ${KUBE_TEMP-} ]]; then
- KUBE_TEMP=$(mktemp -d -t kubernetes.XXXXXX)
- trap 'rm -rf "${KUBE_TEMP}"' EXIT
- fi
- }
- # Take the local tar files and upload them to Azure Storage. They will then be
- # downloaded by the master as part of the start up script for the master.
- #
- # Assumed vars:
- # SERVER_BINARY_TAR
- # SALT_TAR
- # Vars set:
- # SERVER_BINARY_TAR_URL
- # SALT_TAR_URL
- function upload-server-tars() {
- SERVER_BINARY_TAR_URL=
- SALT_TAR_URL=
- echo "==> SERVER_BINARY_TAR: $SERVER_BINARY_TAR"
- echo "==> SALT_TAR: $SALT_TAR"
- echo "+++ Staging server tars to Azure Storage: $AZ_STG"
- local server_binary_url="${SERVER_BINARY_TAR##*/}"
- local salt_url="${SALT_TAR##*/}"
- SERVER_BINARY_TAR_URL="https://${AZ_STG}.blob.core.windows.net/$CONTAINER/$server_binary_url"
- SALT_TAR_URL="https://${AZ_STG}.blob.core.windows.net/$CONTAINER/$salt_url"
- echo "==> SERVER_BINARY_TAR_URL: $SERVER_BINARY_TAR_URL"
- echo "==> SALT_TAR_URL: $SALT_TAR_URL"
- echo "--> Checking storage exists..."
- if [[ -z "$(azure_call storage account show $AZ_STG 2>/dev/null | \
- grep data)" ]]; then
- echo "--> Creating storage..."
- azure_call storage account create -l "$AZ_LOCATION" $AZ_STG --type LRS
- fi
- echo "--> Getting storage key..."
- stg_key=$(azure_call storage account keys list $AZ_STG --json | \
- json_val '["primaryKey"]')
- echo "--> Checking storage container exists..."
- if [[ -z "$(azure_call storage container show -a $AZ_STG -k "$stg_key" \
- $CONTAINER 2>/dev/null | grep data)" ]]; then
- echo "--> Creating storage container..."
- azure_call storage container create \
- -a $AZ_STG \
- -k "$stg_key" \
- -p Blob \
- $CONTAINER
- fi
- echo "--> Checking server binary exists in the container..."
- if [[ -n "$(azure_call storage blob show -a $AZ_STG -k "$stg_key" \
- $CONTAINER $server_binary_url 2>/dev/null | grep data)" ]]; then
- echo "--> Deleting server binary in the container..."
- azure_call storage blob delete \
- -a $AZ_STG \
- -k "$stg_key" \
- $CONTAINER \
- $server_binary_url
- fi
- echo "--> Uploading server binary to the container..."
- azure_call storage blob upload \
- -a $AZ_STG \
- -k "$stg_key" \
- $SERVER_BINARY_TAR \
- $CONTAINER \
- $server_binary_url
- echo "--> Checking salt data exists in the container..."
- if [[ -n "$(azure_call storage blob show -a $AZ_STG -k "$stg_key" \
- $CONTAINER $salt_url 2>/dev/null | grep data)" ]]; then
- echo "--> Deleting salt data in the container..."
- azure_call storage blob delete \
- -a $AZ_STG \
- -k "$stg_key" \
- $CONTAINER \
- $salt_url
- fi
- echo "--> Uploading salt data to the container..."
- azure_call storage blob upload \
- -a $AZ_STG \
- -k "$stg_key" \
- $SALT_TAR \
- $CONTAINER \
- $salt_url
- }
- # Detect the information about the minions
- #
- # Assumed vars:
- # MINION_NAMES
- # ZONE
- # Vars set:
- #
- function detect-minions () {
- if [[ -z "$AZ_CS" ]]; then
- verify-prereqs-local
- fi
- ssh_ports=($(eval echo "2200{1..$NUM_MINIONS}"))
- for (( i=0; i<${#MINION_NAMES[@]}; i++)); do
- MINION_NAMES[$i]=$(ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p ${ssh_ports[$i]} $AZ_CS.cloudapp.net hostname -f)
- done
- }
- # Detect the IP for the master
- #
- # Assumed vars:
- # MASTER_NAME
- # ZONE
- # Vars set:
- # KUBE_MASTER
- # KUBE_MASTER_IP
- function detect-master () {
- if [[ -z "$AZ_CS" ]]; then
- verify-prereqs-local
- fi
- KUBE_MASTER=${MASTER_NAME}
- KUBE_MASTER_IP="${AZ_CS}.cloudapp.net"
- echo "Using master: $KUBE_MASTER (external IP: $KUBE_MASTER_IP)"
- }
- # Instantiate a kubernetes cluster
- #
- # Assumed vars
- # KUBE_ROOT
- # <Various vars set in config file>
- function kube-up {
- # Make sure we have the tar files staged on Azure Storage
- find-release-tars
- upload-server-tars
- ensure-temp-dir
- gen-kube-basicauth
- python "${KUBE_ROOT}/third_party/htpasswd/htpasswd.py" \
- -b -c "${KUBE_TEMP}/htpasswd" "$KUBE_USER" "$KUBE_PASSWORD"
- local htpasswd
- htpasswd=$(cat "${KUBE_TEMP}/htpasswd")
- # Generate openvpn certs
- echo "--> Generating openvpn certs"
- echo 01 > ${KUBE_TEMP}/ca.srl
- openssl genrsa -out ${KUBE_TEMP}/ca.key
- openssl req -new -x509 -days 1095 \
- -key ${KUBE_TEMP}/ca.key \
- -out ${KUBE_TEMP}/ca.crt \
- -subj "/CN=openvpn-ca"
- openssl genrsa -out ${KUBE_TEMP}/server.key
- openssl req -new \
- -key ${KUBE_TEMP}/server.key \
- -out ${KUBE_TEMP}/server.csr \
- -subj "/CN=server"
- openssl x509 -req -days 1095 \
- -in ${KUBE_TEMP}/server.csr \
- -CA ${KUBE_TEMP}/ca.crt \
- -CAkey ${KUBE_TEMP}/ca.key \
- -CAserial ${KUBE_TEMP}/ca.srl \
- -out ${KUBE_TEMP}/server.crt
- for (( i=0; i<${#MINION_NAMES[@]}; i++)); do
- openssl genrsa -out ${KUBE_TEMP}/${MINION_NAMES[$i]}.key
- openssl req -new \
- -key ${KUBE_TEMP}/${MINION_NAMES[$i]}.key \
- -out ${KUBE_TEMP}/${MINION_NAMES[$i]}.csr \
- -subj "/CN=${MINION_NAMES[$i]}"
- openssl x509 -req -days 1095 \
- -in ${KUBE_TEMP}/${MINION_NAMES[$i]}.csr \
- -CA ${KUBE_TEMP}/ca.crt \
- -CAkey ${KUBE_TEMP}/ca.key \
- -CAserial ${KUBE_TEMP}/ca.srl \
- -out ${KUBE_TEMP}/${MINION_NAMES[$i]}.crt
- done
- KUBE_MASTER_IP="${AZ_CS}.cloudapp.net"
- # Build up start up script for master
- echo "--> Building up start up script for master"
- (
- echo "#!/bin/bash"
- echo "CA_CRT=\"$(cat ${KUBE_TEMP}/ca.crt)\""
- echo "SERVER_CRT=\"$(cat ${KUBE_TEMP}/server.crt)\""
- echo "SERVER_KEY=\"$(cat ${KUBE_TEMP}/server.key)\""
- echo "mkdir -p /var/cache/kubernetes-install"
- echo "cd /var/cache/kubernetes-install"
- echo "readonly MASTER_NAME='${MASTER_NAME}'"
- echo "readonly INSTANCE_PREFIX='${INSTANCE_PREFIX}'"
- echo "readonly NODE_INSTANCE_PREFIX='${INSTANCE_PREFIX}-minion'"
- echo "readonly SERVER_BINARY_TAR_URL='${SERVER_BINARY_TAR_URL}'"
- echo "readonly SALT_TAR_URL='${SALT_TAR_URL}'"
- echo "readonly MASTER_HTPASSWD='${htpasswd}'"
- echo "readonly SERVICE_CLUSTER_IP_RANGE='${SERVICE_CLUSTER_IP_RANGE}'"
- echo "readonly ADMISSION_CONTROL='${ADMISSION_CONTROL:-}'"
- echo "readonly KUBE_USER='${KUBE_USER}'"
- echo "readonly KUBE_PASSWORD='${KUBE_PASSWORD}'"
- echo "readonly KUBE_MASTER_IP='${KUBE_MASTER_IP}'"
- grep -v "^#" "${KUBE_ROOT}/cluster/azure-legacy/templates/common.sh"
- grep -v "^#" "${KUBE_ROOT}/cluster/azure-legacy/templates/create-dynamic-salt-files.sh"
- grep -v "^#" "${KUBE_ROOT}/cluster/azure-legacy/templates/create-kubeconfig.sh"
- grep -v "^#" "${KUBE_ROOT}/cluster/azure-legacy/templates/download-release.sh"
- grep -v "^#" "${KUBE_ROOT}/cluster/azure-legacy/templates/salt-master.sh"
- ) > "${KUBE_TEMP}/master-start.sh"
- if [[ ! -f $AZ_SSH_KEY ]]; then
- ssh-keygen -f $AZ_SSH_KEY -N ''
- fi
- if [[ ! -f $AZ_SSH_CERT ]]; then
- openssl req -new -x509 -days 1095 -key $AZ_SSH_KEY -out $AZ_SSH_CERT \
- -subj "/CN=azure-ssh-key"
- fi
- if [[ -z "$(azure_call network vnet show "$AZ_VNET" 2>/dev/null | grep data)" ]]; then
- echo error create vnet $AZ_VNET with subnet $AZ_SUBNET
- exit 1
- fi
- echo "--> Starting VM"
- azure_call vm create \
- -z "$MASTER_SIZE" \
- -w "$AZ_VNET" \
- -n $MASTER_NAME \
- -l "$AZ_LOCATION" \
- -t $AZ_SSH_CERT \
- -e 22000 -P \
- -d ${KUBE_TEMP}/master-start.sh \
- -b $AZ_SUBNET \
- $AZ_CS $AZ_IMAGE $USER
- ssh_ports=($(eval echo "2200{1..$NUM_MINIONS}"))
- #Build up start up script for minions
- echo "--> Building up start up script for minions"
- for (( i=0; i<${#MINION_NAMES[@]}; i++)); do
- (
- echo "#!/bin/bash"
- echo "MASTER_NAME='${MASTER_NAME}'"
- echo "CA_CRT=\"$(cat ${KUBE_TEMP}/ca.crt)\""
- echo "CLIENT_CRT=\"$(cat ${KUBE_TEMP}/${MINION_NAMES[$i]}.crt)\""
- echo "CLIENT_KEY=\"$(cat ${KUBE_TEMP}/${MINION_NAMES[$i]}.key)\""
- echo "MINION_IP_RANGE='${MINION_IP_RANGES[$i]}'"
- echo "readonly KUBE_USER='${KUBE_USER}'"
- echo "readonly KUBE_PASSWORD='${KUBE_PASSWORD}'"
- echo "readonly KUBE_MASTER_IP='${KUBE_MASTER_IP}'"
- grep -v "^#" "${KUBE_ROOT}/cluster/azure-legacy/templates/common.sh"
- grep -v "^#" "${KUBE_ROOT}/cluster/azure-legacy/templates/create-kubeconfig.sh"
- grep -v "^#" "${KUBE_ROOT}/cluster/azure-legacy/templates/salt-minion.sh"
- ) > "${KUBE_TEMP}/minion-start-${i}.sh"
- echo "--> Starting VM"
- azure_call vm create \
- -z "$MINION_SIZE" \
- -c -w "$AZ_VNET" \
- -n ${MINION_NAMES[$i]} \
- -l "$AZ_LOCATION" \
- -t $AZ_SSH_CERT \
- -e ${ssh_ports[$i]} -P \
- -d ${KUBE_TEMP}/minion-start-${i}.sh \
- -b $AZ_SUBNET \
- $AZ_CS $AZ_IMAGE $USER
- done
- echo "--> Creating endpoint"
- azure_call vm endpoint create $MASTER_NAME 443
- detect-master > /dev/null
- echo "==> KUBE_MASTER_IP: ${KUBE_MASTER_IP}"
- echo "Waiting for cluster initialization."
- echo
- echo " This will continually check to see if the API for kubernetes is reachable."
- echo " This might loop forever if there was some uncaught error during start"
- echo " up."
- echo
- until curl --insecure --user "${KUBE_USER}:${KUBE_PASSWORD}" --max-time 5 \
- --fail --output /dev/null --silent "https://${KUBE_MASTER_IP}/healthz"; do
- printf "."
- sleep 2
- done
- printf "\n"
- echo "Kubernetes cluster created."
- export CONTEXT="azure_${INSTANCE_PREFIX}"
- create-kubeconfig
- export KUBE_CERT="/tmp/$RANDOM-kubecfg.crt"
- export KUBE_KEY="/tmp/$RANDOM-kubecfg.key"
- export CA_CERT="/tmp/$RANDOM-kubernetes.ca.crt"
- # TODO: generate ADMIN (and KUBELET) tokens and put those in the master's
- # config file. Distribute the same way the htpasswd is done.
- (umask 077
- ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p 22000 $AZ_CS.cloudapp.net \
- sudo cat /srv/kubernetes/kubecfg.crt >"${KUBE_CERT}" 2>/dev/null
- ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p 22000 $AZ_CS.cloudapp.net \
- sudo cat /srv/kubernetes/kubecfg.key >"${KUBE_KEY}" 2>/dev/null
- ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p 22000 $AZ_CS.cloudapp.net \
- sudo cat /srv/kubernetes/ca.crt >"${CA_CERT}" 2>/dev/null
- )
- echo "Sanity checking cluster..."
- echo
- echo " This will continually check the minions to ensure docker is"
- echo " installed. This is usually a good indicator that salt has"
- echo " successfully provisioned. This might loop forever if there was"
- echo " some uncaught error during start up."
- echo
- # Basic sanity checking
- for (( i=0; i<${#MINION_NAMES[@]}; i++)); do
- # Make sure docker is installed
- echo "--> Making sure docker is installed on ${MINION_NAMES[$i]}."
- until ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p ${ssh_ports[$i]} \
- $AZ_CS.cloudapp.net which docker > /dev/null 2>&1; do
- printf "."
- sleep 2
- done
- done
- sleep 60
- KUBECONFIG_NAME="kubeconfig"
- KUBECONFIG="${HOME}/.kube/config"
- echo "Distributing kubeconfig for kubelet to master kubelet"
- scp -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -P 22000 ${KUBECONFIG} \
- $AZ_CS.cloudapp.net:${KUBECONFIG_NAME}
- ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p 22000 $AZ_CS.cloudapp.net \
- sudo cp ${KUBECONFIG_NAME} /var/lib/kubelet/${KUBECONFIG_NAME}
- ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p 22000 $AZ_CS.cloudapp.net \
- sudo service kubelet restart
- echo "Distributing kubeconfig for kubelet to all minions"
- for (( i=0; i<${#MINION_NAMES[@]}; i++)); do
- scp -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -P ${ssh_ports[$i]} ${KUBECONFIG} \
- $AZ_CS.cloudapp.net:${KUBECONFIG_NAME}
- ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p ${ssh_ports[$i]} $AZ_CS.cloudapp.net \
- sudo cp ${KUBECONFIG_NAME} /var/lib/kubelet/${KUBECONFIG_NAME}
- ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p ${ssh_ports[$i]} $AZ_CS.cloudapp.net \
- sudo cp ${KUBECONFIG_NAME} /var/lib/kube-proxy/${KUBECONFIG_NAME}
- ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p ${ssh_ports[$i]} $AZ_CS.cloudapp.net \
- sudo service kubelet restart
- ssh -oStrictHostKeyChecking=no -i $AZ_SSH_KEY -p ${ssh_ports[$i]} $AZ_CS.cloudapp.net \
- sudo killall kube-proxy
- done
- # ensures KUBECONFIG is set
- get-kubeconfig-basicauth
- echo
- echo "Kubernetes cluster is running. The master is running at:"
- echo
- echo " https://${KUBE_MASTER_IP}"
- echo
- echo "The user name and password to use is located in ${KUBECONFIG}."
- echo
- }
- # Delete a kubernetes cluster
- function kube-down {
- echo "Bringing down cluster"
- set +e
- azure_call vm delete $MASTER_NAME -b -q
- for (( i=0; i<${#MINION_NAMES[@]}; i++)); do
- azure_call vm delete ${MINION_NAMES[$i]} -b -q
- done
- wait
- }
- # Update a kubernetes cluster with latest source
- #function kube-push {
- # detect-project
- # detect-master
- # Make sure we have the tar files staged on Azure Storage
- # find-release-tars
- # upload-server-tars
- # (
- # echo "#! /bin/bash"
- # echo "mkdir -p /var/cache/kubernetes-install"
- # echo "cd /var/cache/kubernetes-install"
- # echo "readonly SERVER_BINARY_TAR_URL='${SERVER_BINARY_TAR_URL}'"
- # echo "readonly SALT_TAR_URL='${SALT_TAR_URL}'"
- # grep -v "^#" "${KUBE_ROOT}/cluster/azure/templates/common.sh"
- # grep -v "^#" "${KUBE_ROOT}/cluster/azure/templates/download-release.sh"
- # echo "echo Executing configuration"
- # echo "sudo salt '*' mine.update"
- # echo "sudo salt --force-color '*' state.highstate"
- # ) | gcutil ssh --project "$PROJECT" --zone "$ZONE" "$KUBE_MASTER" sudo bash
- # get-kubeconfig-basicauth
- # echo
- # echo "Kubernetes cluster is running. The master is running at:"
- # echo
- # echo " https://${KUBE_MASTER_IP}"
- # echo
- # echo "The user name and password to use is located in ${KUBECONFIG:-$DEFAULT_KUBECONFIG}."
- # echo
- #}
- # -----------------------------------------------------------------------------
- # Cluster specific test helpers
- # Execute prior to running tests to build a release if required for env.
- #
- # Assumed Vars:
- # KUBE_ROOT
- function test-build-release {
- # Make a release
- "${KUBE_ROOT}/build/release.sh"
- }
- # SSH to a node by name ($1) and run a command ($2).
- function ssh-to-node {
- local node="$1"
- local cmd="$2"
- ssh --ssh_arg "-o LogLevel=quiet" "${node}" "${cmd}"
- }
- # Restart the kube-proxy on a node ($1)
- function restart-kube-proxy {
- ssh-to-node "$1" "sudo /etc/init.d/kube-proxy restart"
- }
- # Restart the kube-proxy on the master ($1)
- function restart-apiserver {
- ssh-to-node "$1" "sudo /etc/init.d/kube-apiserver restart"
- }
- function test-setup {
- "${KUBE_ROOT}/cluster/kube-up.sh"
- }
- function test-teardown {
- "${KUBE_ROOT}/cluster/kube-down.sh"
- }
|