diff --git a/cf-onprem b/cf-onprem index 0f4eccc..0f5ebcc 100755 --- a/cf-onprem +++ b/cf-onprem @@ -3,53 +3,34 @@ #set -x -msg() { echo -e "\e[32mINFO [$(date +%F\ %T)] ---> $1\e[0m"; } -warning() { echo -e "\e[33mWARNING [$(date +%F\ %T)] ---> $1\e[0m"; } -err() { echo -e "\e[31mERR [$(date +%F\ %T)] ---> $1\e[0m" ; exit 1; } - if [ -f "./env-vars" ]; then . ./env-vars fi +source scripts/helpers.sh + +OS=$(uname -s) readonly HELM_VERSION="${CF_HELM_VERSION:-2.10.0}" readonly CHANNEL="${CF_HELM_CHANNEL:-dev}" readonly CODEFRESH_REPOSITORY=http://charts.codefresh.io/${CHANNEL} - -#export KUBECONFIG=./.kube/config - readonly WORKING_DIR="$(dirname "$0")" readonly SERVICE_ACCOUNT="${WORKING_DIR}/sa.json" readonly VALUES_FILE="${WORKING_DIR}/values.yaml" readonly DOCKER_CFG_YAML="${WORKING_DIR}/dockercfg.yaml" -#readonly SECRET_VALUES_FILE="${WORKING_DIR}/values-dec.yaml" readonly WEBTLS_VALUES_FILE="${WORKING_DIR}/webtls.yaml" -usage() { +function msg() { echo -e "\e[32mINFO [$(date +%F\ %T)] ---> $1\e[0m"; } +function warning() { echo -e "\e[33mWARNING [$(date +%F\ %T)] ---> $1\e[0m"; } +function err() { echo -e "\e[31mERR [$(date +%F\ %T)] ---> $1\e[0m" ; exit 1; } + +function usage() { echo "$0 [-h] [-y|--yes|--web-tls-key|--web-tls-cert]" exit 0 } -check() { command -v $1 >/dev/null 2>&1 || err "$1 binary is required!"; } +function ver() { printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' ' '); } -ver() { printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' ' '); } - -exists() { - if command -v $1 >/dev/null 2>&1; then - msg "$1 binary installed" - else - warning "Please install $1 to proceed" - exit 1 - fi -} - -run_as_root() { - if [[ $EUID > 0 ]]; then - err "Please run as root/sudo" - exit 1 - fi -} - -approveContext() { +function userConfirmContext() { msg "Your kubectl is configured with the following context: " kubectl config current-context read -r -p "Are you sure you want to continue? [y/N] " response @@ -63,15 +44,49 @@ approveContext() { fi } -checkHelmInstalled() { - if command -v $1 >/dev/null 2>&1; then +function handleArgs() { + [ "$1" == "-h" ] && usage + while [[ $1 =~ ^(-(y)|--(yes|web-tls-key|web-tls-cert|set)) ]] + do + key=$1 + value=$2 + case $key in + -y|--yes) + CONFIRM_FLAG="true" + ;; + --web-tls-key) + WebTlsKey="$value" + shift + ;; + --web-tls-cert) + WebTlsCert="$value" + shift + ;; + --set) + SET_VALUES="$SET_VALUES --set $value" + shift + ;; + esac + shift + done + + if [[ -n "${WebTlsKey}" ]] || [[ -n "${WebTlsCert}" ]]; then + [[ -z "${WebTlsKey}" ]] || [[ -z "${WebTlsCert}" ]] && err "Please specify both --web-tls-cert and --web-tls-key arguments" + [[ ! -f "${WebTlsKey}" ]] && err "${WebTlsKey} file path not found. Please define correct path to the private key file." + [[ ! -f "${WebTlsCert}" ]] && err "${WebTlsCert} file path not found. Please define correct path to the certificate full chain file." + CUSTOM_TLS_CONF=1 + fi +} + +function checkHelmInstalled() { + if command -v helm >/dev/null 2>&1; then helm_version=$(helm version --client --short | sed 's/.*\: v//' | sed 's/+.*//') msg "helm is already installed and has version v$helm_version" [ $(ver $helm_version) -lt $(ver $HELM_VERSION) ] && \ err "You have older helm version than required. Please upgrade to v$HELM_VERSION or newer !" else warning "helm is not installed" - if [[ ! "$YES" == 'true' ]]; then + if [[ ! "$CONFIRM_FLAG" == 'true' ]]; then read -p "Do you want to install helm ? [y/n] " yn case ${yn} in y|Y) @@ -88,35 +103,14 @@ checkHelmInstalled() { fi } -helmInstall() { - msg "Downloading and installing helm..." -<< //// - case "$(uname -s)" in - Linux) - os=linux - ;; - Darwin) - os=darwin - ;; - *) - ;; - esac -//// - wget https://storage.googleapis.com/kubernetes-helm/helm-v${HELM_VERSION}-${os}-amd64.tar.gz -P /tmp/ - tar xvf /tmp/helm-v${HELM_VERSION}-${os}-amd64.tar.gz -C /tmp/ - chmod +x /tmp/${os}-amd64/helm - sudo mv /tmp/${os}-amd64/helm /usr/local/bin/ - rm -rf /tmp/helm-v${HELM_VERSION}-${os}-amd64 /tmp/helm-v${HELM_VERSION}-${os}-amd64.tar.gz -} - -checkTillerInstalled() { +function checkTillerInstalled() { status=$(kubectl -nkube-system get pod -l app=helm -l name=tiller -o=go-template --template='{{ range $i, $v := .items }}{{ if eq $v.status.phase "Running" }}{{ $v.status.phase }}{{ end }}{{ end }}') if [ "$status" == "Running" ]; then msg "Tiller is installed and running" helm init -c helm_version=$(helm version --client --short | sed 's/.*\: v//' | sed 's/+.*//') tiller_version=$(helm version --server --short | sed 's/.*\: v//' | sed 's/+.*//') - if [[ ! "$YES" == 'true' ]] && [ $(ver $tiller_version) -lt $(ver $helm_version) ]; then + if [[ ! "$CONFIRM_FLAG" == 'true' ]] && [ $(ver $tiller_version) -lt $(ver $helm_version) ]; then warning "You're running helm v$helm_version but tiller has v$tiller_version." read -p " Do you want to upgrade tiller to v$helm_version ? [y/n] " yn case ${yn} in @@ -129,12 +123,12 @@ checkTillerInstalled() { ;; esac fi - if [[ "$YES" == 'true' ]] && [ $(ver $tiller_version) -lt $(ver $helm_version) ]; then + if [[ "$CONFIRM_FLAG" == 'true' ]] && [ $(ver $tiller_version) -lt $(ver $helm_version) ]; then err "You're running helm v$helm_version but tiller has v$tiller_version . You need to upgrade tiller ! Exiting..." fi else warning "Unable to determine tiller at its default location." - if [[ ! "$YES" == 'true' ]]; then + if [[ ! "$CONFIRM_FLAG" == 'true' ]]; then read -p " Do you want to deploy tiller ? [y/n] " yn case ${yn} in y|Y) @@ -154,7 +148,7 @@ checkTillerInstalled() { } -checkTillerStatus() { +function checkTillerStatus() { while true; do status=$(kubectl -nkube-system get pod -l app=helm -l name=tiller -o=go-template --template='{{ range $i, $v := .items }}{{ if eq $v.status.phase "Running" }}{{ $v.status.phase }}{{ end }}{{ end }}') @@ -167,13 +161,39 @@ checkTillerStatus() { done } -generateWebTlsValuesFile() { +function runPreInstallChecks() { + msg "Checking if the Codefresh SA file is present..." + + msg "Checking helm binary on your system" + checkHelmInstalled + + msg "Checking if tiller is installed on kubernetes cluster" + checkTillerInstalled + + msg "Checking tiller status..." + checkTillerStatus + +} + +function helmInstall() { + OS=$(echo $OS | tr "[:upper:]" "[:lower:]") + msg "Downloading and installing helm..." + + wget https://storage.googleapis.com/kubernetes-helm/helm-v${HELM_VERSION}-${OS}-amd64.tar.gz -P /tmp/ + tar xvf /tmp/helm-v${HELM_VERSION}-${OS}-amd64.tar.gz -C /tmp/ + chmod +x /tmp/${OS}-amd64/helm + sudo mv /tmp/${OS}-amd64/helm /usr/local/bin/ + rm -rf /tmp/helm-v${HELM_VERSION}-${OS}-amd64 /tmp/helm-v${HELM_VERSION}-${OS}-amd64.tar.gz +} + +function generateWebTlsValuesFile() { + msg "Generating TLS values file..." -WEBTLSKEY=$(cat ${WebTlsKey} | sed 's/^/ /') -WEBTLSCERT=$(cat ${WebTlsCert} | sed 's/^/ /') + WEBTLSKEY=$(cat ${WebTlsKey} | sed 's/^/ /') + WEBTLSCERT=$(cat ${WebTlsCert} | sed 's/^/ /') -WEBTLSKEY_CFUI=$(cat ${WebTlsKey} | sed 's/^/ /') -WEBTLSCERT_CFUI=$(cat ${WebTlsCert} | sed 's/^/ /') + WEBTLSKEY_CFUI=$(cat ${WebTlsKey} | sed 's/^/ /') + WEBTLSCERT_CFUI=$(cat ${WebTlsCert} | sed 's/^/ /') cat <<-EOF >${WEBTLS_VALUES_FILE} --- @@ -194,88 +214,19 @@ EOF # exit 0 } -[ "$1" == "-h" ] && usage - -# run_as_root +function generateDockerValuesFile(){ -while [[ $1 =~ ^(-(y)|--(yes|web-tls-key|web-tls-cert|set)) ]] -do - key=$1 - value=$2 - case $key in - -y|--yes) - YES="true" - ;; - --web-tls-key) - WebTlsKey="$value" - shift - ;; - --web-tls-cert) - WebTlsCert="$value" - shift - ;; - --set) - SET_VALUES="$SET_VALUES --set $value" - shift - ;; - esac - shift # past argument or value -done - -os= - -case "$(uname -s)" in - Linux) - os=linux - ;; - Darwin) - os=darwin - ;; - *) - ;; -esac + DOCKER_CFG_JSON=$(cat ${SERVICE_ACCOUNT}) -msg "Starting on-prem Codefresh deployment" - -if [[ ! "$YES" == 'true' ]]; then - approveContext -else - msg "Your kubectl is configured with the following context: " - kubectl config current-context -fi - -#if [ -n "${WebTlsKey}" ] && [ -z "${WebTlsCert}" ]; then -#if [ -z "${WebTlsKey}" ] && [ -n "${WebTlsCert}" ]; then -[ -n "${WebTlsKey}" ] && [ -z "${WebTlsCert}" ] && err "Please specify --web-tls-cert argument" -[ -n "${WebTlsKey}" ] && [ ! -f "${WebTlsKey}" ] && err "${WebTlsKey} file path not found. Please define correct path to the private key file." -[ -z "${WebTlsKey}" ] && [ -n "${WebTlsCert}" ] && err "Please specify --web-tls-key argument" -[ -n "${WebTlsCert}" ] && [ ! -f "${WebTlsCert}" ] && err "${WebTlsCert} file path not found. Please define correct path to the certificate full chain file." -[ -n "${WebTlsKey}" ] && [ -f "${WebTlsKey}" ] && [ -n "${WebTlsCert}" ] && [ -f "${WebTlsCert}" ] && generateWebTlsValuesFile - -msg "Checking helm binary on your system" -checkHelmInstalled "helm" - -msg "Checking if tiller is installed on kubernetes cluster" -checkTillerInstalled - -msg "Checking tiller status..." -checkTillerStatus - -msg "Adding Helm repo..." -#addHelmCodefreshRepo -helm repo add codefresh-onprem-${CHANNEL} "${CODEFRESH_REPOSITORY}" - -DOCKER_CFG_JSON=$(cat ${SERVICE_ACCOUNT}) - -if [ $os == "linux" ]; then - BASE64="base64 -w0" -else - BASE64="base64" -fi + if [ $OS == "Linux" ]; then + BASE64="base64 -w0" + else + BASE64="base64" + fi -DOCKER_CFG_VAR=$(echo -n "_json_key:${DOCKER_CFG_JSON}" | $BASE64) + DOCKER_CFG_VAR=$(echo -n "_json_key:${DOCKER_CFG_JSON}" | $BASE64) -cat <${DOCKER_CFG_YAML} + cat <${DOCKER_CFG_YAML} --- dockerconfigjson: auths: @@ -307,14 +258,110 @@ cfanalytic: auth: ${DOCKER_CFG_VAR} EOF +} + +function configureDeployment() { + [ -n "$CUSTOM_TLS_CONF" ] && generateWebTlsValuesFile && WEBTLS_VALUES="--values ${WEBTLS_VALUES_FILE}" + generateDockerValuesFile + msg "Adding Helm repo..." + helm repo add codefresh-onprem-${CHANNEL} "${CODEFRESH_REPOSITORY}" +} + +function validateInputValues() { + + local valuesParsed + local key + local value + + set -f + + mapfile -t valuesParsed < <(parse_yaml values.yaml) + + for key_value in "${valuesParsed[@]}"; do + key=$(echo $key_value | cut -d '=' -f 1) + value=$(echo $key_value | cut -d '=' -f 2) + + case $key in + global_appProtocol) + regexMatch $value 'http|https' + ;; + global_appUrl) + echo $value + regexMatch $value $dnsRegexp + ;; + firebaseSecret) + [[ $(echo $value | wc -c) == 41 ]] || err "Firebase token is invalid: must be 41 characters long" + ;; + rbacEnable) + regexMatch $value '^true$|^false$' "$key flag must be either true or false" + ;; + ingress_domain) + regexMatch $value $dnsRegexp + ;; + cfapi_rbacEnable) + ;; + webTLS_secretName) + ;; + backups_enabled) + regexMatch $value '^true$|^false$' "$key flag must be either true or false" + ;; + backups_awsAccessKey) + [[ $(echo $value | wc -c) == 21 ]] || err "AWS access key ID is invalid: must be 21 characters long" + ;; + backups_awsSecretAccessKey) + [[ -n $key ]] || err "AWS access key must not be empty" + ;; + backups_s3Url) + regexMatch $value "^s3:\/\/" || err "Backups S3 URL is invalid. Pattern should be s3://" + ;; + mongodb_persistence_enabled) + regexMatch $value '^true$|^false$' "$key flag must be either true or false" + ;; + + # ... further checks later + esac + done + +} + +function validateConfiguration() { + local valuesParsed + local key + local value + + set -f + + mapfile -t valuesParsed < <(parse_yaml values.yaml) + + declare -A valuesMap + for key_value in "${valuesParsed[@]}"; do + key=$(echo $key_value | cut -d '=' -f 1) + value=$(echo $key_value | cut -d '=' -f 2) + valuesMap[$key]=$value + done + + if [[ ${valuesMap[backups_enabled]} == true ]]; then + [[ -z ${valuesMap[backups_awsAccessKey]} ]] || [[ -z ${valuesMap[backups_awsSecretAccessKey]} ]] || [[ -z ${valuesMap[backups_s3Url]} ]] && err "In case if backups_enabled is true, all the related values must be provided" + fi + # ... further checks later +} + +handleArgs $@ +runPreInstallChecks +validateInputValues +configureDeployment +validateConfiguration + +msg "Starting on-prem Codefresh deployment" + +[ "$CONFIRM_FLAG" == 'true' ] || userConfirmContext + #MTU_VALUE="--set global.mtu=$(cat /sys/class/net/cni0/mtu)" #TIMESTAMP=$(date +%F_%H-%M-%S) # --values "${SECRET_VALUES_FILE}" \ # --version 0.6.62 \ # --force \ -[ -n "${WebTlsKey}" ] && [ -f "${WebTlsKey}" ] && [ -n "${WebTlsCert}" ] && [ -f "${WebTlsCert}" ] && [ -f "${WEBTLS_VALUES_FILE}" ] && WEBTLS_VALUES="--values ${WEBTLS_VALUES_FILE}" - cf_status=$(helm ls -q cf) [ -z "${cf_status}" ] && SEEDJOBS="--set global.seedJobs=true" && CERTJOBS="--set global.certsJobs=true" diff --git a/scripts/helpers.sh b/scripts/helpers.sh new file mode 100755 index 0000000..3236ffb --- /dev/null +++ b/scripts/helpers.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +function parse_yaml { + local prefix=$2 + local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034') + sed -ne "s|^\($s\):|\1|" \ + -e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \ + -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" $1 | + awk -F$fs '{ + indent = length($1)/2; + vname[indent] = $2; + for (i in vname) {if (i > indent) {delete vname[i]}} + if (length($3) > 0) { + vn=""; for (i=0; i