123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- #!/usr/bin/env bash
- # Copyright 2017 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.
- # Common utilities for kube-up/kube-down
- set -o errexit
- set -o nounset
- set -o pipefail
- KUBE_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)
- DEFAULT_KUBECONFIG="${HOME:-.}/.kube/config"
- source "${KUBE_ROOT}/hack/lib/util.sh"
- # KUBE_RELEASE_VERSION_REGEX matches things like "v1.2.3" or "v1.2.3-alpha.4"
- #
- # NOTE This must match the version_regex in build/common.sh
- # kube::release::parse_and_validate_release_version()
- #
- # KUBE_RELEASE_VERSION_REGEX is used in hack/get-build.sh and cluster/gce/util.sh and KUBE_RELEASE_VERSION_DASHED_REGEX is used in cluster/gce/util.sh,
- # make sure to remove these vars when not used anymore
- export KUBE_RELEASE_VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-([a-zA-Z0-9]+)\\.(0|[1-9][0-9]*))?$"
- export KUBE_RELEASE_VERSION_DASHED_REGEX="v(0|[1-9][0-9]*)-(0|[1-9][0-9]*)-(0|[1-9][0-9]*)(-([a-zA-Z0-9]+)-(0|[1-9][0-9]*))?"
- # KUBE_CI_VERSION_REGEX matches things like "v1.2.3-alpha.4.56+abcdefg" This
- #
- # NOTE This must match the version_regex in build/common.sh
- # kube::release::parse_and_validate_ci_version()
- #
- # TODO: KUBE_CI_VERSION_REGEX is used in hack/get-build.sh and KUBE_CI_VERSION_DASHED_REGEX is used in cluster/gce/util.sh,
- # make sure to remove these vars when not used anymore
- export KUBE_CI_VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)-([a-zA-Z0-9]+)\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*)\\+[-0-9a-z]*)?$"
- export KUBE_CI_VERSION_DASHED_REGEX="^v(0|[1-9][0-9]*)-(0|[1-9][0-9]*)-(0|[1-9][0-9]*)-([a-zA-Z0-9]+)-(0|[1-9][0-9]*)(-(0|[1-9][0-9]*)\\+[-0-9a-z]*)?"
- # Generate kubeconfig data for the created cluster.
- # Assumed vars:
- # KUBE_USER
- # KUBE_PASSWORD
- # KUBE_MASTER_IP
- # KUBECONFIG
- # CONTEXT
- #
- # If the apiserver supports bearer auth, also provide:
- # KUBE_BEARER_TOKEN
- #
- # If the kubeconfig context being created should NOT be set as the current context
- # SECONDARY_KUBECONFIG=true
- #
- # To explicitly name the context being created, use OVERRIDE_CONTEXT
- #
- # The following can be omitted for --insecure-skip-tls-verify
- # KUBE_CERT
- # KUBE_KEY
- # CA_CERT
- function create-kubeconfig() {
- KUBECONFIG=${KUBECONFIG:-$DEFAULT_KUBECONFIG}
- local kubectl="${KUBE_ROOT}/cluster/kubectl.sh"
- SECONDARY_KUBECONFIG=${SECONDARY_KUBECONFIG:-}
- OVERRIDE_CONTEXT=${OVERRIDE_CONTEXT:-}
- if [[ "$OVERRIDE_CONTEXT" != "" ]];then
- CONTEXT=$OVERRIDE_CONTEXT
- fi
- # KUBECONFIG determines the file we write to, but it may not exist yet
- OLD_IFS=$IFS
- IFS=':'
- for cfg in ${KUBECONFIG} ; do
- if [[ ! -e "${cfg}" ]]; then
- mkdir -p "$(dirname "${cfg}")"
- touch "${cfg}"
- fi
- done
- IFS=$OLD_IFS
- local cluster_args=(
- "--server=${KUBE_SERVER:-https://${KUBE_MASTER_IP}}"
- )
- if [[ -z "${CA_CERT:-}" ]]; then
- cluster_args+=("--insecure-skip-tls-verify=true")
- else
- cluster_args+=(
- "--certificate-authority=${CA_CERT}"
- "--embed-certs=true"
- )
- fi
- local user_args=()
- if [[ -n "${KUBE_BEARER_TOKEN:-}" ]]; then
- user_args+=(
- "--token=${KUBE_BEARER_TOKEN}"
- )
- elif [[ -n "${KUBE_USER:-}" && -n "${KUBE_PASSWORD:-}" ]]; then
- user_args+=(
- "--username=${KUBE_USER}"
- "--password=${KUBE_PASSWORD}"
- )
- fi
- if [[ -n "${KUBE_CERT:-}" && -n "${KUBE_KEY:-}" ]]; then
- user_args+=(
- "--client-certificate=${KUBE_CERT}"
- "--client-key=${KUBE_KEY}"
- "--embed-certs=true"
- )
- fi
- KUBECONFIG="${KUBECONFIG}" "${kubectl}" config set-cluster "${CONTEXT}" "${cluster_args[@]}"
- if [[ -n "${user_args[*]:-}" ]]; then
- KUBECONFIG="${KUBECONFIG}" "${kubectl}" config set-credentials "${CONTEXT}" "${user_args[@]}"
- fi
- KUBECONFIG="${KUBECONFIG}" "${kubectl}" config set-context "${CONTEXT}" --cluster="${CONTEXT}" --user="${CONTEXT}"
- if [[ "${SECONDARY_KUBECONFIG}" != "true" ]];then
- KUBECONFIG="${KUBECONFIG}" "${kubectl}" config use-context "${CONTEXT}" --cluster="${CONTEXT}"
- fi
- # If we have a bearer token, also create a credential entry with basic auth
- # so that it is easy to discover the basic auth password for your cluster
- # to use in a web browser.
- if [[ -n "${KUBE_BEARER_TOKEN:-}" && -n "${KUBE_USER:-}" && -n "${KUBE_PASSWORD:-}" ]]; then
- KUBECONFIG="${KUBECONFIG}" "${kubectl}" config set-credentials "${CONTEXT}-basic-auth" "--username=${KUBE_USER}" "--password=${KUBE_PASSWORD}"
- fi
- echo "Wrote config for ${CONTEXT} to ${KUBECONFIG}"
- }
- # Clear kubeconfig data for a context
- # Assumed vars:
- # KUBECONFIG
- # CONTEXT
- #
- # To explicitly name the context being removed, use OVERRIDE_CONTEXT
- function clear-kubeconfig() {
- export KUBECONFIG=${KUBECONFIG:-$DEFAULT_KUBECONFIG}
- OVERRIDE_CONTEXT=${OVERRIDE_CONTEXT:-}
- if [[ "$OVERRIDE_CONTEXT" != "" ]];then
- CONTEXT=$OVERRIDE_CONTEXT
- fi
- local kubectl="${KUBE_ROOT}/cluster/kubectl.sh"
- # Unset the current-context before we delete it, as otherwise kubectl errors.
- local cc
- cc=$("${kubectl}" config view -o jsonpath='{.current-context}')
- if [[ "${cc}" == "${CONTEXT}" ]]; then
- "${kubectl}" config unset current-context
- fi
- "${kubectl}" config unset "clusters.${CONTEXT}"
- "${kubectl}" config unset "users.${CONTEXT}"
- "${kubectl}" config unset "users.${CONTEXT}-basic-auth"
- "${kubectl}" config unset "contexts.${CONTEXT}"
- echo "Cleared config for ${CONTEXT} from ${KUBECONFIG}"
- }
- # Gets username, password for the current-context in kubeconfig, if they exist.
- # Assumed vars:
- # KUBECONFIG # if unset, defaults to global
- # KUBE_CONTEXT # if unset, defaults to current-context
- #
- # Vars set:
- # KUBE_USER
- # KUBE_PASSWORD
- #
- # KUBE_USER,KUBE_PASSWORD will be empty if no current-context is set, or
- # the current-context user does not exist or contain basicauth entries.
- function get-kubeconfig-basicauth() {
- export KUBECONFIG=${KUBECONFIG:-$DEFAULT_KUBECONFIG}
- local cc
- cc=$("${KUBE_ROOT}/cluster/kubectl.sh" config view -o jsonpath="{.current-context}")
- if [[ -n "${KUBE_CONTEXT:-}" ]]; then
- cc="${KUBE_CONTEXT}"
- fi
- local user
- user=$("${KUBE_ROOT}/cluster/kubectl.sh" config view -o jsonpath="{.contexts[?(@.name == \"${cc}\")].context.user}")
- get-kubeconfig-user-basicauth "${user}"
- if [[ -z "${KUBE_USER:-}" || -z "${KUBE_PASSWORD:-}" ]]; then
- # kube-up stores username/password in a an additional kubeconfig section
- # suffixed with "-basic-auth". Cloudproviders like GKE store in directly
- # in the top level section along with the other credential information.
- # TODO: Handle this uniformly, either get rid of "basic-auth" or
- # consolidate its usage into a function across scripts in cluster/
- get-kubeconfig-user-basicauth "${user}-basic-auth"
- fi
- }
- # Sets KUBE_USER and KUBE_PASSWORD to the username and password specified in
- # the kubeconfig section corresponding to $1.
- #
- # Args:
- # $1 kubeconfig section to look for basic auth (eg: user or user-basic-auth).
- # Assumed vars:
- # KUBE_ROOT
- # Vars set:
- # KUBE_USER
- # KUBE_PASSWORD
- function get-kubeconfig-user-basicauth() {
- KUBE_USER=$("${KUBE_ROOT}/cluster/kubectl.sh" config view -o jsonpath="{.users[?(@.name == \"$1\")].user.username}")
- KUBE_PASSWORD=$("${KUBE_ROOT}/cluster/kubectl.sh" config view -o jsonpath="{.users[?(@.name == \"$1\")].user.password}")
- }
- # Generate basic auth user and password.
- # Vars set:
- # KUBE_USER
- # KUBE_PASSWORD
- function gen-kube-basicauth() {
- KUBE_USER='admin'
- KUBE_PASSWORD=$(python -c 'import string,random; print("".join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(16)))')
- }
- # Get the bearer token for the current-context in kubeconfig if one exists.
- # Assumed vars:
- # KUBECONFIG # if unset, defaults to global
- # KUBE_CONTEXT # if unset, defaults to current-context
- #
- # Vars set:
- # KUBE_BEARER_TOKEN
- #
- # KUBE_BEARER_TOKEN will be empty if no current-context is set, or the
- # current-context user does not exist or contain a bearer token entry.
- function get-kubeconfig-bearertoken() {
- export KUBECONFIG=${KUBECONFIG:-$DEFAULT_KUBECONFIG}
- local cc
- cc=$("${KUBE_ROOT}/cluster/kubectl.sh" config view -o jsonpath="{.current-context}")
- if [[ -n "${KUBE_CONTEXT:-}" ]]; then
- cc="${KUBE_CONTEXT}"
- fi
- local user
- user=$("${KUBE_ROOT}/cluster/kubectl.sh" config view -o jsonpath="{.contexts[?(@.name == \"${cc}\")].context.user}")
- KUBE_BEARER_TOKEN=$("${KUBE_ROOT}/cluster/kubectl.sh" config view -o jsonpath="{.users[?(@.name == \"${user}\")].user.token}")
- }
- # Generate bearer token.
- #
- # Vars set:
- # KUBE_BEARER_TOKEN
- function gen-kube-bearertoken() {
- KUBE_BEARER_TOKEN=$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64 | tr -d "=+/" | dd bs=32 count=1 2>/dev/null)
- }
- function load-or-gen-kube-basicauth() {
- if [[ -n "${KUBE_CONTEXT:-}" ]]; then
- get-kubeconfig-basicauth
- fi
- if [[ -z "${KUBE_USER:-}" || -z "${KUBE_PASSWORD:-}" ]]; then
- gen-kube-basicauth
- fi
- # Make sure they don't contain any funny characters.
- if ! [[ "${KUBE_USER}" =~ ^[-._@a-zA-Z0-9]+$ ]]; then
- echo "Bad KUBE_USER string."
- exit 1
- fi
- if ! [[ "${KUBE_PASSWORD}" =~ ^[-._@#%/a-zA-Z0-9]+$ ]]; then
- echo "Bad KUBE_PASSWORD string."
- exit 1
- fi
- }
- # Sets KUBE_VERSION variable to the proper version number (e.g. "v1.0.6",
- # "v1.2.0-alpha.1.881+376438b69c7612") or a version' publication of the form
- # <path>/<version> (e.g. "release/stable",' "ci/latest-1").
- #
- # See the docs on getting builds for more information about version
- # publication.
- #
- # Args:
- # $1 version string from command line
- # Vars set and exported for external reference:
- # KUBE_VERSION
- function set_binary_version() {
- if [[ "${1}" =~ "/" ]]; then
- IFS='/' read -r -a path <<< "${1}"
- if [[ "${path[0]}" == "release" ]]; then
- KUBE_VERSION=$(gsutil cat "gs://kubernetes-release/${1}.txt")
- else
- KUBE_VERSION=$(gsutil cat "gs://kubernetes-release-dev/${1}.txt")
- fi
- else
- KUBE_VERSION=${1}
- fi
- export KUBE_VERSION
- }
- # Search for the specified tarball in the various known output locations,
- # echoing the location if found.
- #
- # Assumed vars:
- # KUBE_ROOT
- #
- # Args:
- # $1 name of tarball to search for
- function find-tar() {
- local -r tarball=$1
- locations=(
- "${KUBE_ROOT}/node/${tarball}"
- "${KUBE_ROOT}/server/${tarball}"
- "${KUBE_ROOT}/_output/release-tars/${tarball}"
- "${KUBE_ROOT}/bazel-bin/build/release-tars/${tarball}"
- )
- location=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 )
- if [[ ! -f "${location}" ]]; then
- echo "!!! Cannot find ${tarball}" >&2
- exit 1
- fi
- echo "${location}"
- }
- # Verify and find the various tar files that we are going to use on the server.
- #
- # Assumed vars:
- # KUBE_ROOT
- # Vars set and exported:
- # NODE_BINARY_TAR
- # SERVER_BINARY_TAR
- # KUBE_MANIFESTS_TAR
- function find-release-tars() {
- SERVER_BINARY_TAR=$(find-tar kubernetes-server-linux-amd64.tar.gz)
- if [[ -z "${SERVER_BINARY_TAR}" ]]; then
- exit 1
- fi
- export SERVER_BINARY_TAR
- local find_result
- if [[ "${NUM_WINDOWS_NODES}" -gt "0" ]]; then
- if NODE_BINARY_TAR=$(find-tar kubernetes-node-windows-amd64.tar.gz); then
- find_result=0
- else
- find_result=1
- fi
- export NODE_BINARY_TAR
- fi
- # This tarball is used by GCI, Ubuntu Trusty, and Container Linux.
- KUBE_MANIFESTS_TAR=
- if [[ "${MASTER_OS_DISTRIBUTION:-}" == "trusty" || "${MASTER_OS_DISTRIBUTION:-}" == "gci" || "${MASTER_OS_DISTRIBUTION:-}" == "ubuntu" ]] || \
- [[ "${NODE_OS_DISTRIBUTION:-}" == "trusty" || "${NODE_OS_DISTRIBUTION:-}" == "gci" || "${NODE_OS_DISTRIBUTION:-}" == "ubuntu" || "${NODE_OS_DISTRIBUTION:-}" == "custom" ]] ; then
- if KUBE_MANIFESTS_TAR=$(find-tar kubernetes-manifests.tar.gz); then
- find_result=0
- else
- find_result=1
- fi
- export KUBE_MANIFESTS_TAR
- fi
- # the function result is used in function `verify-release-tars`
- if [[ $find_result == 0 ]]; then
- return 0
- else
- return 1
- fi
- }
- # Run the cfssl command to generates certificate files for etcd service, the
- # certificate files will save in $1 directory.
- #
- # Optional vars:
- # GEN_ETCD_CA_CERT (CA cert encode with base64 and ZIP compression)
- # GEN_ETCD_CA_KEY (CA key encode with base64)
- # ca_cert (require when GEN_ETCD_CA_CERT and GEN_ETCD_CA_KEY is set)
- # ca_key (require when GEN_ETCD_CA_CERT and GEN_ETCD_CA_KEY is set)
- # If GEN_ETCD_CA_CERT or GEN_ETCD_CA_KEY is not specified, it will generates certs for CA.
- #
- # Args:
- # $1 (the directory that certificate files to save)
- # $2 (the ip of etcd member)
- # $3 (the type of etcd certificates, must be one of client, server, peer)
- # $4 (the prefix of the certificate filename, default is $3)
- function generate-etcd-cert() {
- local cert_dir=${1}
- local member_ip=${2}
- local type_cert=${3}
- local prefix=${4:-"${type_cert}"}
- local GEN_ETCD_CA_CERT=${GEN_ETCD_CA_CERT:-}
- local GEN_ETCD_CA_KEY=${GEN_ETCD_CA_KEY:-}
- mkdir -p "${cert_dir}"
- pushd "${cert_dir}"
- kube::util::ensure-cfssl .
- if [ ! -r "ca-config.json" ]; then
- cat >ca-config.json <<EOF
- {
- "signing": {
- "default": {
- "expiry": "43800h"
- },
- "profiles": {
- "server": {
- "expiry": "43800h",
- "usages": [
- "signing",
- "key encipherment",
- "server auth",
- "client auth"
- ]
- },
- "client": {
- "expiry": "43800h",
- "usages": [
- "signing",
- "key encipherment",
- "client auth"
- ]
- },
- "peer": {
- "expiry": "43800h",
- "usages": [
- "signing",
- "key encipherment",
- "server auth",
- "client auth"
- ]
- }
- }
- }
- }
- EOF
- fi
- if [ ! -r "ca-csr.json" ]; then
- cat >ca-csr.json <<EOF
- {
- "CN": "Kubernetes",
- "key": {
- "algo": "ecdsa",
- "size": 256
- },
- "names": [
- {
- "C": "US",
- "L": "CA",
- "O": "kubernetes.io"
- }
- ]
- }
- EOF
- fi
- if [[ -n "${GEN_ETCD_CA_CERT}" && -n "${GEN_ETCD_CA_KEY}" ]]; then
- # ca_cert and ca_key are optional external vars supplied in cluster/gce/util.sh,
- # so it's ok to disable shellcheck here
- # shellcheck disable=SC2154
- echo "${ca_cert}" | base64 --decode | gunzip > ca.pem
- # shellcheck disable=SC2154
- echo "${ca_key}" | base64 --decode > ca-key.pem
- fi
- if [[ ! -r "ca.pem" || ! -r "ca-key.pem" ]]; then
- ${CFSSL_BIN} gencert -initca ca-csr.json | ${CFSSLJSON_BIN} -bare ca -
- fi
- case "${type_cert}" in
- client)
- echo "Generate client certificates..."
- echo '{"CN":"client","hosts":["*"],"key":{"algo":"ecdsa","size":256}}' \
- | ${CFSSL_BIN} gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client - \
- | ${CFSSLJSON_BIN} -bare "${prefix}"
- ;;
- server)
- echo "Generate server certificates..."
- echo '{"CN":"'"${member_ip}"'","hosts":[""],"key":{"algo":"ecdsa","size":256}}' \
- | ${CFSSL_BIN} gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="${member_ip},127.0.0.1" - \
- | ${CFSSLJSON_BIN} -bare "${prefix}"
- ;;
- peer)
- echo "Generate peer certificates..."
- echo '{"CN":"'"${member_ip}"'","hosts":[""],"key":{"algo":"ecdsa","size":256}}' \
- | ${CFSSL_BIN} gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=peer -hostname="${member_ip},127.0.0.1" - \
- | ${CFSSLJSON_BIN} -bare "${prefix}"
- ;;
- *)
- echo "Unknow, unsupported etcd certs type: ${type_cert}" >&2
- echo "Supported type: client, server, peer" >&2
- exit 2
- esac
- # the popd will access `directory stack`, no `real` parameters is actually needed
- # shellcheck disable=SC2119
- popd
- }
- # Check whether required binaries exist, prompting to download
- # if missing.
- # If KUBERNETES_SKIP_CONFIRM is set to y, we'll automatically download binaries
- # without prompting.
- function verify-kube-binaries() {
- if ! "${KUBE_ROOT}/cluster/kubectl.sh" version --client >&/dev/null; then
- echo "!!! kubectl appears to be broken or missing"
- download-release-binaries
- fi
- }
- # Check whether required release artifacts exist, prompting to download
- # if missing.
- # If KUBERNETES_SKIP_CONFIRM is set to y, we'll automatically download binaries
- # without prompting.
- function verify-release-tars() {
- if ! find-release-tars; then
- download-release-binaries
- fi
- }
- # Download release artifacts.
- function download-release-binaries() {
- get_binaries_script="${KUBE_ROOT}/cluster/get-kube-binaries.sh"
- local resp="y"
- if [[ ! "${KUBERNETES_SKIP_CONFIRM:-n}" =~ ^[yY]$ ]]; then
- echo "Required release artifacts appear to be missing. Do you wish to download them? [Y/n]"
- read -r resp
- fi
- if [[ "${resp}" =~ ^[nN]$ ]]; then
- echo "You must download release artifacts to continue. You can use "
- echo " ${get_binaries_script}"
- echo "to do this for your automatically."
- exit 1
- fi
- "${get_binaries_script}"
- }
- # Run pushd without stack output
- function pushd() {
- command pushd "$@" > /dev/null
- }
- # Run popd without stack output
- # the popd will access `directory stack`, no `real` parameters is actually needed
- # shellcheck disable=SC2120
- function popd() {
- command popd "$@" > /dev/null
- }
|