#!/bin/bash set -eu set -o pipefail # Library of functions for the kayobe development environment. # Configuration function config_defaults { # Set default values for kayobe development configuration. PARENT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" KAYOBE_SOURCE_PATH_DEFAULT="$(dirname ${PARENT})" # Path to the kayobe source code repository. Typically this will be the # Vagrant shared directory. export KAYOBE_SOURCE_PATH="${KAYOBE_SOURCE_PATH:-$KAYOBE_SOURCE_PATH_DEFAULT}" # Path to the kayobe-config repository checkout. export KAYOBE_CONFIG_SOURCE_PATH="${KAYOBE_CONFIG_SOURCE_PATH:-${KAYOBE_SOURCE_PATH}/config/src/kayobe-config}" # Path to the kayobe virtual environment. export KAYOBE_VENV_PATH="${KAYOBE_VENV_PATH:-${HOME}/kayobe-venv}" # Whether to provision a VM for the seed host. export KAYOBE_SEED_VM_PROVISION=${KAYOBE_SEED_VM_PROVISION:-1} # Whether to configure the seed host. export KAYOBE_SEED_HOST_CONFIGURE=${KAYOBE_SEED_HOST_CONFIGURE:-1} # Whether to build container images for the seed services. If 0, they will # be pulled. export KAYOBE_SEED_CONTAINER_IMAGE_BUILD=${KAYOBE_SEED_CONTAINER_IMAGE_BUILD:-0} # Whether to deploy seed services. export KAYOBE_SEED_SERVICE_DEPLOY=${KAYOBE_SEED_SERVICE_DEPLOY:-1} # Whether to provision a VM for the infra VM host. export KAYOBE_INFRA_VM_PROVISION=${KAYOBE_INFRA_VM_PROVISION:-1} # Whether to configure the infra VM host. export KAYOBE_INFRA_VM_HOST_CONFIGURE=${KAYOBE_INFRA_VM_HOST_CONFIGURE:-1} # Whether to deploy infra VM services. export KAYOBE_INFRA_VM_SERVICE_DEPLOY=${KAYOBE_INFRA_VM_SERVICE_DEPLOY:-1} # Whether to use the 'kolla-ansible certificates' command to generate X.509 # certificates. export KAYOBE_OVERCLOUD_GENERATE_CERTIFICATES=${KAYOBE_OVERCLOUD_GENERATE_CERTIFICATES:-0} # Whether to build container images for the overcloud services. If 0, they # will be pulled if $KAYOBE_OVERCLOUD_CONTAINER_IMAGE_PULL is 1. export KAYOBE_OVERCLOUD_CONTAINER_IMAGE_BUILD=${KAYOBE_OVERCLOUD_CONTAINER_IMAGE_BUILD:-0} # Whether to pull container images for the overcloud services if # $KAYOBE_OVERCLOUD_CONTAINER_IMAGE_BUILD is 0. export KAYOBE_OVERCLOUD_CONTAINER_IMAGE_PULL=${KAYOBE_OVERCLOUD_CONTAINER_IMAGE_PULL:-1} # Whether to deploy overcloud services. export KAYOBE_OVERCLOUD_SERVICE_DEPLOY=${KAYOBE_OVERCLOUD_SERVICE_DEPLOY:-1} # Whether to perform overcloud post configuration. export KAYOBE_OVERCLOUD_POST_CONFIGURE=${KAYOBE_OVERCLOUD_POST_CONFIGURE:-1} # Additional arguments to pass to kayobe commands. export KAYOBE_EXTRA_ARGS=${KAYOBE_EXTRA_ARGS:-} # Use .gitreview as the key to determine the appropriate branch to clone # for tests. Inspired by OSA code. PARENT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ -f "${PARENT}/../.gitreview" ]; then BRANCH=$(awk -F'=' '/defaultbranch/ {print $2}' "${PARENT}/../.gitreview") if [[ "${BRANCH}" == "" ]]; then SERIES="master" else SERIES="$(echo ${BRANCH} | sed -E 's,(stable|unmaintained)/,,')" fi # Upper constraints to use when installing Python packages. export UPPER_CONSTRAINTS_FILE="${UPPER_CONSTRAINTS_FILE:-https://releases.openstack.org/constraints/upper/${SERIES}}" fi # Path to the Tenks virtual environment. export TENKS_VENV_PATH="${TENKS_VENV_PATH:-${HOME}/tenks-test-venv}" # Path to a Tenks YAML configuration file. If unset, # tenks-deploy-config-overcloud.yml or tenks-deploy-config-compute.yml will # be used. export TENKS_CONFIG_PATH=${TENKS_CONFIG_PATH:-} # Log directory in case of errors export LOGDIR=${LOGDIR:-} } function config_set { # Source the configuration file, config.sh PARENT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${PARENT}/config.sh" } function config_check { # Check the configuration environment variables. if [[ ! -e "$KAYOBE_CONFIG_SOURCE_PATH" ]]; then if [[ ${KAYOBE_CONFIG_REQUIRED:-1} -eq 1 ]]; then echo "Kayobe configuration path $KAYOBE_CONFIG_SOURCE_PATH does not exist" return 1 fi fi if [[ ! -e "$KAYOBE_SOURCE_PATH" ]]; then echo "Kayobe source path $KAYOBE_SOURCE_PATH does not exist" return 1 fi } function config_init { config_defaults config_set config_check } # Installation function is_dnf { if [[ -e /etc/centos-release || -e /etc/rocky-release ]]; then /usr/bin/which dnf >/dev/null 2>&1 else return 1 fi } function is_yum { if [[ -e /etc/centos-release || -e /etc/rocky-release ]]; then /usr/bin/which yum >/dev/null 2>&1 else return 1 fi } function get_python { if is_dnf; then echo python3.12 else echo python3 fi } function install_dependencies { echo "Installing package dependencies for kayobe" if is_dnf; then sudo dnf -y install gcc git vim python3-devel python3-pyyaml libffi-devel python3.12-devel python3.12 python3.12-pyyaml elif is_yum; then echo "CentOS 7 is no longer supported" exit 1 else sudo apt update sudo apt install -y python-is-python3 python3-dev python3-venv gcc git libffi-dev fi } function install_venv { # Install a virtualenv at $1. The rest of the arguments are passed # directly to pip. venv_path="$1" shift pip_paths="$@" local venv_parent="$(dirname ${venv_path})" if [[ ! -d "$venv_parent" ]]; then mkdir -p "$venv_parent" fi if [[ ! -f "${venv_path}/bin/activate" ]]; then echo "Creating virtual environment in ${venv_path}" $(get_python) -m venv "${venv_path}" # NOTE: Virtualenv's activate and deactivate scripts reference an # unbound variable. set +u source "${venv_path}/bin/activate" pip install -U pip pip install $pip_paths deactivate set -u else echo "Using existing virtual environment in ${venv_path}" fi } function install_venv_system_site_packages { # Install a virtualenv at $1. The rest of the arguments are passed # directly to pip. venv_path="$1" shift pip_paths="$@" local venv_parent="$(dirname ${venv_path})" if [[ ! -d "$venv_parent" ]]; then mkdir -p "$venv_parent" fi if [[ ! -f "${venv_path}/bin/activate" ]]; then echo "Creating virtual environment in ${venv_path}" # NOTE(wszumski): tenks doesn't currently support not using the system python # interpreter with: "Failed to detect selinux python bindings" /usr/bin/python3 -m venv --system-site-packages "${venv_path}" # NOTE: Virtualenv's activate and deactivate scripts reference an # unbound variable. set +u source "${venv_path}/bin/activate" pip install -U pip pip install $pip_paths deactivate set -u else echo "Using existing virtual environment in ${venv_path}" fi } function install_kayobe_venv { # Install the Kayobe venv. install_venv "${KAYOBE_VENV_PATH}" "${KAYOBE_SOURCE_PATH}" } function install_kayobe_dev_venv { # Install Kayobe in the venv in editable mode. install_venv "${KAYOBE_VENV_PATH}" -e "${KAYOBE_SOURCE_PATH}" } function upgrade_kayobe_venv { echo "Upgrading kayobe virtual environment in ${KAYOBE_VENV_PATH}" # NOTE(wszumski): We need to recreate the old virtualenv to switch to python3.12 rm -rf "${KAYOBE_VENV_PATH}" $(get_python) -m venv "${KAYOBE_VENV_PATH}" # NOTE: Virtualenv's activate and deactivate scripts reference an # unbound variable. set +u source "${KAYOBE_VENV_PATH}/bin/activate" pip install -U pip pip install -U "${KAYOBE_SOURCE_PATH}" deactivate set -u } # Deployment function is_deploy_image_built_locally { ipa_build_images=$(kayobe configuration dump --host localhost --var-name ipa_build_images) to_bool "$ipa_build_images" } function is_ironic_enabled { ironic_enabled=$(kayobe configuration dump --host localhost --var-name kolla_enable_ironic) to_bool "$ironic_enabled" } function is_overcloud_host_image_built_by_dib { overcloud_dib_build_host_images=$(kayobe configuration dump --host localhost --var-name overcloud_dib_build_host_images) to_bool "$overcloud_dib_build_host_images" } function is_cinder_enabled { flag="$(run_kayobe configuration dump --host localhost --var-name kolla_enable_cinder)" to_bool "$flag" } function is_octavia_enabled { octavia_enabled=$(kayobe configuration dump --host localhost --var-name kolla_enable_octavia) to_bool "$octavia_enabled" } function are_octavia_certificates_present { [[ -f ${KAYOBE_CONFIG_PATH}/kolla/config/octavia/client_ca.cert.pem && -f ${KAYOBE_CONFIG_PATH}/kolla/config/octavia/client.cert-and-key.pem && -f ${KAYOBE_CONFIG_PATH}/kolla/config/octavia/server_ca.cert.pem && -f ${KAYOBE_CONFIG_PATH}/kolla/config/octavia/server_ca.key.pem ]] } function environment_setup { # NOTE: Virtualenv's activate script references an unbound variable. set +u source "${KAYOBE_VENV_PATH}/bin/activate" set -u source "${KAYOBE_CONFIG_SOURCE_PATH}/kayobe-env" "$@" } function run_kayobe { # Run a kayobe command, including extra arguments provided via # $KAYOBE_EXTRA_ARGS. kayobe ${KAYOBE_EXTRA_ARGS} $* } function control_host_bootstrap { attempts=10 interval=5 echo "Bootstrapping the Ansible control host" for i in $(seq 1 $attempts); do if run_kayobe control host bootstrap; then chb_success=1 break fi echo "Control host bootstrap failed - likely Ansible Galaxy flakiness. Sleeping $interval seconds before retrying" sleep $interval done if [[ -z ${chb_success+x} ]]; then die $LINENO "Failed to bootstrap control host" exit 1 fi echo "Bootstrapped control host after $i attempts" } function control_host_upgrade { attempts=10 interval=5 echo "Upgrading the Ansible control host" for i in $(seq 1 $attempts); do if run_kayobe control host upgrade; then chu_success=1 break fi echo "Control host upgrade failed - likely Ansible Galaxy flakiness. Sleeping $interval seconds before retrying" sleep $interval done if [[ -z ${chu_success+x} ]]; then die $LINENO "Failed to upgrade control host" exit 1 fi echo "Upgraded control host after $i attempts" } function seed_hypervisor_deploy { # Deploy a seed hypervisor. environment_setup control_host_bootstrap echo "Configuring the seed hypervisor" run_kayobe seed hypervisor host configure } function seed_deploy { # Deploy a kayobe seed in a VM. environment_setup control_host_bootstrap if [[ ${KAYOBE_SEED_VM_PROVISION} = 1 ]]; then echo "Provisioning the seed VM" run_kayobe seed vm provision fi if [[ ${KAYOBE_SEED_HOST_CONFIGURE} = 1 ]]; then echo "Configuring the seed host" run_kayobe seed host configure fi if [[ ${KAYOBE_SEED_CONTAINER_IMAGE_BUILD} = 1 ]]; then echo "Building seed container images" run_kayobe seed container image build else echo "Not pulling seed container images - no such command yet" #run_kayobe seed container image pull fi if [[ ${KAYOBE_SEED_SERVICE_DEPLOY} = 1 ]]; then echo "Deploying containerised seed services" run_kayobe seed service deploy fi if is_deploy_image_built_locally; then echo "Building seed deployment images" run_kayobe seed deployment image build else echo "Not building seed deployment images" fi if is_overcloud_host_image_built_by_dib; then echo "Building overcloud host images" run_kayobe overcloud host image build else echo "Not building overcloud host images" fi } function seed_upgrade { # Upgrade a kayobe seed in a VM. echo "Upgrading Kayobe" upgrade_kayobe_venv environment_setup control_host_upgrade echo "Upgrading the seed host" run_kayobe seed host upgrade if is_deploy_image_built_locally; then echo "Building seed deployment images" run_kayobe seed deployment image build --force-rebuild else echo "Not building seed deployment images" fi if [[ ${KAYOBE_SEED_CONTAINER_IMAGE_BUILD} = 1 ]]; then echo "Building seed container images" run_kayobe seed container image build else echo "Not pulling seed container images - no such command yet" #run_kayobe seed container image pull fi echo "Upgrading containerised seed services" run_kayobe seed service upgrade } function infra_vm_deploy { # Deploy a kayobe infra VM. environment_setup control_host_bootstrap if [[ ${KAYOBE_INFRA_VM_PROVISION} = 1 ]]; then echo "Provisioning the infra VM" run_kayobe infra vm provision fi if [[ ${KAYOBE_INFRA_VM_HOST_CONFIGURE} = 1 ]]; then echo "Configuring the infra VM host" run_kayobe infra vm host configure fi if [[ ${KAYOBE_INFRA_VM_SERVICE_DEPLOY} = 1 ]]; then echo "Deploying containerised infra VM services" run_kayobe infra vm service deploy fi } function overcloud_deploy { # Deploy a kayobe control plane. echo "Deploying a kayobe development environment. This consists of a " echo "single node OpenStack control plane." environment_setup control_host_bootstrap if [[ ${KAYOBE_OVERCLOUD_GENERATE_CERTIFICATES} = 1 ]]; then echo "Generate TLS certificates" run_kayobe playbook run $KAYOBE_SOURCE_PATH/ansible/kolla-ansible.yml -t config # NOTE(mgoddard): There is a chicken and egg when generating libvirt # TLS certificates using the kolla-ansible certificates command, and # host libvirt. The certificates command needs to be able to gather # facts for all hosts, but since the host configure step hasn't been # run, we don't have SSH or the kolla user configured yet. However, we # can't run host configure without the libvirt TLS certificates. # Workaround: add the host to SSH known hosts and SSH as $USER. run_kayobe playbook run $KAYOBE_SOURCE_PATH/ansible/ssh-known-host.yml -l overcloud # Avoid populating the fact cache with this weird setup. export ANSIBLE_CACHE_PLUGIN=memory run_kayobe kolla ansible run certificates \ --kolla-extra kolla_certificates_dir=${KAYOBE_CONFIG_PATH}/kolla/certificates \ --kolla-extra ansible_user=$USER \ --kolla-extra ansible_python_interpreter=/usr/bin/python3 \ --skip-tags kolla-openstack unset ANSIBLE_CACHE_PLUGIN # Add CA cert to trust store. ca_cert=${KAYOBE_CONFIG_PATH}/kolla/certificates/ca/root.crt if [[ -e /etc/debian_version ]]; then # Ubuntu sudo cp $ca_cert "/usr/local/share/ca-certificates/kayobe-customca.crt" sudo update-ca-certificates elif [[ -e /etc/redhat-release ]]; then # CentOS sudo cp $ca_cert "/etc/pki/ca-trust/source/anchors/kayobe-customca.crt" sudo update-ca-trust fi fi echo "Configuring the controller host" run_kayobe overcloud host configure # FIXME(mgoddard): Perform host upgrade workarounds to ensure hostname # resolves to IP address of API interface for RabbitMQ. This seems to be # required since https://review.openstack.org/#/c/584427 was merged. echo "Workaround: upgrading the controller host" run_kayobe overcloud host upgrade # Note: This must currently be before host configure, because host # configure runs kolla-ansible.yml, which validates the presence of the # built deploy images. if is_deploy_image_built_locally; then echo "Building overcloud deployment images" run_kayobe overcloud deployment image build else echo "Not building overcloud deployment images" fi if [[ ${KAYOBE_OVERCLOUD_CONTAINER_IMAGE_BUILD} = 1 ]]; then echo "Building overcloud container images" run_kayobe overcloud container image build elif [[ ${KAYOBE_OVERCLOUD_CONTAINER_IMAGE_PULL} = 1 ]]; then echo "Pulling overcloud container images" run_kayobe overcloud container image pull fi if [[ ${KAYOBE_OVERCLOUD_SERVICE_DEPLOY} = 1 ]]; then if is_octavia_enabled && ! are_octavia_certificates_present; then echo "Generating Octavia certificates" run_kayobe kolla ansible run octavia-certificates mkdir -p ${KAYOBE_CONFIG_PATH}/kolla/config/octavia cp ${KOLLA_CONFIG_PATH:-/etc/kolla}/config/octavia/*.pem ${KAYOBE_CONFIG_PATH}/kolla/config/octavia/ fi echo "Deploying containerised overcloud services" run_kayobe overcloud service deploy fi if [[ ${KAYOBE_OVERCLOUD_POST_CONFIGURE} = 1 ]]; then echo "Performing post-deployment configuration" source "${KOLLA_CONFIG_PATH:-/etc/kolla}/admin-openrc.sh" run_kayobe overcloud post configure fi echo "Control plane deployment complete" } function overcloud_upgrade { # Upgrade a kayobe control plane. echo "Upgrading a kayobe development environment. This consists of a " echo "single node OpenStack control plane." echo "Upgrading Kayobe" upgrade_kayobe_venv environment_setup control_host_upgrade echo "Upgrading the controller host" run_kayobe overcloud host upgrade if is_deploy_image_built_locally; then echo "Building overcloud deployment images" run_kayobe overcloud deployment image build --force-rebuild else echo "Not building overcloud deployment images" fi echo "Updating baremetal deployment images" (source "${KOLLA_CONFIG_PATH:-/etc/kolla}/admin-openrc.sh" && run_kayobe baremetal compute update deployment image) if [[ ${KAYOBE_OVERCLOUD_CONTAINER_IMAGE_BUILD} = 1 ]]; then echo "Building overcloud container images" run_kayobe overcloud container image build else echo "Pulling overcloud container images" run_kayobe overcloud container image pull fi echo "Saving overcloud service configuration" # Don't copy the ironic IPA kernel and ramdisk, since these files can be # quite large. run_kayobe overcloud service configuration save --exclude 'ironic-agent.*' echo "Deploying containerised overcloud services" run_kayobe overcloud service upgrade echo "Control plane upgrade complete" } function overcloud_test_init { echo "Performing overcloud test init" environment_setup if [[ ! -z "$UPPER_CONSTRAINTS_FILE" ]]; then pip install python-openstackclient -c "$UPPER_CONSTRAINTS_FILE" else pip install python-openstackclient fi source "${KOLLA_CONFIG_PATH:-/etc/kolla}/admin-openrc.sh" # This guards init-runonce from running more than once if mkdir /tmp/init-runonce > /dev/null 2>&1; then echo "Running kolla-ansible init-runonce" if is_ironic_enabled; then # Don't create an external network, since it conflicts with the # ironic provision-net. export ENABLE_EXT_NET=${ENABLE_EXT_NET:-0} else # Use the all-in-one network as the external network. There is # currently no option to avoid setting a gateway, so use the # controller's IP. export EXT_NET_CIDR="${EXT_NET_CIDR:-192.168.33.0/24}" export EXT_NET_RANGE="${EXT_NET_RANGE:-start=192.168.33.31,end=192.168.33.127}" export EXT_NET_GATEWAY="${EXT_NET_GATEWAY:-192.168.33.3}" fi ${KOLLA_VENV_PATH:-$HOME/kolla-venv}/share/kolla-ansible/init-runonce if is_ironic_enabled; then unset ENABLE_EXT_NET # Allow provision-net to be used as an external network for # floating IPs. # Note: a provisioning network would not normally be external. openstack network set provision-net --external openstack router set demo-router --external-gateway provision-net fi else echo "Not running kolla-ansible init-runonce - resources exist" fi } function overcloud_test { set -eu # function arguments name="$1" flavor="$2" network="$3" node_config="{ 'name': '$name', 'flavor': '$flavor', 'network': '$network' }" overcloud_test_init # Perform a simple smoke test against the cloud. echo "Performing a simple smoke test with node config: $node_config" echo "$name: Creating a server" openstack server create --wait --image cirros --flavor "$flavor" --key-name mykey --network "$network" "$name" echo "$name: Server created" openstack server show "$name" status=$(openstack server show "$name" -f value -c status) if [[ $status != ACTIVE ]]; then echo "$name: Node creation failed" return 1 fi # Test SSH connectivity. For servers attached directly to the external # network, use the fixed IP. Otherwise add a floating IP. if [[ $network = provision-net ]]; then port_id=$(openstack port list --server $name --network $network -f value -c ID) echo "port $port_id" fixed_ips=$(openstack port show $port_id -f json -c fixed_ips) echo "fixed_ips $fixed_ips" ip=$(echo $fixed_ips | python3 -c "import json,sys; print(json.load(sys.stdin)['fixed_ips'][0]['ip_address'])") echo "ip $ip" else echo "$name: Attaching floating IP" if is_ironic_enabled; then floating_net=provision-net else floating_net=public1 fi ip=$(openstack floating ip create $floating_net -f value -c floating_ip_address) openstack server add floating ip ${name} ${ip} fi echo "$name: Waiting for ping and SSH access via ${ip}" attempts=12 for i in $(seq 1 $attempts); do if ping -c1 -W1 $ip && ssh -v -o StrictHostKeyChecking=no -o BatchMode=yes cirros@$ip hostname; then break elif [[ $i -eq $attempts ]]; then echo "Failed to access server $name via SSH after $attempts attempts" echo "Console log:" openstack console log show ${name} return 1 else echo "Cannot access server $name - retrying" fi sleep 10 done echo "$name: Ping and SSH successful" if [[ $network != provision-net ]]; then echo "$name: Removing floating IP" openstack server remove floating ip ${name} ${ip} openstack floating ip delete ${ip} fi echo "$name: Deleting the Node" openstack server delete --wait "$name" } function write_bifrost_clouds_yaml { SEED_IP="192.168.33.5" # Pull clouds.yaml from Bifrost container and change certificate path. if [[ ! -f ~/.config/openstack/clouds.yaml ]]; then mkdir -p ~/.config/openstack scp stack@$SEED_IP:/home/stack/.config/openstack/clouds.yaml ~/.config/openstack/clouds.yaml sed -i 's|/home/stack/.config/openstack/bifrost.crt|~/.config/openstack/bifrost.crt|g' ~/.config/openstack/clouds.yaml else echo "Not updating clouds.yaml file because it already exists at $HOME/.config/openstack/clouds.yaml. Try removing it if authentication against Bifrost fails." fi #Pull Bifrost PEM certificate from seed. if [[ ! -f ~/.config/openstack/bifrost.crt ]]; then mkdir -p ~/.config/openstack scp stack@$SEED_IP:/home/stack/.config/openstack/bifrost.crt ~/.config/openstack/bifrost.crt else echo "Not updating Bifrost certificate file because it already exists at $HOME/.config/openstack/bifrost.crt. Try removing it if authentication against Bifrost fails." fi } function run_tenks_playbook { # Run a Tenks playbook. Arguments: # $1: The path to the Tenks repo. # $2: The name of the playbook to run. local tenks_path="$1" local tenks_playbook="$2" local tenks_deploy_type="${3:-default}" local parent="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ ! -f "${KOLLA_CONFIG_PATH:-/etc/kolla}/admin-openrc.sh" && "${tenks_deploy_type}" = "compute" ]]; then die $LINENO "Missing admin-openrc.sh & tenks_deploy_type is compute." exit 1 fi if [[ -f "${KOLLA_CONFIG_PATH:-/etc/kolla}/admin-openrc.sh" && ( "${tenks_deploy_type}" = "default" || "${tenks_deploy_type}" = "compute" ) ]]; then # Deploys Compute from Overcloud default_tenks_config=tenks-deploy-config-compute.yml source "${KOLLA_CONFIG_PATH:-/etc/kolla}/admin-openrc.sh" elif [[ "${tenks_deploy_type}" = "default" || "${tenks_deploy_type}" = "overcloud" ]]; then # Deploys Overcloud from Seed default_tenks_config=tenks-deploy-config-overcloud.yml write_bifrost_clouds_yaml export OS_CLOUD=bifrost else die $LINENO "Bad tenks_deploy_type: ${tenks_deploy_type}" exit 1 fi # Allow a specific Tenks config file to be specified via # $TENKS_CONFIG_PATH. tenks_config="${TENKS_CONFIG_PATH:-$parent/$default_tenks_config}" ansible-playbook \ -vvv \ --inventory "$tenks_path/ansible/inventory" \ --extra-vars=@"$tenks_config" \ "$tenks_path/ansible/$tenks_playbook" } function tenks_deploy { set -eu # Create a simple test Tenks deployment. Assumes that a bridge named # 'breth1' exists. Arguments: # $1: The path to the Tenks repo. local tenks_path="$1" local tenks_deploy_type="${2:-default}" echo "Configuring Tenks" environment_setup # We don't want to use the Kayobe venv. deactivate # Install the Tenks venv. install_venv_system_site_packages "${TENKS_VENV_PATH}" "$tenks_path" -c "$UPPER_CONSTRAINTS_FILE" source ${TENKS_VENV_PATH:-$HOME/tenks-test-venv}/bin/activate ${KAYOBE_SOURCE_PATH}/tools/ansible-galaxy-retried.sh install \ --role-file="$tenks_path/requirements.yml" \ --roles-path="$tenks_path/ansible/roles/" local parent="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Install a trivial script for ovs-vsctl that talks to containerised Open # vSwitch. sudo cp --no-clobber "$parent/ovs-vsctl" /usr/bin/ovs-vsctl run_tenks_playbook "$tenks_path" deploy.yml "$tenks_deploy_type" } function tenks_teardown { set -eu # Tear down a test Tenks deployment. # Arguments: # $1: The path to the Tenks repo. local tenks_path="$1" local tenks_deploy_type="${2:-default}" echo "Tearing down Tenks" environment_setup # We don't want to use the Kayobe venv. deactivate # Source the Tenks venv. source ${TENKS_VENV_PATH:-$HOME/tenks-test-venv}/bin/activate run_tenks_playbook "$tenks_path" teardown.yml "$tenks_deploy_type" } # General purpose # Prints backtrace info # filename:lineno:function # backtrace level function backtrace { local level=$1 local deep deep=$((${#BASH_SOURCE[@]} - 1)) echo "[Call Trace]" while [ $level -le $deep ]; do echo "${BASH_SOURCE[$deep]}:${BASH_LINENO[$deep-1]}:${FUNCNAME[$deep-1]}" deep=$((deep - 1)) done } # Prints line number and "message" then exits # die $LINENO "message" function die { local exitcode=$? set +o xtrace local line=$1; shift if [ $exitcode == 0 ]; then exitcode=1 fi backtrace 2 err $line "$*" # Give buffers a second to flush sleep 1 exit $exitcode } # Prints line number and "message" in error format # err $LINENO "message" function err { local exitcode=$? local xtrace xtrace=$(set +o | grep xtrace) set +o xtrace local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2" echo "$msg" 1>&2; if [[ -n ${LOGDIR} ]]; then echo "$msg" >> "${LOGDIR}/error.log" fi $xtrace return $exitcode } function die_if_module_not_loaded { if ! grep -q $1 /proc/modules; then die $LINENO "$1 kernel module is not loaded" fi } # running_in_container - Returns true otherwise false function running_in_container { [[ $(systemd-detect-virt --container) != 'none' ]] } # enable_kernel_bridge_firewall - Enable kernel support for bridge firewalling function enable_kernel_bridge_firewall { # Load bridge module. This module provides access to firewall for bridged # frames; and also on older kernels (pre-3.18) it provides sysctl knobs to # enable/disable bridge firewalling sudo modprobe bridge # For newer kernels (3.18+), those sysctl settings are split into a separate # kernel module (br_netfilter). Load it too, if present. sudo modprobe br_netfilter 2>> /dev/null || : # Enable bridge firewalling in case it's disabled in kernel (upstream # default is enabled, but some distributions may decide to change it). # This is at least needed for RHEL 7.2 and earlier releases. for proto in ip ip6; do sudo sysctl -w net.bridge.bridge-nf-call-${proto}tables=1 done } function to_bool { if [[ "$1" =~ (y|Y|yes|Yes|YES|true|True|TRUE|on|On|ON) ]]; then true elif [[ "$1" =~ (n|N|no|No|NO|false|False|FALSE|off|Off|OFF) ]]; then false else die $LINENO "$1 was not a valid yaml boolean" fi } function configure_iptables { # NOTE(wszumski): adapted from the ironic devstack plugin, see: # https://github.com/openstack/ironic/blob/36e87dc5b472d79470b783fbba9ce396e3cbb96e/devstack/lib/ironic#L2132 set -eu environment_setup # FIXME(wszumski): set these variables with values from kayobe-config HOST_IP='192.168.33.3' INTERNAL_VIP='192.168.33.2' IRONIC_TFTPSERVER_IP="$HOST_IP" IRONIC_SERVICE_PORT=6385 IRONIC_INSPECTOR_PORT=5050 IRONIC_HTTP_SERVER="$INTERNAL_VIP" GLANCE_SERVICE_PORT=9292 IRONIC_HTTP_PORT=8089 ISCSI_SERVICE_PORT=3260 # enable tftp natting for allowing connections to HOST_IP's tftp server if ! running_in_container; then sudo modprobe nf_conntrack_tftp sudo modprobe nf_nat_tftp enable_kernel_bridge_firewall else die_if_module_not_loaded nf_conntrack_tftp die_if_module_not_loaded nf_nat_tftp fi # explicitly allow DHCP - packets are occasionally being dropped here sudo iptables -I INPUT -p udp --dport 67:68 --sport 67:68 -j ACCEPT || true # nodes boot from TFTP and callback to the API server listening on $HOST_IP sudo iptables -I INPUT -d $IRONIC_TFTPSERVER_IP -p udp --dport 69 -j ACCEPT || true sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true # open ironic API on baremetal network sudo iptables -I INPUT -d $IRONIC_HTTP_SERVER -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true # Docker CE has added a default DROP policy to the FORWARD chain. # When nova-compute runs on the controller, kolla ansible sets the # net.bridge.bridge-nf-call-iptables sysctl to 1, which causes iptables to # process frames forwarded across bridges. Forward all frames on the main # bridge, breth1. sudo iptables -A FORWARD -i breth1 -j ACCEPT || true # agent ramdisk gets instance image from swift sudo iptables -I INPUT -d $INTERNAL_VIP -p tcp --dport ${SWIFT_DEFAULT_BIND_PORT:-8080} -j ACCEPT || true sudo iptables -I INPUT -d $INTERNAL_VIP -p tcp --dport $GLANCE_SERVICE_PORT -j ACCEPT || true sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $IRONIC_HTTP_PORT -j ACCEPT || true if is_cinder_enabled; then sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $ISCSI_SERVICE_PORT -j ACCEPT || true fi }