kolla-ansible/tools/kolla-ansible
Michal Nasiadka fb447eb70a Improve kolla-ansible error on missing Ansible
Also improve the error message to point out currently supported
Ansible version.

Change-Id: Iabd11f03ff789f7fab8bec068bc9b4fb4dd1a2be
2022-11-22 06:23:04 +00:00

572 lines
18 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# This script can be used to interact with kolla via ansible.
set -o errexit
# do not use _PYTHON_BIN directly, use $(get_python_bin) instead
_PYTHON_BIN=""
ANSIBLE_VERSION_MIN=2.12
ANSIBLE_VERSION_MAX=2.13
function get_python_bin {
if [ -n "$_PYTHON_BIN" ]; then
echo -n "$_PYTHON_BIN"
return
fi
local ansible_path
ansible_path=$(which ansible)
if [[ $? -ne 0 ]]; then
echo "ERROR: Ansible is not installed in the current (virtual) environment." >&2
echo "Ansible version should be between $ANSIBLE_VERSION_MIN and $ANSIBLE_VERSION_MAX." >&2
exit 1
fi
local ansible_shebang_line
ansible_shebang_line=$(head -n1 "$ansible_path")
if ! echo "$ansible_shebang_line" | egrep "^#!" &>/dev/null; then
echo "ERROR: Ansible script is malformed (missing shebang line)." >&2
exit 1
fi
# NOTE(yoctozepto): may have multiple parts
_PYTHON_BIN=${ansible_shebang_line#\#\!}
echo -n "$_PYTHON_BIN"
}
function check_environment_coherence {
local ansible_python_cmdline
ansible_python_cmdline=$(get_python_bin)
ansible_python_version=$($ansible_python_cmdline -c 'import sys; print(str(sys.version_info[0])+"."+str(sys.version_info[1]))')
if ! $ansible_python_cmdline --version &>/dev/null; then
echo "ERROR: Ansible Python is not functional." >&2
echo "Tried '$ansible_python_cmdline'" >&2
exit 1
fi
# Check for existence of kolla_ansible module using Ansible's Python.
if ! $ansible_python_cmdline -c 'import kolla_ansible' &>/dev/null; then
echo "ERROR: kolla_ansible has to be available in the Ansible PYTHONPATH." >&2
echo "Please install both in the same (virtual) environment." >&2
exit 1
fi
local ansible_full_version
ansible_full_version=$($ansible_python_cmdline -c 'import ansible; print(ansible.__version__)')
if [[ $? -ne 0 ]]; then
echo "ERROR: Failed to obtain Ansible version:" >&2
echo "$ansible_full_version" >&2
exit 1
fi
local ansible_version
ansible_version=$(echo "$ansible_full_version" | egrep -o '^[0-9]+\.[0-9]+')
if [[ $? -ne 0 ]]; then
echo "ERROR: Failed to parse Ansible version:" >&2
echo "$ansible_full_version" >&2
exit 1
fi
if [[ $(printf "%s\n" "$ANSIBLE_VERSION_MIN" "$ANSIBLE_VERSION_MAX" "$ansible_version" | sort -V | head -n1) != "$ANSIBLE_VERSION_MIN" ]] ||
[[ $(printf "%s\n" "$ANSIBLE_VERSION_MIN" "$ANSIBLE_VERSION_MAX" "$ansible_version" | sort -V | tail -n1) != "$ANSIBLE_VERSION_MAX" ]]; then
echo "ERROR: Ansible version should be between $ANSIBLE_VERSION_MIN and $ANSIBLE_VERSION_MAX. Current version is $ansible_full_version which is not supported."
exit 1
fi
}
function find_base_dir {
local dir_name
local python_dir
dir_name=$(dirname "$0")
# NOTE(yoctozepto): Fix the case where dir_name is a symlink and VIRTUAL_ENV might not be. This
# happens with pyenv-virtualenv, see https://bugs.launchpad.net/kolla-ansible/+bug/1903887
dir_name=$(readlink -e "$dir_name")
python_dir="python${ansible_python_version}"
if [ -z "$SNAP" ]; then
if [[ ${dir_name} == "/usr/bin" ]]; then
if test -f /usr/lib/${python_dir}/*-packages/kolla-ansible.egg-link; then
# Editable install.
BASEDIR="$(head -n1 /usr/lib/${python_dir}/*-packages/kolla-ansible.egg-link)"
else
BASEDIR=/usr/share/kolla-ansible
fi
elif [[ ${dir_name} == "/usr/local/bin" ]]; then
if test -f /usr/local/lib/${python_dir}/*-packages/kolla-ansible.egg-link; then
# Editable install.
BASEDIR="$(head -n1 /usr/local/lib/${python_dir}/*-packages/kolla-ansible.egg-link)"
else
BASEDIR=/usr/local/share/kolla-ansible
fi
elif [[ ${dir_name} == ~/.local/bin ]]; then
if test -f ~/.local/lib/${python_dir}/*-packages/kolla-ansible.egg-link; then
# Editable install.
BASEDIR="$(head -n1 ~/.local/lib/${python_dir}/*-packages/kolla-ansible.egg-link)"
else
BASEDIR=~/.local/share/kolla-ansible
fi
elif [[ -n ${VIRTUAL_ENV} ]] && [[ ${dir_name} == "$(readlink -e "${VIRTUAL_ENV}/bin")" ]]; then
if test -f ${VIRTUAL_ENV}/lib/${python_dir}/site-packages/kolla-ansible.egg-link; then
# Editable install.
BASEDIR="$(head -n1 ${VIRTUAL_ENV}/lib/${python_dir}/*-packages/kolla-ansible.egg-link)"
else
BASEDIR="${VIRTUAL_ENV}/share/kolla-ansible"
fi
else
# Running from sources (repo).
BASEDIR="$(dirname ${dir_name})"
fi
else
BASEDIR="$SNAP/share/kolla-ansible"
fi
}
function install_deps {
echo "Installing Ansible Galaxy dependencies"
ansible-galaxy collection install -r ${BASEDIR}/requirements.yml --force
if [[ $? -ne 0 ]]; then
echo "ERROR: Failed to install Ansible Galaxy dependencies" >&2
exit 1
fi
}
function process_cmd {
echo "$ACTION : $CMD"
$CMD
if [[ $? -ne 0 ]]; then
echo "Command failed $CMD"
exit 1
fi
}
function usage {
cat <<EOF
Usage: $0 COMMAND [options]
Options:
--inventory, -i <inventory_path> Specify path to ansible inventory file. \
Can be specified multiple times to pass multiple inventories.
--playbook, -p <playbook_path> Specify path to ansible playbook file
--configdir <config_path> Specify path to directory with globals.yml
--key -k <key_path> Specify path to ansible vault keyfile
--help, -h Show this usage information
--tags, -t <tags> Only run plays and tasks tagged with these values
--skip-tags <tags> Only run plays and tasks whose tags do not match these values
--extra, -e <ansible variables> Set additional variables as key=value or YAML/JSON passed to ansible-playbook
--passwords <passwords_path> Specify path to the passwords file
--limit <host> Specify host to run plays
--forks <forks> Number of forks to run Ansible with
--vault-id <@prompt or path> Specify @prompt or password file (Ansible >= 2.4)
--ask-vault-pass Ask for vault password
--vault-password-file <path> Specify password file for vault decrypt
--check, -C Don't make any changes and try to predict some of the changes that may occur instead
--diff, -D Show differences in ansible-playbook changed tasks
--verbose, -v Increase verbosity of ansible-playbook
--version Show version
Environment variables:
EXTRA_OPTS Additional arguments to pass to ansible-playbook
Commands:
install-deps Install Ansible Galaxy dependencies
prechecks Do pre-deployment checks for hosts
mariadb_recovery Recover a completely stopped mariadb cluster
mariadb_backup Take a backup of MariaDB databases
--full (default)
--incremental
monasca_cleanup Remove unused containers for the Monasca service
bootstrap-servers Bootstrap servers with kolla deploy dependencies
destroy Destroy Kolla containers, volumes and host configuration
--include-images to also destroy Kolla images
--include-dev to also destroy dev mode repos
deploy Deploy and start all kolla containers
deploy-bifrost Deploy and start bifrost container
deploy-servers Enroll and deploy servers with bifrost
deploy-containers Only deploy and start containers (no config updates or bootstrapping)
gather-facts Gather Ansible facts
post-deploy Do post deploy on deploy node
pull Pull all images for containers (only pulls, no running container changes)
reconfigure Reconfigure OpenStack service
stop Stop Kolla containers
certificates Generate self-signed certificate for TLS *For Development Only*
octavia-certificates Generate certificates for octavia deployment
upgrade Upgrades existing OpenStack Environment
upgrade-bifrost Upgrades an existing bifrost container
genconfig Generate configuration files for enabled OpenStack services
prune-images Prune orphaned Kolla images
nova-libvirt-cleanup Clean up disabled nova_libvirt containers
EOF
}
function bash_completion {
cat <<EOF
--inventory -i
--playbook -p
--configdir
--key -k
--help -h
--skip-tags
--tags -t
--extra -e
--passwords
--limit
--forks
--vault-id
--ask-vault-pass
--vault-password-file
--check -C
--diff -D
--verbose -v
--version
install-deps
prechecks
mariadb_recovery
mariadb_backup
monasca_cleanup
bootstrap-servers
destroy
deploy
deploy-bifrost
deploy-containers
deploy-servers
gather-facts
post-deploy
pull
reconfigure
stop
certificates
octavia-certificates
upgrade
upgrade-bifrost
genconfig
prune-images
nova-libvirt-cleanup
EOF
}
function version {
local python_bin
python_bin=$(get_python_bin)
$python_bin -c 'from kolla_ansible.version import version_info; print(version_info)'
}
check_environment_coherence
SHORT_OPTS="hi:p:t:k:e:CD:v"
LONG_OPTS="help,version,inventory:,playbook:,skip-tags:,tags:,key:,extra:,check,diff,verbose,configdir:,passwords:,limit:,forks:,vault-id:,ask-vault-pass,vault-password-file:,yes-i-really-really-mean-it,include-images,include-dev:,full,incremental"
RAW_ARGS="$*"
ARGS=$(getopt -o "${SHORT_OPTS}" -l "${LONG_OPTS}" --name "$0" -- "$@") || { usage >&2; exit 2; }
eval set -- "$ARGS"
find_base_dir
INVENTORY="${BASEDIR}/ansible/inventory/all-in-one"
PLAYBOOK="${BASEDIR}/ansible/site.yml"
VERBOSITY=
EXTRA_OPTS=${EXTRA_OPTS}
CONFIG_DIR="/etc/kolla"
DANGER_CONFIRM=
INCLUDE_IMAGES=
INCLUDE_DEV=
BACKUP_TYPE="full"
# Serial is not recommended and disabled by default. Users can enable it by
# configuring ANSIBLE_SERIAL variable.
ANSIBLE_SERIAL=${ANSIBLE_SERIAL:-0}
INVENTORIES=()
while [ "$#" -gt 0 ]; do
case "$1" in
(--inventory|-i)
INVENTORIES+=("$2")
shift 2
;;
(--playbook|-p)
PLAYBOOK="$2"
shift 2
;;
(--skip-tags)
EXTRA_OPTS="$EXTRA_OPTS --skip-tags $2"
shift 2
;;
(--tags|-t)
EXTRA_OPTS="$EXTRA_OPTS --tags $2"
shift 2
;;
(--check|-C)
EXTRA_OPTS="$EXTRA_OPTS --check"
shift 1
;;
(--diff|-D)
EXTRA_OPTS="$EXTRA_OPTS --diff"
shift 1
;;
(--verbose|-v)
VERBOSITY="$VERBOSITY --verbose"
shift 1
;;
(--configdir)
CONFIG_DIR="$2"
shift 2
;;
(--yes-i-really-really-mean-it)
if [[ ${RAW_ARGS} =~ "$1" ]]
then
DANGER_CONFIRM="$1"
fi
shift 1
;;
(--include-images)
INCLUDE_IMAGES="$1"
shift 1
;;
(--include-dev)
INCLUDE_DEV="$1"
shift 1
;;
(--key|-k)
VAULT_PASS_FILE="$2"
EXTRA_OPTS="$EXTRA_OPTS --vault-password-file=$VAULT_PASS_FILE"
shift 2
;;
(--extra|-e)
EXTRA_OPTS="$EXTRA_OPTS -e $2"
shift 2
;;
(--passwords)
PASSWORDS_FILE="$2"
shift 2
;;
(--limit)
EXTRA_OPTS="$EXTRA_OPTS --limit $2"
shift 2
;;
(--forks)
EXTRA_OPTS="$EXTRA_OPTS --forks $2"
shift 2
;;
(--vault-id)
EXTRA_OPTS="$EXTRA_OPTS --vault-id $2"
shift 2
;;
(--ask-vault-pass)
VERBOSITY="$EXTRA_OPTS --ask-vault-pass"
shift 1
;;
(--vault-password-file)
EXTRA_OPTS="$EXTRA_OPTS --vault-password-file $2"
shift 2
;;
(--full)
BACKUP_TYPE="full"
shift 1
;;
(--incremental)
BACKUP_TYPE="incremental"
shift 1
;;
(--version)
version
exit 0
;;
(--help|-h)
usage
exit 0
;;
(--)
shift
break
;;
(*)
echo "error"
exit 3
;;
esac
done
case "$1" in
(install-deps)
install_deps
exit 0
;;
(prechecks)
ACTION="Pre-deployment checking"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=precheck"
;;
(mariadb_recovery)
ACTION="Attempting to restart mariadb cluster"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=deploy"
PLAYBOOK="${BASEDIR}/ansible/mariadb_recovery.yml"
;;
(mariadb_backup)
ACTION="Backup MariaDB databases"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=backup -e mariadb_backup_type=${BACKUP_TYPE}"
PLAYBOOK="${BASEDIR}/ansible/mariadb_backup.yml"
;;
(monasca_cleanup)
ACTION="Cleanup unused Monasca services"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=cleanup"
PLAYBOOK="${BASEDIR}/ansible/monasca_cleanup.yml"
;;
(destroy)
ACTION="Destroy Kolla containers, volumes and host configuration"
PLAYBOOK="${BASEDIR}/ansible/destroy.yml"
if [[ "${INCLUDE_IMAGES}" == "--include-images" ]]; then
EXTRA_OPTS="$EXTRA_OPTS -e destroy_include_images=yes"
fi
if [[ "${INCLUDE_DEV}" == "--include-dev" ]]; then
EXTRA_OPTS="$EXTRA_OPTS -e destroy_include_dev=yes"
fi
if [[ "${DANGER_CONFIRM}" != "--yes-i-really-really-mean-it" ]]; then
cat << EOF
WARNING:
This will PERMANENTLY DESTROY all deployed kolla containers, volumes and host configuration.
There is no way to recover from this action. To confirm, please add the following option:
--yes-i-really-really-mean-it
EOF
exit 1
fi
;;
(bootstrap-servers)
ACTION="Bootstrapping servers"
PLAYBOOK="${BASEDIR}/ansible/kolla-host.yml"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=bootstrap-servers"
;;
(deploy)
ACTION="Deploying Playbooks"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=deploy"
;;
(deploy-bifrost)
ACTION="Deploying Bifrost"
PLAYBOOK="${BASEDIR}/ansible/bifrost.yml"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=deploy"
;;
(deploy-containers)
ACTION="Deploying Containers"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=deploy-containers"
;;
(deploy-servers)
ACTION="Deploying servers with bifrost"
PLAYBOOK="${BASEDIR}/ansible/bifrost.yml"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=deploy-servers"
;;
(gather-facts)
ACTION="Gathering Ansible facts"
PLAYBOOK="${BASEDIR}/ansible/gather-facts.yml"
;;
(post-deploy)
ACTION="Post-Deploying Playbooks"
PLAYBOOK="${BASEDIR}/ansible/post-deploy.yml"
;;
(pull)
ACTION="Pulling Docker images"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=pull"
;;
(upgrade)
ACTION="Upgrading OpenStack Environment"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=upgrade -e kolla_serial=${ANSIBLE_SERIAL}"
;;
(upgrade-bifrost)
ACTION="Upgrading Bifrost"
PLAYBOOK="${BASEDIR}/ansible/bifrost.yml"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=upgrade"
;;
(reconfigure)
ACTION="Reconfigure OpenStack service"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=reconfigure -e kolla_serial=${ANSIBLE_SERIAL}"
;;
(stop)
ACTION="Stop Kolla containers"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=stop"
if [[ "${DANGER_CONFIRM}" != "--yes-i-really-really-mean-it" ]]; then
cat << EOF
WARNING:
This will stop all deployed kolla containers, limit with tags is possible and also with
skip_stop_containers variable. To confirm, please add the following option:
--yes-i-really-really-mean-it
EOF
exit 1
fi
;;
(certificates)
ACTION="Generate TLS Certificates"
PLAYBOOK="${BASEDIR}/ansible/certificates.yml"
;;
(octavia-certificates)
ACTION="Generate octavia Certificates"
PLAYBOOK="${BASEDIR}/ansible/octavia-certificates.yml"
;;
(genconfig)
ACTION="Generate configuration files for enabled OpenStack services"
EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=config"
;;
(prune-images)
ACTION="Prune orphaned Kolla images"
PLAYBOOK="${BASEDIR}/ansible/prune-images.yml"
if [[ "${DANGER_CONFIRM}" != "--yes-i-really-really-mean-it" ]]; then
cat << EOF
WARNING:
This will PERMANENTLY DELETE all orphaned kolla images. To confirm, please add the following option:
--yes-i-really-really-mean-it
EOF
exit 1
fi
;;
(nova-libvirt-cleanup)
ACTION="Cleanup disabled nova_libvirt containers"
PLAYBOOK="${BASEDIR}/ansible/nova-libvirt-cleanup.yml"
;;
(bash-completion)
bash_completion
exit 0
;;
(*) usage
exit 3
;;
esac
GLOBALS_DIR="${CONFIG_DIR}/globals.d"
EXTRA_GLOBALS=$(find ${GLOBALS_DIR} -maxdepth 1 -type f -name '*.yml' -printf ' -e @%p' || true 2>/dev/null)
PASSWORDS_FILE="${PASSWORDS_FILE:-${CONFIG_DIR}/passwords.yml}"
CONFIG_OPTS="-e @${CONFIG_DIR}/globals.yml ${EXTRA_GLOBALS} -e @${PASSWORDS_FILE} -e CONFIG_DIR=${CONFIG_DIR}"
CMD="ansible-playbook $CONFIG_OPTS $EXTRA_OPTS $PLAYBOOK $VERBOSITY"
for INVENTORY in ${INVENTORIES[@]}; do
CMD="${CMD} --inventory $INVENTORY"
done
process_cmd