732 lines
25 KiB
Bash
Executable File
732 lines
25 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
help-table() {
|
|
local cmd_width=30
|
|
local opt_width=26
|
|
local desc_width=70
|
|
local column="| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n"
|
|
|
|
printf "$column" 'Command' 'Option' 'Description'
|
|
echo "|$(printf '%*s' $((cmd_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((opt_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((desc_width + 2)) '' | tr ' ' '-')|"
|
|
# Env
|
|
printf "$column" 'version' '' 'Show tool versions.'
|
|
# Galaxy
|
|
printf "$column" 'build-galaxy' '' 'Create tarball of collection.'
|
|
printf "$column" 'publish-galaxy' '' 'Publish tarball to Ansible Galaxy.'
|
|
# Docs
|
|
printf "$column" 'build-vuepress' '' 'Create vuepress build.'
|
|
printf "$column" 'dev-vuepress' '' 'Start vuepress development server.'
|
|
printf "$column" 'docs' '' 'Update docs.'
|
|
printf "$column" 'install-vuepress' '' 'Install build dependencies.'
|
|
printf "$column" 'serve-vuepress' '' 'Serve vuepress build.'
|
|
printf "$column" 'update-roles-doc' '' 'Update readme files in roles folder.'
|
|
# LLM
|
|
printf "$column" 'commit-with-llm' '' 'Commit with llm generated commit message.'
|
|
printf "$column" 'update-with-llm' '[glob][prompt]' 'Feed files matching glob with prompt to LLM and apply file changes.'
|
|
# Docker
|
|
printf "$column" "login-docker" "[user][token]" "Run Docker login and create docker config."
|
|
# Vault
|
|
printf "$column" 'convert-vault-file' '[vault_id] [path]' 'Re-encrypt vault file as single strings.'
|
|
printf "$column" 'decrypt-file' '[path]' 'Decrypt Ansible Vault file.'
|
|
printf "$column" 'encrypt-file' '[vault_id] [path]' 'Encrypt file with Ansible Vault.'
|
|
printf "$column" 'encrypt-string' '[vault_id] [key:value] -q' 'Generate encrypted string with Ansible Vault.'
|
|
printf "$column" 'generate-vault-password' '[vault_id] [password]' 'Generate a password file for Ansible vault.'
|
|
printf "$column" 'show-vault-file' '[vault_id] [path]' 'Show content of encrypted strings or fully encrypted vault file.'
|
|
# Setup
|
|
printf "$column" 'install' '' 'Install Ansible and dependencies with uv.'
|
|
printf "$column" 'install-ansible-build-scripts' '[role]' 'Install scripts of the specified Ansbile role.'
|
|
printf "$column" 'install-exo' '' 'Install Exoscale CLI.'
|
|
printf "$column" 'show-passwordless-sudo' '[username]' 'Give instructions to setup passwordless sudo.'
|
|
printf "$column" 'upgrade' '' 'Upgrade Ansible and dependencies with uv.'
|
|
# Development
|
|
printf "$column" 'lint' '' 'Lint Ansible roles and playbooks.'
|
|
printf "$column" 'source' '' 'Source the Python virtual env.'
|
|
# Report
|
|
printf "$column" 'get-last-hostname' '[role]' 'Search inventory for $ROLE_hostname entries.'
|
|
printf "$column" 'list-hosts' '[path]' 'Lists all hosts of an inventory.'
|
|
printf "$column" 'list-roles' '' 'Lists all roles.'
|
|
printf "$column" 'list-vault' '' 'Lists vault identities.'
|
|
printf "$column" 'list-deployments-odoo' '[path]' 'List Odoo deplyments.'
|
|
# Git
|
|
printf "$column" 'pull-repos' '' 'Pull git repos in inventories folder.'
|
|
# Run
|
|
printf "$column" 'play' '' 'Run ansible-playbook command.'
|
|
printf "$column" 'run' '' 'Run ansible command.'
|
|
printf "$column" 'connect-host' '[host]' 'Connect to host with configs.'
|
|
# Test
|
|
printf "$column" 'test-localhost' '[cleanup]' 'Deploy to localhost. Pass option '\''cleanup'\'' to reset test env.'
|
|
printf "$column" 'test-scripts' '[cleanup]' 'Install and test scripts. Pass option '\''cleanup'\'' to reset test env.'
|
|
}
|
|
|
|
help() {
|
|
echo
|
|
if [[ -n "$1" ]]; then
|
|
help-table | grep -i "$1" | column -t -s'|'
|
|
else
|
|
echo 'task <command> [options]'
|
|
echo
|
|
echo 'commands:'
|
|
echo
|
|
help-table
|
|
fi
|
|
echo
|
|
}
|
|
|
|
# Dynamic env vars
|
|
|
|
GIT_BRANCH=$(git symbolic-ref --short -q HEAD)
|
|
LLM_MODEL=${LLM_MODEL:="llama"}
|
|
|
|
if [[ -a ".env" ]]; then
|
|
export $(cat .env | sed 's/^#.*//g' | xargs)
|
|
fi
|
|
|
|
# Import commands
|
|
|
|
clone-taskfile(){
|
|
if [ ! -d "$HOME/taskfile.build" ]; then
|
|
echo -e "\033[38;5;214mGit\033[0m: Clone taskfile repo"
|
|
git clone https://git.taskfile.build "$HOME/taskfile.build"
|
|
else
|
|
echo -e "\033[38;5;214mGit\033[0m: Pull taskfile repo"
|
|
git -C "$HOME/taskfile.build" pull
|
|
fi
|
|
}
|
|
|
|
if [ -d "$HOME/taskfile.build/bin" ]; then
|
|
for file in "$HOME/taskfile.build/bin/"*; do
|
|
if [ -f "$file" ]; then
|
|
source "$file"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Vault
|
|
|
|
connect-host() {
|
|
if [[ -z "$1" ]]; then
|
|
echo 'Host name cannot be empty'
|
|
return 1
|
|
fi
|
|
local search_host="$1"
|
|
|
|
# Find hosts.yaml file in inventories folder
|
|
local hosts_files
|
|
hosts_files=$(find ./inventories -type f -name 'hosts.yml')
|
|
|
|
# Search for host name match
|
|
local host_config=""
|
|
local hosts_file
|
|
for hosts_file in $hosts_files; do
|
|
|
|
local command="yq e '.all.children.*.hosts.$search_host' $hosts_file"
|
|
host_config=$(eval "$command" | sed '/null/d' | head -5)
|
|
|
|
if [[ -z "$host_config" ]]; then
|
|
command="yq e '.all.hosts.$search_host' $hosts_file"
|
|
host_config=$(eval "$command" | sed '/null/d' | head -5)
|
|
fi
|
|
|
|
if [[ -n "$host_config" ]]; then
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ -z "$host_config" ]]; then
|
|
echo "Host '$search_host' not found in hosts.yml file"
|
|
return 1
|
|
fi
|
|
|
|
# Get Ansible vars from the host configuration
|
|
local ansible_host
|
|
local ansible_port
|
|
local ansible_user
|
|
local ansible_common_args
|
|
ansible_host=$(echo "$host_config" | grep -m1 '^ansible_host' | cut -d: -f2 | xargs)
|
|
ansible_port=$(echo "$host_config" | grep -m1 '^ansible_port' | cut -d: -f2 | xargs)
|
|
ansible_user=$(echo "$host_config" | grep -m1 '^ansible_user' | cut -d: -f2 | xargs)
|
|
ansible_common_args=$(echo "$host_config" | grep -m1 'ansible_ssh_common_args' | cut -d: -f2 | xargs)
|
|
|
|
# Build SSH command using extracted connection details
|
|
local ssh_command="ssh"
|
|
if [[ "$ansible_port" != "null" ]] && [[ -n "$ansible_port" ]]; then
|
|
ssh_command+=" -p $ansible_port"
|
|
fi
|
|
if [[ "$ansible_common_args" != "null" ]] && [[ -n "$ansible_common_args" ]]; then
|
|
ssh_command+=" $ansible_common_args"
|
|
fi
|
|
if [[ "$ansible_user" != "null" ]] && [[ -n "$ansible_user" ]]; then
|
|
ssh_command+=" $ansible_user@$ansible_host"
|
|
else
|
|
ssh_command+=" $ansible_host"
|
|
fi
|
|
|
|
echo "Run command: $ssh_command"
|
|
$ssh_command
|
|
}
|
|
|
|
|
|
decrypt-file() {
|
|
if [[ -z "$1" ]]; then echo '$1 is empty'; exit; fi
|
|
echo "Decrypt file $1."
|
|
ansible-vault decrypt --output="$1" "$1"
|
|
}
|
|
|
|
encrypt-file() {
|
|
if [[ -z "$1" ]]; then echo '$1 is empty'; exit; fi
|
|
if [[ -z "$2" ]]; then echo '$2 is empty'; exit; fi
|
|
echo "Encrypt file $2 with vault id $1."
|
|
ansible-vault encrypt --encrypt-vault-id="$1" "$2"
|
|
}
|
|
|
|
list-vault() {
|
|
grep 'vault_identity_list' ansible.cfg | sed 's/^vault_identity_list = //' | tr ',' '\n' | sed '/^$/d'
|
|
}
|
|
|
|
generate-vault-password() {
|
|
if [[ -z "$1" ]]; then echo '$1 is empty'; exit; fi
|
|
if [[ -z "$2" ]]; then echo '$2 is empty'; exit; fi
|
|
|
|
local vault_id="$1"
|
|
local vaultpassword="$2"
|
|
export VAULT_ID="$vault_id"
|
|
export VAULTPASSWORD="$vaultpassword"
|
|
echo "$vaultpassword" > ".vault_pass_$vault_id"
|
|
chmod 600 ".vault_pass_$vault_id"
|
|
echo "Password file .vault_pass_$vault_id created."
|
|
}
|
|
|
|
encrypt-string() {
|
|
if [[ -z "$1" ]]; then echo '$1 is empty'; exit; fi
|
|
if [[ -z "$2" ]]; then echo '$2 is empty'; exit; fi
|
|
|
|
# Split multiline
|
|
local string_key
|
|
local string_value
|
|
string_key=$(echo "$2" | cut -d ':' -f 1)
|
|
string_value=$(echo "$2" | cut -d ':' -f 2 | sed 's/^ *//')
|
|
|
|
if [[ "$3" != "-q" ]]; then
|
|
echo "Found key: $string_key"
|
|
echo "Encrypting value: $string_value"
|
|
fi
|
|
ansible-vault encrypt_string --encrypt-vault-id="$1" --name "$string_key" "$string_value"
|
|
}
|
|
|
|
convert-vault-file() {
|
|
if [[ -z "$1" ]]; then echo '$1 is empty'; exit; fi
|
|
if [[ -z "$2" ]]; then echo '$2 is empty'; exit; fi
|
|
|
|
local vault_id="$1"
|
|
local file_path="$2"
|
|
local temp_file
|
|
temp_file=$(mktemp)
|
|
|
|
# Decrypt the vault file
|
|
ansible-vault decrypt --output="$file_path" "$file_path"
|
|
|
|
# Process each key-value pair
|
|
yq eval '.' "$file_path" | while IFS= read -r line; do
|
|
local key
|
|
local value
|
|
key=$(echo "$line" | cut -d':' -f1)
|
|
value=$(echo "$line" | cut -d':' -f2-)
|
|
value=$(echo "$value" | sed 's/^[[:space:]"]*//;s/[[:space:]"]*$//')
|
|
|
|
# Re-encrypt the key-value pair
|
|
local encrypted
|
|
encrypted=$(ansible-vault encrypt_string --encrypt-vault-id="$vault_id" --name "$key" "$value" 2>/dev/null)
|
|
echo "$encrypted" >> "$temp_file"
|
|
done
|
|
|
|
# Move temp file to vault file
|
|
mv "$temp_file" "$file_path"
|
|
echo "Converted file saved as $file_path"
|
|
}
|
|
|
|
show-vault-file() {
|
|
if [[ -z "$1" ]]; then echo '$1 is empty'; exit 1; fi
|
|
if [[ -z "$2" ]]; then echo '$2 is empty'; exit 1; fi
|
|
local vault_id="$1"
|
|
local file_path="$2"
|
|
local temp_file
|
|
local temp_part_file
|
|
temp_file=$(mktemp)
|
|
temp_part_file=$(mktemp)
|
|
|
|
if head -n 1 "$file_path" | grep -q "^\$ANSIBLE_VAULT;1.2;AES256;$vault_id"; then
|
|
ansible-vault decrypt --output="$temp_file" "$file_path"
|
|
else
|
|
local write_finished=false
|
|
local current_key=""
|
|
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ "!vault" ]]; then
|
|
# Process previous vault entry if it exists
|
|
if [[ "$write_finished" = true ]] && [[ -n "$current_key" ]] && [[ -s "$temp_part_file" ]]; then
|
|
ansible-vault decrypt "$temp_part_file"
|
|
local value
|
|
value=$(cat "$temp_part_file")
|
|
echo "$current_key: $value" >> "$temp_file"
|
|
fi
|
|
|
|
# Set up for new vault entry
|
|
current_key=$(echo "$line" | cut -d':' -f1)
|
|
: > "$temp_part_file"
|
|
write_finished=true
|
|
else
|
|
if [[ "$write_finished" = true ]]; then
|
|
echo "$line" | sed 's/^[[:space:]"]*//;s/[[:space:]"]*$//' >> "$temp_part_file"
|
|
fi
|
|
fi
|
|
done < "$file_path"
|
|
|
|
# Process the final vault entry
|
|
if [[ "$write_finished" = true ]] && [[ -n "$current_key" ]] && [[ -s "$temp_part_file" ]]; then
|
|
ansible-vault decrypt "$temp_part_file"
|
|
local value
|
|
value=$(cat "$temp_part_file")
|
|
echo "$current_key: $value" >> "$temp_file"
|
|
fi
|
|
fi
|
|
|
|
bat --paging=always "$temp_file"
|
|
rm -f "$temp_file"
|
|
rm -f "$temp_part_file"
|
|
}
|
|
|
|
# Env
|
|
|
|
install() {
|
|
echo "Ensure Python version $(cat .python-version) is installed."
|
|
uv python install
|
|
remove-venv
|
|
activate-venv
|
|
|
|
echo "Setup Ansible log file"
|
|
sudo touch /var/log/ansible.log
|
|
sudo chown $USER: /var/log/ansible.log
|
|
|
|
echo "Install Ansible and Python dependencies"
|
|
uv pip install -r requirements.txt
|
|
}
|
|
|
|
install-exo() {
|
|
curl -fsSL https://raw.githubusercontent.com/exoscale/cli/master/install-latest.sh | sh
|
|
}
|
|
|
|
version() {
|
|
uv --version
|
|
ansible --version
|
|
}
|
|
|
|
show-passwordless-sudo() {
|
|
local user="${1:-$USERNAME}"
|
|
echo "echo \"$user ALL=(ALL) NOPASSWD: ALL\" >> /etc/sudoers"
|
|
}
|
|
|
|
# Run
|
|
|
|
play() {
|
|
ansible-playbook "$@"
|
|
}
|
|
|
|
run() {
|
|
ansible "$@"
|
|
}
|
|
|
|
upgrade() {
|
|
echo "Update Ansible"
|
|
uv pip install --upgrade ansible
|
|
}
|
|
|
|
lint() {
|
|
ansible-lint --fix --offline roles/*
|
|
}
|
|
|
|
# Report
|
|
|
|
list-hosts() {
|
|
if [[ -z "$1" ]]; then echo '$1 is empty'; exit; fi
|
|
|
|
find "$1" -name 'hosts.yml' | sort | while read -r hosts_file; do
|
|
echo -e "\n<<< $hosts_file >>>\n"
|
|
|
|
# Check if any host has a 'customer' field
|
|
local has_customers=$(yq e '.all.children.*.hosts | .[] | has("customer")' "$hosts_file" | grep -m1 true)
|
|
|
|
if [[ -n "$has_customers" ]]; then
|
|
# Handle inventories with customer info
|
|
local aliases=$(yq e '.all.children.*.hosts' "$hosts_file" | grep '^[a-zA-Z]' | cut -d: -f1)
|
|
local hosts=$(yq e '.all.children.*.hosts | .[] | .ansible_host' "$hosts_file")
|
|
local customers=$(yq e '.all.children.*.hosts | .[] | .customer' "$hosts_file")
|
|
|
|
if [[ -z "$aliases" || -z "$hosts" ]]; then
|
|
echo "No hosts found in $hosts_file"
|
|
continue
|
|
fi
|
|
|
|
local alias_width=15
|
|
local host_width=25
|
|
local cust_width=35
|
|
local column="| %-${alias_width}s | %-${host_width}s | %-${cust_width}s |\n"
|
|
printf "$column" 'Alias' 'Host' 'Customer'
|
|
echo "|$(printf '%*s' $((alias_width + 2)) '' | tr ' ' '-')+$(printf '%*s' $((host_width + 2)) '' | tr ' ' '-')+$(printf '%*s' $((cust_width + 2)) '' | tr ' ' '-')|"
|
|
paste <(echo "$aliases") <(echo "$hosts") <(echo "$customers") | sort -u | while read -r alias host customer; do
|
|
printf "$column" "$alias" "$host" "$customer"
|
|
done
|
|
else
|
|
# Regular inventory without customer field
|
|
local aliases=$(yq e '.all.hosts' "$hosts_file" | grep '^[a-zA-Z]' | cut -d: -f1)
|
|
local hosts=$(yq e '.all.hosts | .[] | .ansible_host' "$hosts_file")
|
|
|
|
if [[ -z "$aliases" || -z "$hosts" ]]; then
|
|
echo "No hosts found in $hosts_file"
|
|
continue
|
|
fi
|
|
|
|
local alias_width=15
|
|
local host_width=25
|
|
local column="| %-${alias_width}s | %-${host_width}s |\n"
|
|
printf "$column" 'Alias' 'Host'
|
|
echo "|$(printf '%*s' $((alias_width + 2)) '' | tr ' ' '-')+$(printf '%*s' $((host_width + 2)) '' | tr ' ' '-')|"
|
|
paste <(echo "$aliases") <(echo "$hosts") | while read -r alias host; do
|
|
printf "$column" "$alias" "$host"
|
|
done
|
|
fi
|
|
done
|
|
}
|
|
|
|
list-roles() {
|
|
local role_width=30
|
|
local description_width=70
|
|
local column="| %-${role_width}s | %-${description_width}s |\n"
|
|
printf "$column" 'Role' 'Description'
|
|
echo "|$(printf '%*s' $((role_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((description_width + 2)) '' | tr ' ' '-')|"
|
|
|
|
local md_files
|
|
md_files=$(find roles -name 'README.md' | sort)
|
|
local readme
|
|
for readme in $md_files; do
|
|
local role
|
|
role=$(basename $(dirname "$readme"))
|
|
local description
|
|
description=$(sed '5q;d' "$readme")
|
|
printf "$column" "$role" "$description"
|
|
done
|
|
}
|
|
|
|
get-last-hostname() {
|
|
if [[ -z "$1" ]]; then echo '$1 is empty'; exit; fi
|
|
local role="$1"
|
|
|
|
echo "Search inventories folder for '${role}_hostname: $role'"
|
|
local all_hostnames
|
|
all_hostnames=$(rg -I "^${role}_hostname: $role" inventories | cut -d' ' -f2 | sort -u)
|
|
|
|
local highest
|
|
highest=$(echo "$all_hostnames" | sed "s/${role}//g" | sort -n | tail -1)
|
|
echo "Highest hostname: ${role}$highest"
|
|
echo "Free hostnames:"
|
|
for i in $(seq 1 $highest); do
|
|
local num
|
|
num=$(printf "%02d" $i)
|
|
local hostname="${role}${num}"
|
|
|
|
if ! echo "$all_hostnames" | grep -q "$hostname"; then
|
|
echo "$hostname"
|
|
fi
|
|
done
|
|
}
|
|
|
|
pull-repos() {
|
|
local git_folder
|
|
for git_folder in $(find inventories -name .git); do
|
|
local repo
|
|
repo=$(dirname "$git_folder")
|
|
echo "Pull repo $repo."
|
|
git -C "$repo" pull
|
|
done
|
|
}
|
|
|
|
list-deployments-odoo() {
|
|
INVENTORY_DIR="$1"
|
|
HOST_VARS_DIR="$INVENTORY_DIR/host_vars"
|
|
COL_WIDTH_ALIAS=15
|
|
COL_WIDTH_HOSTNAME=15
|
|
COL_WIDTH_IMAGE=80
|
|
|
|
printf "| %-${COL_WIDTH_ALIAS}s | %-${COL_WIDTH_HOSTNAME}s | %-${COL_WIDTH_IMAGE}s |\n" "alias" "odoo_hostname" "odoo_image"
|
|
printf "| %-${COL_WIDTH_ALIAS}s | %-${COL_WIDTH_HOSTNAME}s | %-${COL_WIDTH_IMAGE}s |\n" \
|
|
"$(printf '%.0s-' {1..$COL_WIDTH_ALIAS} | sed 's/-/---/')" \
|
|
"$(printf '%.0s-' {1..$COL_WIDTH_HOSTNAME} | sed 's/-/---/')" \
|
|
"$(printf '%.0s-' {1..$COL_WIDTH_IMAGE} | sed 's/-/---/')"
|
|
|
|
mapfile -t FILE_LIST < <(find "$HOST_VARS_DIR" -type f -name "vars.yml" -o -path "$HOST_VARS_DIR/*.yml" | sort)
|
|
|
|
for FILE_PATH in "${FILE_LIST[@]}"; do
|
|
if [[ "$FILE_PATH" == *vault* ]]; then
|
|
continue
|
|
fi
|
|
|
|
if [[ "$FILE_PATH" == */vars.yml ]]; then
|
|
ALIAS=$(basename "$(dirname "$FILE_PATH")")
|
|
VARS_FILE="$FILE_PATH"
|
|
elif [[ "$FILE_PATH" == *.yml ]]; then
|
|
ALIAS=$(basename "$FILE_PATH" .yml)
|
|
VARS_FILE="$FILE_PATH"
|
|
else
|
|
continue
|
|
fi
|
|
|
|
if [[ "$ALIAS" == "vars" ]] || [[ "$ALIAS" == "vault" ]] || [[ -z "$ALIAS" ]]; then
|
|
continue
|
|
fi
|
|
|
|
ODOO_HOSTNAME=$(yq eval '.odoo_hostname // "N/A"' "$VARS_FILE" | head -1)
|
|
ODOO_IMAGE=$(yq eval '.odoo_image // "N/A"' "$VARS_FILE" | head -1)
|
|
|
|
printf "| %-${COL_WIDTH_ALIAS}s | %-${COL_WIDTH_HOSTNAME}s | %-${COL_WIDTH_IMAGE}s |\n" \
|
|
"$ALIAS" "$ODOO_HOSTNAME" "$ODOO_IMAGE"
|
|
done
|
|
}
|
|
|
|
# Galaxy
|
|
|
|
build-galaxy() {
|
|
local version=$(yq eval '.version' galaxy.yml)
|
|
local namespace=$(yq eval '.namespace' galaxy.yml)
|
|
local name=$(yq eval '.name' galaxy.yml)
|
|
|
|
ansible-galaxy collection build
|
|
mv $namespace-$name-$version.tar.gz tmp/
|
|
}
|
|
|
|
publish-galaxy() {
|
|
local version=$(yq eval '.version' galaxy.yml)
|
|
local namespace=$(yq eval '.namespace' galaxy.yml)
|
|
local name=$(yq eval '.name' galaxy.yml)
|
|
|
|
ansible-galaxy collection publish tmp/$namespace-$name-$version.tar.gz --token "$GALAXY_API_TOKEN"
|
|
}
|
|
|
|
# Test commands
|
|
|
|
test-localhost() {
|
|
version
|
|
if [[ "$1" = "cleanup" ]]; then
|
|
echo "Cleanup localhost"
|
|
ansible-playbook -i inventory plays/cleanup.yml -t "odoo,odoo_data,odoo_volume,\
|
|
postgres,postgres_data,postgres_volume,\
|
|
meilisearch,meilisearch_data,meilisearch_volume,\
|
|
pgadmin,pgadmin_data,pgadmin_volume,\
|
|
n8n,n8n_data,n8n_volume,\
|
|
nginx,nginx_data,nginx_volume,\
|
|
metabase,metabase_data,metabase_volume,\
|
|
prometheus,prometheus_data,prometheus_volume,\
|
|
grafana,grafana_data,grafana_volume,\
|
|
loki,loki_data,loki_volume,\
|
|
promtail,promtail_data,promatil_volume,\
|
|
docker_compose,docker_compose_data"
|
|
else
|
|
echo "Setup localhost"
|
|
ansible-playbook -i inventory plays/localhost.yml --skip-tags check
|
|
|
|
echo "Curl the services and check HTTP code."
|
|
|
|
local fail=0
|
|
|
|
local code=$(curl -o /dev/null -s -w "%{http_code}" -L "http://n8n.local:8080")
|
|
[[ $code -eq 200 ]] || { echo "http://n8n.local:8080 -> $code"; fail=1; }
|
|
|
|
local code=$(curl -o /dev/null -s -w "%{http_code}" -L "http://odoo.local:8080")
|
|
[[ $code -eq 200 ]] || { echo "http://odoo.local:8080 -> $code"; fail=1; }
|
|
|
|
local code=$(curl -o /dev/null -s -w "%{http_code}" -L "http://odoo.local:8080/website/info")
|
|
[[ $code -eq 403 ]] || { echo "http://odoo.local:8080/website/info -> $code"; fail=1; }
|
|
|
|
local code=$(curl -o /dev/null -s -w "%{http_code}" -L "http://metabase.local:8080")
|
|
[[ $code -eq 200 ]] || { echo "http://metabase.local:8080 -> $code"; fail=1; }
|
|
|
|
local code=$(curl -o /dev/null -s -w "%{http_code}" -L "http://grafana.local:8080")
|
|
[[ $code -eq 200 ]] || { echo "http://grafana.local:8080 -> $code"; fail=1; }
|
|
|
|
exit $fail
|
|
|
|
fi
|
|
}
|
|
|
|
test-scripts() {
|
|
set -e
|
|
|
|
if [[ "$1" = "cleanup" ]]; then
|
|
echo -e "\033[38;5;214mTEST\033[0m: Cleanup test environment."
|
|
ansible localhost -m ansible.builtin.cron -a 'name="test" state="absent"'
|
|
ansible-playbook -i inventory plays/cleanup.yml -t "odoo,odoo_data,odoo_volume,\
|
|
postgres,postgres_data,postgres_volume"
|
|
else
|
|
echo -e "\033[38;5;214mTEST\033[0m: Test restic scripts"
|
|
sudo ./roles/cron/files/install
|
|
|
|
# Add cron job
|
|
ansible localhost -m ansible.builtin.cron -a 'name="test" minute="0" hour="*/6" job="echo \"test\""'
|
|
|
|
# List cron job and compare output
|
|
[[ "$(cron-job-list)" == "[1] 0 */6 * * * test" ]]
|
|
cron-job-run -i 1
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Test postgres scripts"
|
|
sudo ./roles/postgres/files/install
|
|
|
|
# Start postgres container
|
|
ansible-playbook -i inventory plays/localhost.yml -t postgres
|
|
|
|
docker-postgres-create -c postgres01 -d test
|
|
docker-postgres-list -c postgres01 | grep "test"
|
|
docker-postgres-shell -c postgres01 -d test -s 'CREATE TABLE example(id int);'
|
|
docker-postgres-duplicate -c postgres01 -s test -t example
|
|
docker-postgres-drop -c postgres01 -d test
|
|
docker-postgres-size -c postgres01 -d example | grep "0 bytes"
|
|
docker-postgres-backup -c postgres01 -d example
|
|
docker-postgres-restore -c postgres01 -f /var/tmp/postgres01/example.sql -d test -i
|
|
docker-postgres-size -c postgres01 -d test | grep "0 bytes"
|
|
mkdir -p tmp
|
|
echo 'DROP TABLE example;' > tmp/drop.sql
|
|
docker-postgres-patch -c postgres01 -d test -f ./tmp/drop.sql
|
|
docker-postgres-rename -c postgres01 -s test -t example -r
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Test odoo scripts"
|
|
sudo ./roles/odoo/files/install
|
|
|
|
# Start odoo container
|
|
ansible-playbook -i inventory plays/localhost.yml -t odoo --skip-tags depends
|
|
|
|
docker-odoo-init -c odoo01-prod -d odoo-prod -i contacts -w
|
|
docker-odoo-rename -c odoo01-prod -s odoo-prod -t odoo
|
|
docker-odoo-list -c odoo01-prod | grep "odoo$"
|
|
docker-odoo-user -c odoo01-prod -d odoo -a list | grep "admin"
|
|
docker-odoo-drop -c odoo01-int -d odoo-int
|
|
docker-odoo-duplicate -c odoo01-prod -s odoo -t odoo-int
|
|
docker-odoo-neutralize -c odoo01-int -d odoo-int
|
|
docker exec odoo01-int clone-git-addons
|
|
docker restart odoo01-int
|
|
docker-odoo-init -c odoo01-int -d odoo-int -i partner_firstname
|
|
docker-odoo-shell -c odoo01-int -d odoo-int -f -p 'env["res.partner"].browse(1).write({"name": "admint"})'
|
|
[[ "admint" == $(docker-odoo-shell -c odoo01-int -d odoo-int -p 'print(env["res.partner"].browse(1).name)') ]]
|
|
docker-odoo-upgrade -c postgres01 -d odoo-int -s "17.0" -n upgrade -t "18.0" -m test -l "$ODOO_ENTERPRISE_CODE"
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Test docker volume scripts"
|
|
docker stop postgres01
|
|
docker-volume-backup -c postgres01 -v postgres01
|
|
docker-volume-backup -c postgres01 -a
|
|
docker rm -f postgres01
|
|
docker volume rm postgres01
|
|
docker-volume-restore -v postgres01 -f /var/tmp/postgres01/postgres01.tar
|
|
ansible-playbook -i inventory plays/localhost.yml -t postgres --skip-tags depends
|
|
docker-postgres-list -c postgres01 | grep "example"
|
|
fi
|
|
}
|
|
|
|
# Docs
|
|
|
|
docs() {
|
|
echo "Update roles.md"
|
|
echo "# Roles" > "roles.md"
|
|
echo "" >> "roles.md"
|
|
echo "| Logo | Role | Description |" >> "roles.md"
|
|
echo "| --- | --- | --- |" >> "roles.md"
|
|
|
|
local md_files=$(find roles -name 'README.md' | sort)
|
|
for readme in $md_files; do
|
|
local role
|
|
role=$(basename $(dirname "$readme"))
|
|
local description
|
|
description=$(sed '5q;d' "$readme")
|
|
echo "|  | [$role]($readme) | $description |" >> "roles.md"
|
|
done
|
|
}
|
|
|
|
update-roles-doc() {
|
|
local md_files=$(find roles -name 'README.md' | sort)
|
|
for readme in $md_files; do
|
|
local role
|
|
role=$(basename "$(dirname "$readme")")
|
|
|
|
echo "Update README of $role role."
|
|
|
|
local logo_line="<img src=\"/logos/$role.png\" alt=\"$role logo\" width=\"100\" height=\"100\">"
|
|
local tmpfile
|
|
tmpfile=$(mktemp)
|
|
{
|
|
echo "$logo_line"
|
|
echo ""
|
|
cat "$readme"
|
|
} > "$tmpfile" && mv "$tmpfile" "$readme"
|
|
done
|
|
}
|
|
|
|
install-vuepress() {
|
|
pnpm install
|
|
}
|
|
|
|
dev-vuepress() {
|
|
echo "Copy logos folder to vuepress public folder."
|
|
cp -r logos .vuepress/public/
|
|
|
|
pnpm run dev
|
|
}
|
|
|
|
build-vuepress() {
|
|
echo "Copy logos folder to vuepress public folder."
|
|
cp -r logos .vuepress/public/
|
|
|
|
pnpm run build
|
|
|
|
echo "Create vuepress script folders."
|
|
mkdir -p .vuepress/dist/ansible_scripts
|
|
mkdir -p .vuepress/dist/cron
|
|
mkdir -p .vuepress/dist/certbot
|
|
mkdir -p .vuepress/dist/docker
|
|
mkdir -p .vuepress/dist/docker_volume
|
|
mkdir -p .vuepress/dist/grafana
|
|
mkdir -p .vuepress/dist/mysql
|
|
mkdir -p .vuepress/dist/nginx
|
|
mkdir -p .vuepress/dist/odoo
|
|
mkdir -p .vuepress/dist/postgres
|
|
|
|
echo "Copy script files to vuepress folder."
|
|
cp roles/ansible_scripts/files/* .vuepress/dist/ansible_scripts
|
|
cp roles/cron/files/* .vuepress/dist/cron
|
|
cp roles/certbot/files/* .vuepress/dist/certbot
|
|
cp roles/docker/files/* .vuepress/dist/docker
|
|
cp roles/docker_volume/files/* .vuepress/dist/docker_volume
|
|
cp roles/grafana/files/* .vuepress/dist/grafana
|
|
cp roles/mysql/files/* .vuepress/dist/mysql
|
|
cp roles/nginx/files/* .vuepress/dist/nginx
|
|
cp roles/odoo/files/* .vuepress/dist/odoo
|
|
cp roles/postgres/files/* .vuepress/dist/postgres
|
|
|
|
}
|
|
|
|
serve-vuepress() {
|
|
cd .vuepress/dist
|
|
pnpx serve
|
|
}
|
|
|
|
if declare -f "$1" > /dev/null; then
|
|
activate-venv 2>/dev/null || true
|
|
"$1" "${@:2}"
|
|
else
|
|
case "$1" in
|
|
source)
|
|
activate-venv
|
|
;;
|
|
*)
|
|
echo "Unknown command: $1"
|
|
help
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|