Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add openstack charm func test runner #220

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions openstack/tools/charmed_openstack_functest_runner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/bin/bash -eu
#
# Run Charmed Openstack CI tests manually in a similar way to how they are run
# by OpenStack CI (OSCI).
#
# Usage: clone/fetch charm to test and run from within charm root dir.
#
FUNC_TEST_PR=
FUNC_TEST_TARGET=
MODIFY_BUNDLE_CONSTRAINTS=true
SKIP_BUILD=false

usage () {
cat << EOF
USAGE: `basename $0` OPTIONS
Run OpenStack charms functional tests manually in a similar way to how
Openstack CI (OSCI) would do it. This tool should be run from within a charm
root.
Not all charms use the same versions and dependencies and an attempt is made to
cover this here but in some cases needs to be dealt with as a pre-requisite to
running the tool. For example some charms need their tests to be run using
python 3.8 and others python 3.10. Some tests might require Juju 2.9 and others
Juju 3.x - the assumption in this runner is that Juju 3.x is ok to use.
OPTIONS:
--func-test-target
Provide the name of a specific test target to run. If none provided
all tests are run based on what is defined in osci.yaml i.e. will do
what osci would do by default.
--func-test-pr
Provides similar functionality to Func-Test-Pr in commit message. Set
to zaza-openstack-tests Pull Request ID.
--skip-build
Skip building charm if already done to save time.
--skip-modify-bundle-constraints
By default we modify test bundle constraints to ensure that applications
have the resources they need. For example nova-compute needs to have
enough capacity to boot the vms required by the tests.
--help
This help message.
EOF
}

while (($# > 0))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you call the script without any arguments and you're not inside a charm directory it eventually fails. It should check for the current directory being a charm somehow.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i will fix this as a followup patch but have put info in the help message about how to run the tool

do
case "$1" in
--func-test-target)
FUNC_TEST_TARGET=$2
shift
;;
--func-test-pr)
FUNC_TEST_PR=$2
shift
;;
--skip-modify-bundle-constraints)
MODIFY_BUNDLE_CONSTRAINTS=false
;;
--skip-build)
SKIP_BUILD=true
;;
--help|-h)
usage
exit 0
;;
*)
echo "ERROR: invalid input '$1'"
usage
exit 1
;;
esac
shift
done

set -x

source ~/novarc
export {,TEST_}CIDR_EXT=`openstack subnet show subnet_${OS_USERNAME}-psd-extra -c cidr -f value`
FIP_MAX=$(ipcalc $CIDR_EXT| awk '$1=="HostMax:" {print $2}')
FIP_MIN=$(ipcalc $CIDR_EXT| awk '$1=="HostMin:" {print $2}')
FIP_MIN_ABC=${FIP_MIN%.*}
FIP_MIN_D=${FIP_MIN##*.}
FIP_MIN=${FIP_MIN_ABC}.$(($FIP_MIN_D + 64))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This turns out to be gateway_ip + 64 since it's always .1 by default, and as long as this is a /25 or larger it's fine, smaller and it will be greater than the max. It's only until they get the gate fixed anyways...


CIDR_OAM=`openstack subnet show subnet_${OS_USERNAME}-psd -c cidr -f value`
OAM_MAX=$(ipcalc $CIDR_OAM| awk '$1=="HostMax:" {print $2}')
OAM_MIN=$(ipcalc $CIDR_OAM| awk '$1=="HostMin:" {print $2}')
OAM_MIN_ABC=${OAM_MIN%.*}
OAM_MAX_D=${OAM_MAX##*.}
# Picking last two addresses and hoping they dont get used by Neutron.
export OS_VIP00=${OAM_MIN_ABC}.$(($OAM_MAX_D - 1))
export OS_VIP01=${OAM_MIN_ABC}.$(($OAM_MAX_D - 2))

# More information on config https://github.com/openstack-charmers/zaza/blob/master/doc/source/runningcharmtests.rst
export {,TEST_}NET_ID=$(openstack network show net_${OS_USERNAME}-psd-extra -f value -c id)
export {,TEST_}FIP_RANGE=$FIP_MIN:$FIP_MAX
export {,TEST_}GATEWAY=$(openstack subnet show subnet_${OS_USERNAME}-psd-extra -c gateway_ip -f value)
export {,TEST_}NAME_SERVER=91.189.91.131
export {,TEST_}CIDR_PRIV=192.168.21.0/24
#export SWIFT_IP=10.140.56.22
export TEST_MODEL_SETTINGS="image-stream=released;default-series=jammy;test-mode=true;transmit-vendor-metrics=false"
# We need to set TEST_JUJU3 as well as the constraints file
# Ref: https://github.com/openstack-charmers/zaza/blob/e96ab098f00951079fccb34bc38d4ae6ebb38606/setup.py#L47
export TEST_JUJU3=1

# NOTE: this should not be necessary for > juju 2.x but since we still have a need for it we add it in
export TEST_ZAZA_BUG_LP1987332=1

# Some charms point to an upstream constraints file that installs python-libjuju 2.x so we need to do this to ensure we get 3.x
export TEST_CONSTRAINTS_FILE=https://raw.githubusercontent.com/openstack-charmers/zaza/master/constraints-juju34.txt

# 2. Build
if ! $SKIP_BUILD; then
sudo snap refresh charmcraft --channel $(grep charmcraft_channel osci.yaml| sed -r 's/.+:\s+(\S+)/\1/')

# ensure lxc initialised
lxd init --auto || true

tox -re build
fi

# 3. Run functional tests.

# If a func test pr is provided switch to that pr.
if [[ -n $FUNC_TEST_PR ]]; then
(
[[ -d src ]] && cd src
# We use the zosci-config tools to do this.
[[ -d ~/zosci-config ]] || ( cd; git clone https://github.com/openstack-charmers/zosci-config; )
(cd ~/zosci-config; git checkout master; git pull;)
MSG=$(echo "Func-Test-Pr: https://github.com/openstack-charmers/zaza-openstack-tests/pull/$FUNC_TEST_PR"| base64)
~/zosci-config/roles/handle-func-test-pr/files/process_func_test_pr.py -f ./test-requirements.txt "$MSG"
)
fi

if [[ -n $FUNC_TEST_TARGET ]]; then
func_targets=( $FUNC_TEST_TARGET )
else
func_targets=( $(python3 $(realpath $(dirname $0))/identify_charm_func_tests.py) )
fi

if $MODIFY_BUNDLE_CONSTRAINTS; then
(
[[ -d src ]] && cd src
sed -i -r '/\s+nova-compute:$/{n;s/mem=[0-9]+M/root-disk=80G mem=8G/}' tests/bundles/*.yaml
)
fi

for target in ${func_targets[@]}; do
[[ -d src ]] && pushd src || true
tox -re func-target -- $target

read -p "Destroy model and run next test? [ENTER]"
# cleanup before next run
model=`juju list-models| egrep -o "^zaza-\S+"|tr -d '*'`
juju destroy-model --no-prompt $model --force --no-wait --destroy-storage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail if you have multiple matching models. Ideally it would also print the name of all the models it will destroy before it does, in case you had created another model with a name starting with zaza.

You can also just tell zaza to destroy the model itself automatically by passing an argument, perhaps we should use that by default and then have an option to switch to manual cleanup behaviour for trying to debug the tests?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you happen to know what the argument is?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can fix this as a future patch

done

20 changes: 20 additions & 0 deletions openstack/tools/identify_charm_func_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Get names of test targets that OSCI would run for the given charm. Should be
# run from within the charm root.
#
# Outputs space seperated list of target names.
#
import os
import yaml

CLASSIC_TESTS_YAML = 'tests/tests.yaml'
REACTIVE_TESTS_YAML = os.path.join('src', CLASSIC_TESTS_YAML)

if os.path.exists(REACTIVE_TESTS_YAML):
bundles = yaml.safe_load(open(REACTIVE_TESTS_YAML))
else:
bundles = yaml.safe_load(open(CLASSIC_TESTS_YAML))

targets = set(bundles['smoke_bundles'] + bundles['gate_bundles'] +
bundles['dev_bundles'])

print(' '.join(sorted(targets)))
Loading