From 9732ec6988d2d441588a46c2163eaa46ed63a3a0 Mon Sep 17 00:00:00 2001 From: Sergey Dudoladov Date: Mon, 29 Jan 2018 16:59:25 +0100 Subject: [PATCH] Refactor code into separate functions --- run_locally.sh | 299 +++++++++++++++++++++++++++++++------------------ 1 file changed, 188 insertions(+), 111 deletions(-) diff --git a/run_locally.sh b/run_locally.sh index 66b23b71b..f77b50287 100755 --- a/run_locally.sh +++ b/run_locally.sh @@ -1,156 +1,233 @@ -#!/bin/bash +#!/usr/bin/env bash +# +# Deploy a Postgres operator to a minikube aka local Kubernetes cluster +# Optionally re-build the operator binary beforehand to test local changes -# unofficial bash strict mode w/o the -e option -# -e breaks "eval $cmd" in the retry function -set -uo pipefail + +# enable unofficial bash strict mode +set -o errexit +set -o nounset +set -o pipefail IFS=$'\n\t' -function retry(){ # timeouts after 1 minutes - cmd="$1" - retryMsg="$2" + +readonly PATH_TO_LOCAL_OPERATOR_MANIFEST="/tmp/local-postgres-operator.yaml" +readonly PATH_TO_PORT_FORWARED_KUBECTL_PID="/tmp/kubectl-port-forward.pid" +readonly LOCAL_PORT="8080" +readonly OPERATOR_PORT="8080" + + +# minikube needs time to create resources, +# so the script retries actions until all the resources become available +function retry(){ + + # errexit may break "eval $cmd", so we disable it temporarily + set +o errexit + + local cmd="$1" + local retry_msg="$2" + + # times out after 1 minute for i in {1..20}; do if eval "$cmd"; then + set -o errexit # enable again return 0 fi - echo "$retryMsg" + echo "$retry_msg" sleep 3 done + >2& echo "The command $cmd timed out" return 1 } -function build_operator_binary(){ - make tools > /dev/null 2>&1 && - make deps > /dev/null 2>&1 && - make local > /dev/null 2>&1 + +function build_operator_binary(){ + + # redirecting stderr greatly reduces non-informative output during normal builds + echo "Build operator binary (stderr redirected to /dev/null)..." + + make tools > /dev/null 2>&1 + make deps > /dev/null 2>&1 + make local > /dev/null 2>&1 } -# the fastest way to run your docker image locally is to reuse the docker from minikube. + function deploy_self_built_image() { echo "==== DEPLOY CUSTOM OPERATOR IMAGE ==== " - - echo "Build operator binary (stderr redirected to /dev/null)..." + build_operator_binary - # set docker env vars so that docker can talk to the Docker daemon inside the minikube VM + # the fastest way to run your docker image locally is to reuse the docker from minikube. + # set docker env vars so that docker can talk to the Docker daemon inside the minikube eval $(minikube docker-env) # image tag consists of a git tag or a unique commit prefix # and the "-dev" suffix if there are uncommited changes in the working dir - export TAG=$(git describe --tags --always --dirty="-dev") - + TAG=$(git describe --tags --always --dirty="-dev") + export TAG + # build the image - echo "Build the operator Docker image (stderr redirected to /dev/null)..." make docker > /dev/null 2>&1 # update the tag in the postgres operator conf - # since the image with this tag is already present on the machine, + # since the image with this tag already exists on the machine, # docker should not attempt to fetch it from the registry due to imagePullPolicy - file="/tmp/local-postgres-operator.yaml" - sed -e "s/\(image\:.*\:\).*$/\1$TAG/" manifests/postgres-operator.yaml > "$file" + sed --expression "s/\(image\:.*\:\).*$/\1$TAG/" manifests/postgres-operator.yaml > "$PATH_TO_LOCAL_OPERATOR_MANIFEST" - retry "kubectl create -f \"$file\"" "attempt to create $file resource" + retry "kubectl create -f \"$PATH_TO_LOCAL_OPERATOR_MANIFEST\"" "attempt to create $PATH_TO_LOCAL_OPERATOR_MANIFEST resource" } function display_help(){ echo "Usage: ./run_locally.sh [ -r | --rebuild-operator ] [ -h | --help ]" } -# parse options -should_build_operator=false -while true -do - case "${1:-''}" in # if 1st is usnet, use the mety string as a default value - - -h | --help) - display_help - exit 0 - ;; - -r | --rebuild-operator) - should_build_operator=true - shift 2 - break - ;; - --) shift - break;; - *) break - ;; - esac -done - - -echo "==== CLEAN UP PREVIOUS RUN ==== " - -status=$(minikube status --format "{{.MinikubeStatus}}") -if [ "$status" = "Running" ] || [ "$status" = "Stopped" ]; then - echo "Delete the existing local cluster so that we can cleanly apply resources from scratch..." - minikube delete -fi - -# the kubectl process does the port-forwarding between operator and local ports -# we restart the process to bind to the same port again (see end of script) -if [ -e /tmp/kubectl-port-forward.pid ]; then +function clean_up(){ - pid=$(cat /tmp/kubectl-port-forward.pid) - # the process will die if a minikube is stopped manually between two invocations of the script - if ps --pid "$pid" > /dev/null; then - echo "Kill the kubectl process responsible for port forwarding for minikube so that we can re-use the same ports for forwarding later..." - kill "$pid" + echo "==== CLEAN UP PREVIOUS RUN ==== " + + local status + status=$(minikube status --format "{{.MinikubeStatus}}" || true) + + if [[ "$status" = "Running" ]] || [[ "$status" = "Stopped" ]]; then + echo "Delete the existing local cluster so that we can cleanly apply resources from scratch..." + minikube delete fi - rm /tmp/kubectl-port-forward.pid -fi + if [[ -e "$PATH_TO_LOCAL_OPERATOR_MANIFEST" ]]; then + rm --verbose "$PATH_TO_LOCAL_OPERATOR_MANIFEST" + fi + + # the kubectl process does the port-forwarding between operator and local ports + # we restart the process to bind to the same port again (see end of script) + if [[ -e "$PATH_TO_PORT_FORWARED_KUBECTL_PID" ]]; then + + local pid + pid=$(cat "$PATH_TO_PORT_FORWARED_KUBECTL_PID") + + # the process dies if a minikube stops between two invocations of the script + if ps --pid "$pid" > /dev/null 2>&1; then + echo "Kill the kubectl process responsible for port forwarding for minikube so that we can re-use the same ports for forwarding later..." + kill "$pid" + fi + rm --verbose /tmp/kubectl-port-forward.pid -echo "==== START MINIKUBE ==== " -echo "May take a few minutes ..." -minikube start -kubectl config set-context minikube + fi +} -echo "==== MINIKUBE STATUS ==== " -minikube status +function start_minikube(){ + + echo "==== START MINIKUBE ==== " + echo "May take a few minutes ..." + + minikube start + kubectl config set-context minikube -echo "==== START OPERATOR ==== " -# the order of files is significant -for file in "configmap.yaml" "serviceaccount.yaml" -do - retry "kubectl create -f manifests/\"$file\"" "attempt to create $file resource" -done + echo "==== MINIKUBE STATUS ==== " + minikube status + +} + +function start_operator(){ + + echo "==== START OPERATOR ==== " + echo "Certain operations may be retried multiple times..." + + # the order of resource initialization is significant + local file + for file in "configmap.yaml" "serviceaccount.yaml" + do + retry "kubectl create -f manifests/\"$file\"" "attempt to create $file resource" + done + + if [[ "$should_build_operator" = true ]]; then + deploy_self_built_image + else + retry "kubectl create -f manifests/postgres-operator.yaml" "attempt to create /postgres-operator.yaml resource" + fi + + local msg="Wait for the postgresql custom resource definition to register..." + local cmd="kubectl get crd | grep --quiet 'postgresqls.acid.zalan.do'" + retry "$cmd" "$msg " + + kubectl create -f manifests/complete-postgres-manifest.yaml +} + +function forward_ports(){ + + echo "==== FORWARD OPERATOR PORT $OPERATOR_PORT TO LOCAL PORT $LOCAL_PORT ====" + + local operator_pod + operator_pod=$(kubectl get pod -l name=postgres-operator -o jsonpath={.items..metadata.name}) + + # runs in the background to keep current terminal responsive + # stdout redirect removes the info message about forwarded ports; the message sometimes garbles the cli prompt + kubectl port-forward "$operator_pod" "$LOCAL_PORT":"$OPERATOR_PORT" &> /dev/null & + + pgrep --newest "kubectl" > "$PATH_TO_PORT_FORWARED_KUBECTL_PID" +} + +function check_health(){ + + echo "==== RUN HEALTH CHECK ==== " + + local check_cmd="curl --location --silent http://127.0.0.1:$LOCAL_PORT/clusters &> /dev/null" + echo "Command for checking: $check_cmd" + local check_msg="Wait for port forwarding to take effect" + + if retry "$check_cmd" "$check_msg"; then + echo "==== SUCCESS: OPERATOR IS RUNNING ==== " + echo "To stop it cleanly, run 'minikube delete'" + else + >2& echo "==== FAILURE: OPERATOR DID NOT START OR PORT FORWARDING DID NOT WORK" + >2& echo "This *might* have left the minikube VM image in inconsistent state." + exit 1 + fi + +} + +function main(){ + + if ! [[ $(basename $PWD) == "postgres-operator" ]]; then + echo "Please execute the script only from the root directory of the Postgres opepator repo." + exit 1 + fi + + trap "echo 'If you observe issues with minikube VM not starting/not proceeding, consider deleting the .minikube dir and/or rebooting before re-running the script'" EXIT + + + local should_build_operator=false + while true + do + # if 1st param is unset, use the empty string as a default value + case "${1:-}" in + + -h | --help) + display_help + exit 0 + ;; + -r | --rebuild-operator) + should_build_operator=true + shift 2 || true + break + ;; + --) shift + break;; + *) break + ;; + esac + done + + clean_up + start_minikube + start_operator should_build_operator + forward_ports + check_health + + exit 0 +} -if [ "$should_build_operator" = true ]; then - deploy_self_built_image -else - retry "kubectl create -f manifests/postgres-operator.yaml" "attempt to create /postgres-operator.yaml resource" -fi - -msg="Wait for the postgresql custom resource definition to register..." -cmd="kubectl get crd | grep --quiet 'postgresqls.acid.zalan.do'" -retry "$cmd" "$msg " - -kubectl create -f manifests/complete-postgres-manifest.yaml - -localPort="8080" -operatorPort="8080" -echo "==== FORWARD OPERATOR PORT $operatorPort TO LOCAL PORT $localPort ====" -operatorPod=$(kubectl get pod -l name=postgres-operator -o jsonpath={.items..metadata.name}) -# runs in the background to keep current terminal responsive -# stdout redirect removes the info message about forwarded ports; the message sometimes garbles the cli prompt -kubectl port-forward "$operatorPod" "$localPort":"$operatorPort" &> /dev/null & -pgrep --newest "kubectl" > /tmp/kubectl-port-forward.pid - -echo "==== RUN HEALTH CHECK ==== " -checkCmd="curl --location --silent http://127.0.0.1:$localPort/clusters &> /dev/null" -echo "Command for checking: $checkCmd" -checkMsg="Wait for port forwarding to take effect" - -if retry "$checkCmd" "$checkMsg" ; then - echo "==== SUCCESS: OPERATOR IS RUNNING ==== " - echo "To stop it cleanly, run 'minikube delete'" -else - echo "==== FAILURE: OPERATOR DID NOT START OR PORT FORWARDING DID NOT WORK" - echo "This *might* have left the minikube VM image in inconsistent state." - echo "If you observe strange issues, try deleting .minikube dir and re-running the script" - exit 1 -fi +main "$@"