Files

411 lines
11 KiB
Bash
Executable File

#!/usr/bin/env zsh
#
local debug=${DEBUG}
local playbook_filename="main.yml"
local playbook_dir=
local inventory=
local template_dir=
local template_repo=
local template_repo_version=
local quiet=
# Bold Colors
local BLUE='\x1b[34;1m'
local GREEN='\x1b[32;1m'
local RED='\x1b[31;1m'
local NOCOLOR='\033[0m'
########################## UTILS #########################
function print_color {
local color=$1
local string=$2
shift;shift;
printf "%s$color$string$NOCOLOR$@"
}
function debug_print() {
local label=$1
shift
local rest="$@"
[ ! "$debug" = "" ] && print_color $BLUE "$label " && print_color $NOCOLOR "$rest\n"
}
function fail() {
print_color $RED "ERROR: " && print_color $NOCOLOR "$1\n" && exit 1
}
function set_verbose() {
if [ ! "$1" = "" ]; then
debug="1"
fi
}
function set_quiet() {
if [ ! "$1" = "" ]; then
debug=
quiet="1"
fi
}
function load_config() {
local configs=(
"$HOME/.hparc"
$(find "$XDG_CONFIG_HOME/hpa-playbook/" -type f -maxdepth 1 -mindepth 1 -print0)
"${HPA_CONFIG_DIR}"
"$PWD/.hparc"
)
for f in ${configs[@]}; do
[ -f "$f" ] && source "$f" && debug_print "Load Config:" "sourced config: $f"
done
}
# NOTE: Assumes playbook_dir and inventory have been setup.
function run_playbook() {
if [ "$quiet" = "" ]; then
ansible-playbook "$playbook_dir/$playbook_filename" \
--inventory "$inventory" \
"${HPA_DEFAULT_PLAYBOOK_ARGS}" \
"$@"
else
ansible-playbook "$playbook_dir/$playbook_filename" \
--inventory "$inventory" \
"${HPA_DEFAULT_PLAYBOOK_ARGS}" \
"$@" 2>&1 1>/dev/null
fi
}
function parse_opt_or_env_var {
local opt=$1
local env=$2
if [ ! "$opt" = "" ]; then
echo $opt
elif [ ! "$env" = "" ]; then
echo $env
fi
}
function parse_playbook_dir_or_fail() {
local label="Parse Playbook:"
local parsed=$(parse_opt_or_env_var $1 ${HPA_PLAYBOOK_DIR})
[ "$parsed" = "" ] && fail "$label playbook directory not found."
if [ -f "$parsed" ]; then
playbook_dir=$(dirname "$parsed")
elif [ -d "$parsed" ]; then
playbook_dir=$parsed
else
fail "$label playbook directory not found."
fi
}
# NOTE: assumes playbook_dir has been set.
function parse_inventory_or_fail() {
local label="Parse Inventory:"
debug_print $label "opt: '$1'"
local parsed=$(parse_opt_or_env_var $1 ${HPA_DEFAULT_INVENTORY})
debug_print $label "parsed opt or env: '$parsed'"
if [ ! "$parsed" = "" ]; then
[ ! -f "$parsed" ] && fail "$label inventory is not a file."
debug_print $label "using parsed inventory."
inventory=$parsed
elif [ -f "$playbook_dir/inventory.ini" ]; then
debug_print $label "using default playbook option."
inventory="$playbook_dir/inventory.ini"
else
fail "$label failed to find inventory file."
fi
}
# NOTE: assumes load_config has been called.
function parse_template_dir() {
template_dir=$(parse_opt_or_env_var $1 ${HPA_TEMPLATE_DIR})
}
# NOTE: assumes load_config has been called.
function parse_repo_or_fail() {
local label="Parse Repo:"
template_repo=$(parse_opt_or_env_var $1 ${HPA_TEMPLATE_REPO})
if [ "$template_repo" = "" ]; then
fail "$label failed to find template repo."
fi
}
# NOTE: assumes load_config has been called.
function parse_repo_version_or_fail() {
local label="Parse Repo Version:"
template_repo_version=$(parse_opt_or_env_var $1 ${HPA_TEMPLATE_VERSION})
if [ "$template_repo_version" = "" ]; then
fail "$label failed to find template repo version."
fi
}
function setup_command() {
local label=$1
local verbose=$2
local quietOpt=$3
local playbookOpt=$4
local inventoryOpt=$5
set_verbose $verbose
set_quiet $quietOpt
parse_playbook_dir_or_fail "$playbookOpt"
parse_inventory_or_fail "$inventoryOpt"
debug_print "$label" "playbook dir: '$playbook_dir'"
debug_print "$label" "inventory: '$inventory'"
}
########################## SUBCOMMANDS #########################
function create_project() {
function usage() {
cat <<EOF
Setup a project from a template or repo.
This script calls the ansible-hpa-playbook that sets up a new project from the supplied template or repo.
Or will read from a configuration file what defaults to use.
Usage: hpa setup-project [Options [GlobalOptions]] <project-dir> [playbook-args...]
Where:
project-dir : The directory to generate the project in (required).
playbook-args : Extra arguments passed after the project directory get passed directly to the ansible-playbook command.
Options:
-b | --branch : The repo branch to clone (ignored if the -t option is used).
-r | --repo : A template repo to use and clone into the project (ignored if the -t option is used).
-t | --template : A local template / repo to use without cloning.
-v | --version : The version of the repo to clone (ignored if the -t option is used).
Flags:
-l | --local-template-dir : Force using local template dir, generally used when config holds the information for where to
locate the template directory on the system.
Global Options:
-i | --inventory : A custom ansible inventory file to use (optional if calling this script from the playbook directory).
-p | --playbook : Path to the ansible-hpa-playbook (optional if calling this script from the playbook directory).
-q | --quiet : Surpress ansible output to only errors and warnings.
Global Flags:
-h | --help : Show this help page.
--verbose : Increase log output.
Examples:
# Setup a project for super-customer using a local template directory.
$ hpa setup-project --template ~/projects/my-template ~/consults/super-customer --ask-vault-pass
# Setup a project for super-customer using a template repo.
$ hpa setup-project --repo "https://git.example.com/my-template.git" --branch "main" ~/consults/super-customer --ask-vault-pass
EOF
}
local label="Setup Project:"
local setup_args=("--tags" "setup-project")
zparseopts -D -E - \
p:=playbookOpt -playbook:=playbookOpt \
i:=inventoryOpt -inventory:=inventoryOpt \
t:=template -template-dir:=template \
r:=repo -repo:=repo \
v:=version -version:=version \
b:=version -branch:=version \
h=help -help=help \
l=localTemplateDir -local-template-dir=localTemplateDir \
-verbose=verbose \
q=quietOpt -quiet=quietOpt
# exit early and show help
[ ! "$help" = "" ] && usage && exit 0
setup_command $label $verbose $quietOpt \
${playbookOpt[-1]} ${inventoryOpt[-1]}
local project_dir="$1"
[ "$project_dir" = "" ] && fail "Setup Project: project directory not supplied"
setup_args+=("--extra-vars" "project_dir=$project_dir")
shift;
parse_template_dir "${template[-1]}"
local json=
if [ ! "$localTemplateDir" = "" ]; then
debug_print $label "parsed template dir: '$template_dir'"
if [ "$template_dir" = "" ]; then
fail "$label failed to find template directory."
fi
json="{'template': {'path': '"$template_dir"'}}"
else
parse_repo_or_fail ${repo[-1]}
parse_repo_version_or_fail ${version[-1]}
debug_print $label "parsed repo: '$template_repo'"
debug_print $label "parsed repo version: '$template_repo_version'"
json="{'template': {'repo': {'url': '"$template_repo"', 'version': '"$template_repo_version"' }}}"
fi
debug_print "$label" "json: $json"
setup_args+=("--extra-vars" "$json")
run_playbook "${setup_args[@]}" "$@"
}
function build_project() {
function usage() {
cat <<EOF
Build a project.
This script calls the ansible-hpa-playbook that builds project from the supplied directory.
Usage: hpa build-project [Options [GlobalOptions]] <project-dir> [playbook-args...]
Where:
project-dir : The path to the project to build.
playbook-args : Extra arguments passed after the project directory get passed directly to the ansible-playbook command.
Options:
-v | --vars-dir : Specifiy where project variables are loaded from, useful if they are not
in the root of the project directory.
Global Options:
-i | --inventory : A custom ansible inventory file to use (optional if calling this script from the playbook directory).
-p | --playbook : Path to the ansible-hpa-playbook (optional if calling this script from the playbook directory).
-q | --quiet : Surpress ansible output to only errors and warnings.
Global Flags:
--verbose : Increase log output.
Examples:
# Setup a project for super-customer using a local template directory.
$ hpa setup-project --template ~/projects/my-template ~/consults/super-customer --ask-vault-pass
# Setup a project for super-customer using a template repo.
$ hpa setup-project --repo "https://git.example.com/my-template.git" --branch "main" ~/consults/super-customer --ask-vault-pass
EOF
}
zparseopts -D -E - \
p:=playbookOpt -playbook:=playbookOpt \
i:=inventoryOpt -inventory:=inventoryOpt \
v:=varsDir -vars-dir:=varsDir \
-verbose=verbose \
q=quietOpt -quiet=quietOpt
local label="Build Project:"
local build_args=("--tags" "build-project")
setup_command $label $verbose $quietOpt \
${playbookOpt[-1]} ${inventoryOpt[-1]}
local project_dir=$1
[ "$project_dir" = "" ] && fail "$label did not specify project directory"
shift
build_args+=("--extra-vars" "project_dir=$project_dir")
debug_print $label "args: $build_args"
if [ ${#varsDir} -gt 1 ]; then
build_args+=("--extra-vars" "project_vars_dir=${varsDir[-1]}")
fi
run_playbook "${build_args[@]}" "$@"
}
function create_project_template() {
zparseopts -D -E - \
p:=playbookOpt -playbook:=playbookOpt \
i:=inventoryOpt -inventory:=inventoryOpt \
v:=varsDir -vars-dir:=varsDir
w:=vaultOpt -with-vault:=vaultOpt \
-verbose=verbose \
q=quietOpt -quiet=quietOpt
local label="Create Project Template:"
local template_args=("--tags" "repo-template")
setup_command $label $verbose $quietOpt \
${playbookOpt[-1]} ${inventoryOpt[-1]}
local output_dir=$1
[ "$output_dir" = "" ] && fail "$label did not specify output directory"
shift
template_args+=("--extra-vars" "output_dir=$output_dir")
if [ ${#varsDir} -gt 1 ];then
template_args+=("--extra-vars" "repo_vars_dir=${varsDir[-1]}")
fi
run_playbook "${template_args[@]}" "$@"
}
########################## MAIN #########################
function main() {
function usage() {
cat <<EOF
FIX ME!.
EOF
}
local label="MAIN:"
zparseopts -D -E - \
h=help -help=help \
p:=playbookOpt -playbook:=playbookOpt \
i:=inventoryOpt -inventory:=inventoryOpt \
-verbose=verbose \
q=quietOpt -quiet=quietOpt
set_verbose $verbose
set_quiet $quietOpt
debug_print $label "Begin args: $@"
load_config
debug_print $label "Loaded configuration."
case $1 in
create-project)
shift
create_project $playbookOpt $inventoryOpt $verbose $quietOpt $help $@
;;
build-project)
shift
build_project $playbookOpt $inventoryOpt $verbose $quietOpt $help $@
;;
create-project-template)
shift
create_project_template $playbookOpt $inventoryOpt $verbose $quietOpt $help $@
;;
*)
[ ! "$help" = "" ] && usage && exit 0
# TODO: Show usage here.
fail "$label unrecognized option."
esac
}
debug_print "GLOBAL:" "${@}"
main "${@}"