#!/usr/bin/env bash # # This script can be used to interact with kolla via ansible. # do not use _PYTHON_BIN directly, use $(get_python_bin) instead _PYTHON_BIN="" 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 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 local ANSIBLE_VERSION_MIN=2.11 local ANSIBLE_VERSION_MAX=2.12 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 < Specify path to ansible inventory file. \ Can be specified multiple times to pass multiple inventories. --playbook, -p Specify path to ansible playbook file --configdir Specify path to directory with globals.yml --key -k Specify path to ansible vault keyfile --help, -h Show this usage information --tags, -t Only run plays and tasks tagged with these values --skip-tags Only run plays and tasks whose tags do not match these values --extra, -e Set additional variables as key=value or YAML/JSON passed to ansible-playbook --passwords Specify path to the passwords file --limit Specify host to run plays --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 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 <&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' 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