#!/bin/bash # ----------------------------------------------------------------------------- # Copyright © 2018 AT&T USA # # 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. # # ----------------------------------------------------------------------------- # # This script generates docker-compose volume overlay files from the oom # kubernetes configuration files. Multiple environments can be supported. By # default the environment is the 'local' environment and the docker-compose # file is named docker-compose-local.yml. This script only generates the # overlay files, not the docker-compose file. # # Overlay files contain the springboot configuration for each SO container. # # The idea here is that docker-compose is lighter weight than kubernetes with # rancher, and people will find it easier to use in a development environment. # Whenever the overlay files in oom are modified, this script can be used to # (re)build overlay files for the docker-compose environment. # # Reasonably up-to-date overlay files for the docker-compose environment may # be checked into the docker-config repository as a convenience to those who # don't want to (or can't) run this script. This script will refresh those. # # Example Workflow: # # 1) build SO software and docker images -or- pull SO docker images from nexus3 # # 2) Create configuration for 'local' environment: # ./create-configs.sh -e local -i -u rd472p -b master # # 3) Start the environment: # docker-compose -f docker-compose-local.yml up # function usage { echo "usage: $(basename $0) [-e env] [-i] [-u oom-git-user] [-b oom-git-branch]" echo "where -e specifies the environment name (default: 'local')" echo " -i re-initializes the staging directory (default: no)" echo " -u specifies the git user for cloning oom (default: current user)" echo " -b specifies the oom branch (default: current docker-config branch)" } # # Purpose: prompts for a yes/no (or equivalent) answer # Output: none # Return Code: 0 for yes, 1 for no # Usage: askConfirm prompt # function askConfirm { ask_prompt="$1" while : do echo -n "$ask_prompt" >> /dev/tty read ask_reply ask_reply=${ask_reply##+([[:space:]])}; ask_reply=${ask_reply%%+([[:space:]])} case "$ask_reply" in y | yes | Y | YES) return 0 ;; n | no | N | NO) return 1 ;; esac done } # # Purpose: performs a literal string replacement (no regexs) # Output: none, but modifies the specified file # Return Code: 0 for success, 1 for failure # Usage: replace source replacement file # function replace { local src=$1 local rpl=$2 local file=$3 if ! type xxd > /dev/null 2>&1 then echo "xxd: command not found" 1>&2 return 1 fi local xsrc=$(echo -n "$src" | xxd -p | tr -d '\n') local xrpl=$(echo -n "$rpl" | xxd -p | tr -d '\n') xxd -p $file | tr -d '\n' | sed "s/$xsrc/$xrpl/g" | xxd -p -r > $file.replace || return 1 mv $file.replace $file || return 1 return 0 } # # Purpose: converts a camel-case variable name to snake (upper) case # openStackUserName -> OPEN_STACK_USER_NAME # Output: the converted variable name # Usage: toSnake name # function toSnake { echo "$1" | sed -r 's/([A-Z])/_\L\1/g' | sed 's/^_//' | tr '[a-z]' '[A-Z]' } # # Purpose: lists all the environment variables in the specified docker # compose yaml for the specified container, e.g.: # VAR1=VALUE1 # VAR2=VALUE2 # ... # Output: the list of variable mappings # Usage: listEnv composeFile containerName # function listEnv { local composeFile=$1 local container=$2 local inContainer=FALSE local inEnvironment=FALSE while read line do if [[ $line == "$container:" ]] then inContainer=TRUE elif [[ $inContainer == TRUE && $line == "environment:" ]] then inEnvironment=TRUE else if [[ $inEnvironment == TRUE ]] then if [[ ${line:0:1} == "-" ]] then echo "$line" else break fi fi fi done < $composeFile | sed -e "s/^- '//" -e "s/'$//" } # # Purpose: tests if the specified environment variable is defined in the # docker compose yaml for the specified container. # Output: none # Return Code: 0 if the variable exists, 1 if it doesn't # Usage: varExists composeFile containerName variableName # function varExists { local composeFile=$1 local container=$2 local var=$3 listEnv $composeFile $container | grep "^$var=" > /dev/null return $? } # # Purpose: returns the value of the specified environment variable # from the compose yaml for the specified container. # Output: the variable value (empty if it isn't defined) # Usage: varValue composeFile containerName variableName # function varValue { local composeFile=$1 local container=$2 local var=$3 listEnv $composeFile $container | grep "^$var=" | cut -d= -f2 } ### MAIN CODE STARTS HERE if [[ ! -d volumes/so ]] then echo "You must run this command in the docker-config directory" 1>&2 exit 1 fi ENV=local INIT=FALSE GITUSER=$(id -un) GITBRANCH=$(git rev-parse --abbrev-ref HEAD) while getopts :e:iu:b: c do case "$c" in e) ENV=$OPTARG ;; i) INIT=TRUE ;; u) GITUSER=$OPTARG ;; b) GITBRANCH=$OPTARG ;; *) usage 1>&2 exit 1 ;; esac done shift $(($OPTIND - 1)) if [[ $# != 0 ]] then usage 1>&2 exit 1 fi if [[ ! -f docker-compose-$ENV.yml ]] then echo "No such file: docker-compose-$ENV.yml" 1>&2 exit 1 fi mkdir -p staging if [[ -d staging && $INIT == TRUE ]] then if ! askConfirm "Delete existing staging directory? " then exit 1 fi rm -fr staging || exit 1 fi mkdir -p staging || exit 1 # Get the oom repository from gerrit. if [[ -d staging/oom ]] then cd staging/oom || exit 1 branch=$(git rev-parse --abbrev-ref HEAD) if [[ $branch != $GITBRANCH ]] then echo "staging/oom is not on branch '$GITBRANCH'" 1>&2 exit 1 fi cd ../.. || exit 1 else cd staging || exit 1 echo "Cloning into staging/oom" git clone https://$GITUSER@gerrit.onap.org/r/a/oom || exit 1 cd oom || exit 1 branch=$(git rev-parse --abbrev-ref HEAD) if [[ $branch != $GITBRANCH ]] then if [[ $(git ls-remote origin $GITBRANCH | wc -l) == 0 ]] then echo "staging/oom has no '$GITBRANCH' branch" 1>&2 exit 1 fi echo "Switching staging/oom to '$GITBRANCH' branch" git checkout -b $GITBRANCH remotes/origin/$GITBRANCH || exit 1 fi cd ../.. || exit 1 fi kso=staging/oom/kubernetes/so if [[ ! -d $kso ]] then echo "No such directory: $kso" 1>&2 exit 1 fi if [[ ! -d staging/volumes/so/config ]] then mkdir -p staging/volumes/so/config fi stagedTargets= for override in $(cd $kso && find * -name 'override.yaml') do subdir=${override%%/*} if [[ $subdir == resources ]] then container=so-api-handler-infra elif [[ $subdir == charts ]] then container=${override#charts/} container=${container%%/*} fi if [[ $container != so-monitoring ]] then container=${container#so-} fi target=staging/volumes/so/config/$container/$ENV/override.yaml if [[ ! -f $target ]] then mkdir -p $(dirname $target) || exit 1 cp $kso/$override $target.tmp || exit 1 if ! varExists docker-compose-$ENV.yml $container COMMON_NAMESPACE then echo "ERROR: no COMMON_NAMESPACE variable is defined in docker-compose-$ENV.yml for container $container" 1>&2 exit 1 fi replace '{{ include "common.namespace" . }}' '${COMMON_NAMESPACE}' $target.tmp || exit 1 if ! varExists docker-compose-$ENV.yml $container CONTAINER_PORT then echo "ERROR: no CONTAINER_PORT variable is defined in docker-compose-$ENV.yml for container $container" 1>&2 exit 1 fi replace '{{ index .Values.containerPort }}' '${CONTAINER_PORT}' $target.tmp || exit 1 for configValue in $(grep "{{ \.Values\.config\..*}}" $target.tmp | cut -d'{' -f3 | cut -d'}' -f1 | tr -d ' ' | sed 's/.Values.config.//' | sort -u) do var=$(toSnake $configValue) if ! varExists docker-compose-$ENV.yml $container $var then echo "ERROR: no $var variable is defined in docker-compose-$ENV.yml for container $container" 1>&2 exit 1 fi if [[ ${var:0:11} == "OPEN_STACK_" ]] then # Workaround for variables in the openstack # adapter cloud configuration. The override # yaml is read by a migration program that # doesn't expand variables, so we need to # substitute the variable values here. value=$(varValue docker-compose-$ENV.yml $container $var) replace "{{ .Values.config.$configValue }}" "$value" $target.tmp || exit 1 else replace "{{ .Values.config.$configValue }}" '${'$var'}' $target.tmp || exit 1 fi done if grep "{{" $target.tmp > /dev/null then echo "ERROR: Unresolved placeholders in $kso/$override:" 1>&2 grep "{{.*}}" $target.tmp | cut -d'{' -f3 | cut -d'}' -f1 | sed -e 's/^/ {{/' -e 's/$/}}/' | sort -u 1>&2 exit 1 fi mv $target.tmp $target || exit 1 echo "Created $target" stagedTargets="$stagedTargets target" fi done for override in $(cd staging && find volumes -name 'override.yaml') do dir=$(dirname $override) mkdir -p $dir || exit 1 cp staging/$override $override || exit 1 echo "Installed $override" done echo "SUCCESS"