diff --git a/.automation.conf/run-tempest.sh b/.automation.conf/run-tempest.sh new file mode 100755 index 000000000..72f9eba85 --- /dev/null +++ b/.automation.conf/run-tempest.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# Script based on tempest section of Kayobe multinode deployment script +# plus https://wiki.stackhpc.com/doc/using-kayobe-automation-to-run-tempest-7yAEJw2eHb + +set -euxo pipefail + +KAYOBE_CONFIG_BASE_PATH=$KAYOBE_CONFIG_PATH/../../ + +set +x +export KAYOBE_AUTOMATION_SSH_PRIVATE_KEY=$(cat ~/.ssh/id_rsa) +export TEMPEST_OPENRC="$(< $KAYOBE_CONFIG_PATH/../kolla/admin-openrc.sh)" +set -x + +# Ensure timestamped output dir exists +OUTPUT_DIR=$KAYOBE_CONFIG_BASE_PATH/tempest-artifacts/$KAYOBE_ENVIRONMENT/$(date +%Y-%m-%d--T%H-%M-%S) +echo Creating output directory: $OUTPUT_DIR +mkdir -p $OUTPUT_DIR + + +# Set base image for kayobe container. Use rocky 9 for zed+ CentOS otherwise +if grep -Eq "(202|zed)" $KAYOBE_CONFIG_BASE_PATH/.gitreview; then + export BASE_IMAGE=rockylinux:9 +else + export BASE_IMAGE=quay.io/centos/centos:stream8 +fi + +IMAGE_TAG="kayobe" +if [[ "$(sudo docker image ls)" == *$IMAGE_TAG* ]]; then + echo "Image already exists skipping docker build" +else + sudo DOCKER_BUILDKIT=1 docker build \ + --network host \ + --build-arg BASE_IMAGE=$BASE_IMAGE \ + --build-arg HTTP_PROXY=$http_proxy \ + --build-arg HTTPS_PROXY=$https_proxy \ + --build-arg NO_PROXY=$no_proxy \ + --file $KAYOBE_CONFIG_BASE_PATH/.automation/docker/kayobe/Dockerfile \ + --tag $IMAGE_TAG:latest $KAYOBE_CONFIG_BASE_PATH +fi + +sudo -E docker run --rm \ + --name kayobe_automation \ + --network host \ + -v $KAYOBE_CONFIG_BASE_PATH:/stack/kayobe-automation-env/src/kayobe-config \ + -v $OUTPUT_DIR:/stack/tempest-artifacts \ + -e KAYOBE_ENVIRONMENT -e KAYOBE_VAULT_PASSWORD -e KAYOBE_AUTOMATION_SSH_PRIVATE_KEY \ + -e TEMPEST_OPENRC \ + $IMAGE_TAG:latest \ + /stack/kayobe-automation-env/src/kayobe-config/.automation/pipeline/tempest.sh \ + -e ansible_user=stack -e rally_no_sensitive_log=false + +# Fix output dir ownership +sudo chown -R stack:stack $OUTPUT_DIR + +# Uncomment to copy failures into a load list for easy retry +# cp $OUTPUT_DIR/failed-tests $KAYOBE_CONFIG_BASE_PATH/.automation.conf/tempest/load-lists/$KAYOBE_ENVIRONMENT-failed-tests diff --git a/.automation.conf/tempest-cleanup.sh b/.automation.conf/tempest-cleanup.sh new file mode 100755 index 000000000..f5a392c47 --- /dev/null +++ b/.automation.conf/tempest-cleanup.sh @@ -0,0 +1,109 @@ +#!/bin/bash + +# Helper script that will attempt to delete leftover resources from tempest testing. +# Usage: tempest-cleanup.sh [--dry-run] + +# NOTE: This script is provided as a convenience and may not cover all +# resources created by tempest. In particular, it does not attempt to delete +# floating IPs and can have issues with ports attached to other resources. Use +# with caution. + +DRY_RUN=false + +if [[ $1 == "--dry-run" ]]; then + DRY_RUN=true + echo "Dry run mode activated. No resources will be deleted." +fi + +# Ensure openstack CLI is available +if ! command -v openstack > /dev/null; then + echo "openstack command not found. Ensure you have sourced a virtual environment with the openstack CLI installed." + exit 1 +elif ! openstack network list > /dev/null; then + echo "openstack command failed. Ensure you have sourced an openrc file." + exit 1 +fi + +# Function to delete ports based on subnet IDs +function delete_ports { + local subnet_ids=$1 + for subnet_id in $subnet_ids; do + port_ids=$(openstack port list --fixed-ip subnet=$subnet_id -f value -c ID) + if [[ -z $port_ids ]]; then + echo "No ports found for subnet $subnet_id" + continue + fi + for port_id in $port_ids; do + local port_name=$(openstack port show $port_id -f value -c name) + local device_owner=$(openstack port show $port_id -f value -c device_owner) + if [[ $device_owner == "network:router_interface" ]] || [[ $device_owner == "network:ha_router_replicated_interface" ]]; then + local router_id=$(openstack port show $port_id -f value -c device_id) + if $DRY_RUN; then + echo "Would remove router interface on port $port_id $port_name from router $router_id" + else + echo "Removing router interface on port $port_id $port_name from router $router_id..." + openstack router remove port $router_id $port_id || echo "Failed to remove router interface on port $port_id $port_name from router $router_id" + fi + fi + if $DRY_RUN; then + echo "Would delete port $port_id $port_name" + else + echo "Deleting port $port_id $port_name..." + openstack port delete $port_id || echo "Failed to delete port $port_id $port_name" + fi + done + done +} + +# Function to delete resources based on type and name prefix +function delete_resources { + local resource_type=$1 + local name_prefix=$2 + # If resource type is server, volume, or image, list all + if [[ $resource_type == "server" ]] || [[ $resource_type == "volume" ]] || [[ $resource_type == "image" ]]; then + id_name_list=$(openstack $resource_type list --all -f value -c ID -c Name | awk -v prefix="$name_prefix" '$2 ~ "^"prefix {print $1, $2}') + else + id_name_list=$(openstack $resource_type list -f value -c ID -c Name | awk -v prefix="$name_prefix" '$2 ~ "^"prefix {print $1, $2}') + fi + if [[ -z $id_name_list ]]; then + echo "No $resource_type resources found with prefix $name_prefix" + return + fi + while IFS= read -r line; do + local resource_id=$(echo $line | awk '{print $1}') + local resource_name=$(echo $line | awk '{$1=""; print $0}') + if $DRY_RUN; then + echo "Would delete $resource_type $resource_id $resource_name" + else + echo "Deleting $resource_type $resource_id $resource_name..." + openstack $resource_type delete $resource_id || echo "Failed to delete $resource_type $resource_id $resource_name" + fi + done <<< "$id_name_list" +} + +function cleanup { + local name_prefix=$1 + echo "Getting network and subnet IDs with $name_prefix prefix (may take a while)" + + # Get subnet IDs associated with tempest networks + TEMPEST_NETWORK_IDS=$(openstack network list -f value -c ID -c Name | awk -v prefix="$TEMPEST_PREFIX" '$2 ~ "^"prefix {print $1}') + TEMPEST_SUBNET_IDS="" + for network_id in $TEMPEST_NETWORK_IDS; do + TEMPEST_SUBNET_IDS+=" $(openstack subnet list --network $network_id -f value -c ID)" + done + + # Delete resources in the specified order + delete_resources server $name_prefix + delete_ports "$TEMPEST_SUBNET_IDS" + delete_resources volume $name_prefix + delete_resources router $name_prefix + delete_resources network $name_prefix + delete_resources image $name_prefix + delete_resources user $name_prefix + delete_resources project $name_prefix +} + +cleanup tempest- +cleanup rally_ + +echo "Operation completed." diff --git a/releasenotes/notes/tempest-scripts-fe80b699af767753.yaml b/releasenotes/notes/tempest-scripts-fe80b699af767753.yaml new file mode 100644 index 000000000..f4e77e6b3 --- /dev/null +++ b/releasenotes/notes/tempest-scripts-fe80b699af767753.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Added a new convenience script `.automation.conf/run-tempest.sh` to run + Tempest tests. + - | + Added a new convenience script `.automation.conf/tempest-cleanup.sh` which + will attempt to clear away resources left behind by Tempest testing.