#!/usr/bin/env bash shopt -s extglob nullglob profile_name_for () { local root_profile="${1}" env="${2}" if [[ $env == "root" ]] then echo "${root_profile}" else echo "${root_profile}-${env}" fi } apply () { terraform apply ${@-} "plan" && rm "plan" } # # V1 # onboard () { local root_profile profile echo "What AWS profile would you like to use as your root profile?" read -p "> " root_profile echo echo $root_profile > .fenna/root_profile local backend_env=$(cat .fenna/backend/env) local backend_profile=$(profile_name_for $root_profile $backend_env) echo $backend_profile > .fenna/backend/profile if [[ -f ".fenna/sandbox" ]] then local suffix local sandbox_env=$(cat .fenna/sandbox) profile="${root_profile}-${sandbox_env}" echo "What suffix would you like to use to distinguish your resources in the sandbox?" read -p "> " suffix echo echo $suffix > .fenna/suffix touch "${sandbox_env}.tfvars" touch user.tfvars else local target_env=$(readlink .fenna/backend/current.tfvars | sed -e 's/\.\.\/backends\/\(.*\)\.tfvars/\1/') profile=$(profile_name_for $root_profile $target_env) fi echo $profile > .fenna/profile } init () { local backend_profile=$(cat .fenna/backend/profile) local suffix if [[ -f ".fenna/suffix" ]] then suffix=$(cat .fenna/suffix) fi if [[ -f ".fenna/sandbox" ]] && [[ ! -z "$suffix" ]] then terraform init \ -backend-config .fenna/backend/current.tfvars \ -backend-config "profile=${backend_profile}" \ -backend-config "key=$(cat .fenna/service_name)-${suffix}/terraform.tfstate" \ ${@-} else terraform init \ -backend-config .fenna/backend/current.tfvars \ -backend-config "profile=${backend_profile}" \ -backend-config "key=$(cat .fenna/service_name)/terraform.tfstate" \ ${@-} fi } plan () { local profile=$(cat .fenna/profile) local root_profile=$(cat .fenna/root_profile) local service_name=$(cat .fenna/service_name) if [[ -f ".fenna/sandbox" ]] then local sandbox_env=$(cat .fenna/sandbox) local suffix if [[ -f ".fenna/suffix" ]] then suffix=$(cat .fenna/suffix) fi terraform plan \ -var "profile=${profile}" \ -var "root_profile=${root_profile}" \ -var "service_name=${service_name}" \ -var "suffix=${suffix}" \ -var-file "${sandbox_env}.tfvars" \ -var-file "user.tfvars" \ -out "plan" \ ${@-} else terraform plan \ -var "profile=${profile}" \ -var "root_profile=${root_profile}" \ -var "service_name=${service_name}" \ -out "plan" \ ${@-} fi } # # V2 # v2_backends () { if [[ -d ".fenna/backends" ]] then local backends local paths paths=(.fenna/backends/*.tfvars) for path in "${paths[@]}"; do backends+=("$(sed -e 's/^.fenna\/backends\///' <<< "${path}" | sed -e 's/.tfvars$//')") done printf "%s\n" "${backends[@]}" fi } v2_targets () { if [[ -d ".fenna/targets" ]] then local targets local paths paths=(.fenna/targets/*) for path in "${paths[@]}"; do targets+=("$(sed -e 's/^.fenna\/targets\///' <<< "${path}")") done printf "%s\n" "${targets[@]}" fi } v2_set_target () { local name="${1}" rm -f .fenna/target ln -sf "targets/${name}" .fenna/target rm -f .terraform mkdir -p ".fenna/targets/${name}/.terraform" ln -sf ".fenna/targets/${name}/.terraform" .terraform echo "${name}" } v2_migrate () { cp -R .fenna .fenna-bak echo "2" > .fenna/version local backend backend=$(readlink .fenna/backend/current.tfvars | sed -e 's/\.\.\/backends\/\(.*\)\.tfvars/\1/') rm .fenna/backend/current.tfvars local target if [[ -f ".fenna/sandbox" ]] then target=$(cat .fenna/sandbox) rm .fenna/sandbox else target="${backend}" fi mkdir -p ".fenna/targets/${target}" mv .fenna/profile ".fenna/targets/${target}/profile" mv .fenna/backend ".fenna/targets/${target}/backend" ln -sf "../../../backends/${backend}.tfvars" ".fenna/targets/${target}/backend/config.tfvars" if [[ -f ".fenna/suffix" ]] then local suffix suffix=$(cat .fenna/suffix) if [[ -z "${suffix}" ]] then rm .fenna/suffix else mv .fenna/suffix ".fenna/targets/${target}/suffix" fi fi cp -R .terraform .terraform-bak mv .terraform ".fenna/targets/${target}/.terraform" rm .fenna/.gitignore cat > .fenna/.gitignore < fenna_variables.tf <> .gitignore *.sensitive.tfvars EOS touch "${target}.sensitive.tfvars" v2_set_target "${target}" } v2_configure_target () { local name="${1}" local root_profile root_profile=$(cat .fenna/root_profile) local backend_env backend_env=$(cat ".fenna/targets/${name}/backend/env") local backend_profile backend_profile=$(profile_name_for "${root_profile}" "${backend_env}") echo "$backend_profile" > ".fenna/targets/${name}/backend/profile" local target_env target_env=$(readlink ".fenna/targets/${name}/backend/config.tfvars" | sed -e 's/\.\.\/\.\.\/\.\.\/backends\/\(.*\)\.tfvars/\1/') local profile profile=$(profile_name_for "${root_profile}" "${target_env}") echo "$profile" > ".fenna/targets/${name}/profile" local suffix echo "What suffix would you like to use to distinguish your state and resources within this target?" read -rp "> " suffix echo if [[ -n "${suffix}" ]] then echo "${suffix}" > ".fenna/targets/${name}/suffix" fi } v2_target () { local name="${1}" if [[ -z "$name" ]] then if [[ -L ".fenna/target" ]] then basename "$(readlink .fenna/target)" fi return fi if [[ -d ".fenna/targets/${name}" ]] then if [[ -f ".fenna/targets/${name}/profile" ]] && [[ -f ".fenna/targets/${name}/backend/profile" ]] then v2_set_target "${name}" else v2_configure_target "${name}" v2_set_target "${name}" fi else mkdir -p ".fenna/targets/${name}/backend" mkdir ".fenna/targets/${name}/.terraform" local environments mapfile -t environments <<< "$(v2_backends)" local backend echo "Which backend would you like to use? [${environments[*]}]" read -rp "> " backend echo ln -sf "../../../backends/${backend}.tfvars" ".fenna/targets/${name}/backend/config.tfvars" local backend_env echo "Where is your backend stored? [${environments[*]})]" read -rp "> " backend_env echo echo "${backend_env}" > ".fenna/targets/${name}/backend/env" touch "${name}.tfvars" touch "${name}.sensitive.tfvars" v2_configure_target "${name}" v2_set_target "${name}" fi } v2_onboard () { local root_profile echo "What AWS profile would you like to use as your root profile?" read -rp "> " root_profile echo echo "${root_profile}" > .fenna/root_profile touch user.tfvars local targets mapfile -t targets <<< "$(v2_targets)" if [[ -n "${targets[*]}" ]] then for target in "${targets[@]}" do touch "${target}.sensitive.tfvars" done local target echo "Which target would you like to use? [${targets[*]}]" read -rp "> " target echo if [[ -n "${target}" ]] then v2_target "${target}" fi fi } v2_bootstrap () { if [[ ! -d ".fenna" ]] then mkdir -p .fenna/targets fi echo "2" > .fenna/version cat > .fenna/.gitignore < " service_name echo echo "${service_name}" > .fenna/service_name cat > fenna_variables.tf <> .gitignore *.tfstate* .terraform plan *.sensitive.tfvars user.tfvars EOS if [[ ! -d ".fenna/backends" ]] then local repository_url echo "What's your backend config repository's URL?" read -rp "> " repository_url echo git submodule add "${repository_url}" .fenna/backends echo fi v2_onboard } v2_init () { local backend_profile backend_profile=$(cat .fenna/target/backend/profile) local suffix if [[ -f ".fenna/target/suffix" ]] then suffix=$(cat .fenna/target/suffix) fi local state_key_root state_key_root=$(cat .fenna/service_name) if [[ -n "${suffix}" ]] then state_key_root="${state_key_root}-${suffix}" fi terraform init \ -backend-config .fenna/target/backend/config.tfvars \ -backend-config "profile=${backend_profile}" \ -backend-config "key=${state_key_root}/terraform.tfstate" \ ${@-} } v2_plan () { local profile profile=$(cat .fenna/target/profile) local root_profile root_profile=$(cat .fenna/root_profile) local service_name service_name=$(cat .fenna/service_name) local target target=$(readlink .fenna/target | sed -e 's/targets\/\(.*\)/\1/') local suffix if [[ -f ".fenna/target/suffix" ]] then suffix=$(cat .fenna/target/suffix) fi terraform plan \ -var "profile=${profile}" \ -var "root_profile=${root_profile}" \ -var "service_name=${service_name}" \ -var "suffix=${suffix}" \ -var-file "${target}.tfvars" \ -var-file "${target}.sensitive.tfvars" \ -var-file "user.tfvars" \ -out "plan" \ ${@-} } # # Usage # usage () { cat < [] bootstrap Configure a new service onboard Configure profiles for a bootstrapped service migrate Migrate from fenna v1 to v2 backends List available backends targets List available targets target Select a target or configure a new target init Run "terraform init" for the current target plan Run "terraform plan" for the current target apply Run "terraform apply" for the current target EOF } # # Dispatch # cmd="${1}" shift if [[ -f ".fenna/version" ]] then case "${cmd}" in backends) v2_backends ;; targets) v2_targets ;; bootstrap) v2_bootstrap ;; onboard) v2_onboard ;; target) v2_target "${1}" ;; init) v2_init "${@}" ;; plan) v2_plan "${@}" ;; apply) apply "${@}" ;; *) usage ;; esac else case "$cmd" in migrate) v2_migrate ;; bootstrap) v2_bootstrap ;; onboard) onboard ;; init) init "$@" ;; plan) plan "$@" ;; apply) apply "$@" ;; *) usage ;; esac fi