Merge "conversion of execute_test.py into cli"
This commit is contained in:
commit
5d4ba1797c
@ -63,4 +63,4 @@ RUN /usr/local/bin/pip install -r /tempest/test-requirements.txt
|
|||||||
# CONF_JSON - JSON string that contains portion of the Tempest
|
# CONF_JSON - JSON string that contains portion of the Tempest
|
||||||
# config. For example, the passwords of the users.
|
# config. For example, the passwords of the users.
|
||||||
|
|
||||||
CMD wget http://${APP_SERVER_ADDRESS}/get-script -O execute_test.py && python execute_test.py --callback ${APP_SERVER_ADDRESS} --test-id ${TEST_ID} --conf-json ${CONF_JSON} --tempest-home /tempest -v
|
CMD wget http://${APP_SERVER_ADDRESS}/get-script -O execute_test.py && python execute_test.py --url ${APP_SERVER_ADDRESS} --test-id ${TEST_ID} --conf-json ${CONF_JSON} --tempest-dir /tempest -v
|
||||||
|
45
refstack/tools/execute_test/README.rst
Executable file
45
refstack/tools/execute_test/README.rst
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
Execute Test
|
||||||
|
============
|
||||||
|
|
||||||
|
Execute test is a command line utility that allows you to execute tempest runs with generated configs. When finished running tempest it sends the raw subunit data back to an api.
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
|
||||||
|
First make sure you have some stuff installed
|
||||||
|
|
||||||
|
`apt-get update`
|
||||||
|
|
||||||
|
|
||||||
|
`apt-get install -y git python-pip`
|
||||||
|
|
||||||
|
`apt-get install -y libxml2-dev libxslt-dev lib32z1-dev python2.7-dev libssl-dev libxml2-python`
|
||||||
|
|
||||||
|
`apt-get install -y python-dev libxslt1-dev libsasl2-dev libsqlite3-dev libldap2-dev libffi-dev`
|
||||||
|
|
||||||
|
`pip install --upgrade pip>=1.4`
|
||||||
|
`pip install virtualenv`
|
||||||
|
|
||||||
|
Then you'll need to setup the tempest env.. from the refstack dir.
|
||||||
|
|
||||||
|
`cd refstack/tools/execute_test/`
|
||||||
|
|
||||||
|
the following command installs stable havana tempest in a virtual env named 'test_runner'. putting tempest in `./test_runner/src/tempest`
|
||||||
|
|
||||||
|
`./setup_env`
|
||||||
|
|
||||||
|
From here you have two options..
|
||||||
|
|
||||||
|
a. if you are triggering this test from the web gui you can use the `/get-miniconf` method ..
|
||||||
|
|
||||||
|
i.e. `./execute_test --url refstack.org --test-id 235 --tempest-dir ./test_runner/src/tempest --conf-json {section:{option:value}}`
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
b. my recomendation which is to source an openstack rc file you download from the cloud you want to test.
|
||||||
|
|
||||||
|
i.e.
|
||||||
|
|
||||||
|
`source openstackrc.sh`
|
||||||
|
|
||||||
|
`./execute_test --env --url refstack.org --test-id 235 --tempest-dir ./test_runner/src/tempest`
|
||||||
|
|
@ -14,7 +14,6 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
import fnmatch
|
import fnmatch
|
||||||
@ -23,7 +22,6 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import urllib2
|
import urllib2
|
||||||
|
|
||||||
@ -51,47 +49,73 @@ class Test:
|
|||||||
else:
|
else:
|
||||||
self.logger.setLevel(logging.CRITICAL)
|
self.logger.setLevel(logging.CRITICAL)
|
||||||
|
|
||||||
if args.callback:
|
# assign local vars to match args
|
||||||
self.app_server_address = args.callback
|
# things not passed in right will be set as None
|
||||||
|
self.app_server_address = args.app_server_address
|
||||||
|
self.test_id = args.test_id
|
||||||
|
self.tempest_dir = args.tempest_dir
|
||||||
|
self.extra_conf_dict = args.extra_conf_dict
|
||||||
|
|
||||||
if args.test_id:
|
# if --env is used then import from env vars and don't call home
|
||||||
self.test_id = args.test_id
|
if args.env:
|
||||||
|
self.mini_conf_dict = self.import_config_from_env()
|
||||||
self.mini_conf_dict = json.loads(self.get_mini_config())
|
else:
|
||||||
|
self.mini_conf_dict = self.get_mini_config()
|
||||||
if args.conf_json:
|
|
||||||
self.extra_conf_dict = args.conf_json
|
|
||||||
|
|
||||||
if args.testcases:
|
if args.testcases:
|
||||||
self.testcases = {"testcases": args.testcases}
|
self.testcases = {"testcases": args.testcases}
|
||||||
|
|
||||||
self.tempest_home =\
|
self.sample_conf_file = os.path.join(self.tempest_dir, 'etc',
|
||||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tempest')
|
|
||||||
|
|
||||||
if args.tempest_home:
|
|
||||||
self.tempest_home = args.tempest_home
|
|
||||||
|
|
||||||
self.sample_conf_file = os.path.join(self.tempest_home, 'etc',
|
|
||||||
'tempest.conf.sample')
|
'tempest.conf.sample')
|
||||||
self.tempest_conf_file = os.path.join(self.tempest_home,
|
self.tempest_conf_file = os.path.join(self.tempest_dir,
|
||||||
'tempest.config')
|
'tempest.config')
|
||||||
self.result_dir = os.path.join(self.tempest_home, '.testrepository')
|
self.result_dir = os.path.join(self.tempest_dir, '.testrepository')
|
||||||
self.result = os.path.join(self.result_dir, 'result')
|
self.result = os.path.join(self.result_dir, 'result')
|
||||||
self.tempest_script = os.path.join(self.tempest_home, 'run_tests.sh')
|
self.tempest_script = os.path.join(self.tempest_dir, 'run_tests.sh')
|
||||||
self.sample_conf_parser = ConfigParser.SafeConfigParser()
|
self.sample_conf_parser = ConfigParser.SafeConfigParser()
|
||||||
self.sample_conf_parser.read(self.sample_conf_file)
|
self.sample_conf_parser.read(self.sample_conf_file)
|
||||||
|
|
||||||
def gen_config(self):
|
def import_config_from_env(self):
|
||||||
'''Merge mini config, extra config, tempest.conf.sample
|
"""create config from environment variables if set"""
|
||||||
and write to tempest.config.
|
if not os.environ.get("OS_AUTH_URL"):
|
||||||
'''
|
# TODO: add better argument parsing for this input..
|
||||||
|
# failure needs to give a more detailed response.
|
||||||
|
print """Missing env variables did you source your localrc?"""
|
||||||
|
else:
|
||||||
|
self.logger.info('Using Config ENV variables for %s@%s'
|
||||||
|
% (os.environ.get("OS_USERNAME"),
|
||||||
|
os.environ.get("OS_AUTH_URL")))
|
||||||
|
|
||||||
|
env_config = {"identity":
|
||||||
|
{"uri": os.environ.get("OS_AUTH_URL"),
|
||||||
|
"username": os.environ.get("OS_USERNAME"),
|
||||||
|
"password": os.environ.get("OS_PASSWORD"),
|
||||||
|
"tenant_name": os.environ.get("OS_TENANT_NAME")},
|
||||||
|
"compute": {"image_ref":
|
||||||
|
os.environ.get("TEMPEST_IMAGE_REF",
|
||||||
|
"cirros")}}
|
||||||
|
|
||||||
|
self.logger.debug("ENV config: %s" % (env_config))
|
||||||
|
|
||||||
|
return env_config
|
||||||
|
|
||||||
|
def generate_config(self):
|
||||||
|
'''Merge passed in config with tempest.conf.sample
|
||||||
|
and write to $tempest/tempest.config'''
|
||||||
self.logger.info('Generating tempest.config')
|
self.logger.info('Generating tempest.config')
|
||||||
|
|
||||||
|
# merge in config from env or api
|
||||||
self.merge_to_sample_conf(self.mini_conf_dict)
|
self.merge_to_sample_conf(self.mini_conf_dict)
|
||||||
|
|
||||||
|
# merge in extra config
|
||||||
self.merge_to_sample_conf(self.extra_conf_dict)
|
self.merge_to_sample_conf(self.extra_conf_dict)
|
||||||
|
|
||||||
# discovered config will not overwrite the value in the
|
# discovered config will not overwrite the value in the
|
||||||
# mini_conf_dict and extra_conf_dict
|
# mini_conf_dict and extra_conf_dict
|
||||||
discovered_conf_dict = self._build_discovered_dict_conf()
|
discovered_conf_dict = self._build_discovered_dict_conf()
|
||||||
self.merge_to_sample_conf(discovered_conf_dict)
|
self.merge_to_sample_conf(discovered_conf_dict)
|
||||||
|
|
||||||
|
# write the config file
|
||||||
self.sample_conf_parser.write(open(self.tempest_conf_file, 'w'))
|
self.sample_conf_parser.write(open(self.tempest_conf_file, 'w'))
|
||||||
|
|
||||||
def merge_to_sample_conf(self, dic):
|
def merge_to_sample_conf(self, dic):
|
||||||
@ -102,41 +126,20 @@ class Test:
|
|||||||
self.sample_conf_parser.set(section, key, value)
|
self.sample_conf_parser.set(section, key, value)
|
||||||
|
|
||||||
def get_mini_config(self):
|
def get_mini_config(self):
|
||||||
'''Return a mini config in JSON string.'''
|
'''Return a mini config in from the remote server.'''
|
||||||
# create config from environment variables if set
|
if self.app_server_address and self.test_id:
|
||||||
url = os.environ.get("OS_AUTH_URL")
|
url = "http://%s/get-miniconf?test_id=%s" % \
|
||||||
if url:
|
(self.app_server_address, self.test_id)
|
||||||
user = os.environ.get("OS_USERNAME")
|
try:
|
||||||
self.logger.info('Using Config ENV variables for %s@%s'
|
req = urllib2.urlopen(url=url, timeout=10)
|
||||||
% (url, user))
|
self.logger.info('Using App Server Config from %s' % (url))
|
||||||
# for now, very limited configuration. refactor as we add vars
|
return json.loads(req.readlines()[0])
|
||||||
env_config = {"identity":
|
except:
|
||||||
{"uri": url,
|
self.logger.critical('Failed to get mini config from %s'
|
||||||
"username": user,
|
% url)
|
||||||
"password": os.environ.get("OS_PASSWORD"),
|
raise
|
||||||
"tenant_name": os.environ.get("OS_TENANT_NAME"),
|
|
||||||
"region": os.environ.get("OS_REGION_NAME")},
|
|
||||||
"compute":
|
|
||||||
{"image_ref": os.environ.get("TEMPEST_IMAGE_REF",
|
|
||||||
"cirros")}}
|
|
||||||
json_config = json.dumps(env_config, separators=(',', ':'))
|
|
||||||
self.logger.debug("ENV config: %s" % (json_config))
|
|
||||||
return json_config
|
|
||||||
# otherwise get them from the app server
|
|
||||||
else:
|
else:
|
||||||
if self.app_server_address and self.test_id:
|
return dict()
|
||||||
url = "http://%s/get-miniconf?test_id=%s" % \
|
|
||||||
(self.app_server_address, self.test_id)
|
|
||||||
try:
|
|
||||||
req = urllib2.urlopen(url=url, timeout=10)
|
|
||||||
self.logger.info('Using App Server Config from %s' % (url))
|
|
||||||
return req.readlines()[0]
|
|
||||||
except:
|
|
||||||
self.logger.critical('Failed to get mini config from %s'
|
|
||||||
% url)
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
return json.dumps(dict())
|
|
||||||
|
|
||||||
def get_test_cases(self):
|
def get_test_cases(self):
|
||||||
'''Return list of tempest testcases in JSON string.
|
'''Return list of tempest testcases in JSON string.
|
||||||
@ -216,7 +219,7 @@ class Test:
|
|||||||
def run(self):
|
def run(self):
|
||||||
'''Execute tempest test against the cloud.'''
|
'''Execute tempest test against the cloud.'''
|
||||||
|
|
||||||
self.gen_config()
|
self.generate_config()
|
||||||
|
|
||||||
self.run_test_cases()
|
self.run_test_cases()
|
||||||
|
|
||||||
@ -414,45 +417,60 @@ if __name__ == '__main__':
|
|||||||
parser = argparse.ArgumentParser(description='Starts a tempest test',
|
parser = argparse.ArgumentParser(description='Starts a tempest test',
|
||||||
formatter_class=argparse.
|
formatter_class=argparse.
|
||||||
ArgumentDefaultsHelpFormatter)
|
ArgumentDefaultsHelpFormatter)
|
||||||
conflict_group = parser.add_mutually_exclusive_group()
|
|
||||||
|
|
||||||
conflict_group.add_argument("--callback",
|
parser.add_argument('-s', '--silent',
|
||||||
type=str,
|
action='store_true',
|
||||||
action='store',
|
help='rigged for silent running')
|
||||||
help="refstack API IP address \
|
|
||||||
retrieve configurations. i.e.:\
|
|
||||||
--callback 127.0.0.1:8000")
|
|
||||||
|
|
||||||
conflict_group.add_argument("--test-id",
|
|
||||||
action='store',
|
|
||||||
dest='test_id',
|
|
||||||
type=str,
|
|
||||||
help="refstack test ID i.e.:\
|
|
||||||
--test-id 1234 ")
|
|
||||||
|
|
||||||
parser.add_argument("--tempest-home",
|
|
||||||
help="tempest directory path")
|
|
||||||
|
|
||||||
# with nargs, arguments are returned as a list
|
|
||||||
conflict_group.add_argument("--testcases",
|
|
||||||
nargs='+',
|
|
||||||
help="tempest test cases. Use space to\
|
|
||||||
separate each testcase")
|
|
||||||
'''
|
|
||||||
TODO: May need to decrypt/encrypt password in args.JSON_CONF
|
|
||||||
'''
|
|
||||||
parser.add_argument("--conf-json",
|
|
||||||
type=json.loads,
|
|
||||||
help="tempest configurations in JSON string")
|
|
||||||
|
|
||||||
parser.add_argument("-v", "--verbose",
|
parser.add_argument("-v", "--verbose",
|
||||||
action="store_true",
|
action="count",
|
||||||
help="show verbose output")
|
help="show verbose output")
|
||||||
|
|
||||||
|
parser.add_argument('-e', '--env',
|
||||||
|
action='store_true',
|
||||||
|
required=False,
|
||||||
|
dest='env',
|
||||||
|
help='uses env variables.. and does not\
|
||||||
|
pull mini config from server')
|
||||||
|
|
||||||
|
parser.add_argument("--url",
|
||||||
|
action='store',
|
||||||
|
required=True,
|
||||||
|
type=str,
|
||||||
|
dest='app_server_address',
|
||||||
|
help="refstack API url \
|
||||||
|
retrieve configurations. i.e.:\
|
||||||
|
--url 127.0.0.1:8000")
|
||||||
|
|
||||||
|
parser.add_argument("--test-id",
|
||||||
|
action='store',
|
||||||
|
required=False,
|
||||||
|
dest='test_id',
|
||||||
|
type=int,
|
||||||
|
help="refstack test ID i.e.:\
|
||||||
|
--test-id 1234 ")
|
||||||
|
|
||||||
|
parser.add_argument("--tempest-dir",
|
||||||
|
action='store',
|
||||||
|
required=True,
|
||||||
|
dest='tempest_dir',
|
||||||
|
help="tempest directory path")
|
||||||
|
|
||||||
|
parser.add_argument("--testcases",
|
||||||
|
action='store',
|
||||||
|
required=False,
|
||||||
|
nargs='+',
|
||||||
|
help="tempest test cases. Use space to\
|
||||||
|
separate each testcase")
|
||||||
|
|
||||||
|
parser.add_argument("--conf-json",
|
||||||
|
action='store',
|
||||||
|
required=False,
|
||||||
|
type=json.loads,
|
||||||
|
dest='extra_conf_dict',
|
||||||
|
help="tempest configurations in JSON string")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
test = Test(args)
|
||||||
parser.print_help()
|
test.run()
|
||||||
else:
|
|
||||||
test = Test(args)
|
|
||||||
test.run()
|
|
1
refstack/tools/execute_test/havana_requirements.txt
Executable file
1
refstack/tools/execute_test/havana_requirements.txt
Executable file
@ -0,0 +1 @@
|
|||||||
|
-e git+https://github.com/openstack/tempest.git@stable/havana#egg=tempest
|
28
refstack/tools/execute_test/setup.cfg
Executable file
28
refstack/tools/execute_test/setup.cfg
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
[metadata]
|
||||||
|
name = execute_test
|
||||||
|
version = 0.1
|
||||||
|
summary = Tempest test wrapper for refstack
|
||||||
|
description-file =
|
||||||
|
README.rst
|
||||||
|
author = OpenStack
|
||||||
|
author-email = fits@lists.openstack.org
|
||||||
|
home-page = http://www.openstack.org/
|
||||||
|
classifier =
|
||||||
|
Environment :: OpenStack
|
||||||
|
Intended Audience :: Developers
|
||||||
|
Intended Audience :: Information Technology
|
||||||
|
License :: OSI Approved :: Apache Software License
|
||||||
|
Operating System :: POSIX :: Linux
|
||||||
|
Programming Language :: Python
|
||||||
|
Programming Language :: Python :: 2
|
||||||
|
Programming Language :: Python :: 2.7
|
||||||
|
Programming Language :: Python :: 3.3
|
||||||
|
|
||||||
|
[files]
|
||||||
|
packages =
|
||||||
|
refstack
|
||||||
|
|
||||||
|
[global]
|
||||||
|
setup-hooks =
|
||||||
|
pbr.hooks.setup_hook
|
||||||
|
|
21
refstack/tools/execute_test/setup.py
Normal file
21
refstack/tools/execute_test/setup.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) 2014 Piston Cloud Computing, inc. all rights reserved
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
setuptools.setup(
|
||||||
|
setup_requires=['pbr'],
|
||||||
|
pbr=True)
|
12
refstack/tools/execute_test/setup_env
Executable file
12
refstack/tools/execute_test/setup_env
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
# !/bin/bash
|
||||||
|
|
||||||
|
virtualenv test_runner
|
||||||
|
|
||||||
|
source test_runner/bin/activate
|
||||||
|
|
||||||
|
pip install -r havana_requirements.txt
|
||||||
|
|
||||||
|
#cd /test_runner/src/tempest
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user