From dc594c07ab8084fcc4f2c7d051efaef70ccc3d15 Mon Sep 17 00:00:00 2001 From: Raymond Wong Date: Thu, 13 Mar 2014 16:25:50 -0700 Subject: [PATCH] Use values from DB instead of config file for tempest config. Update tempest_tester.py to use the data in the cloud db. Values in config file can still be used to futher customize the tempest config. Unnecessary values are removed from conf.json.sample. The remaining values will be removed once the execute_test.py can discover them. Change-Id: I5a3257a0b99985fccbc0f26d04f0060986ec6cc3 --- config.json.sample | 19 +---- refstack/refstack_config.py | 14 ++-- refstack/tools/tempest_tester.py | 115 +++++++++++++++++++++++++------ 3 files changed, 106 insertions(+), 42 deletions(-) diff --git a/config.json.sample b/config.json.sample index 950ef5a4..a8a373cb 100644 --- a/config.json.sample +++ b/config.json.sample @@ -1,7 +1,7 @@ { - "app_address": "x.x.x.x:8000", + "app_address": "0.0.0.0:8000", - "test_mode": "DOCKER", + "test_mode": "docker", "tempest_url": "https://github.com/openstack/tempest/archive/stable/havana.zip", @@ -10,14 +10,9 @@ { "identity": { - "uri": "http://x.x.x.x:5000/v2.0/", - "uri_v3": "http://x.x.x.x:5000/v3/", "region": "RegionOne", - "username": "demo", "tenant_name": "demo", - "alt_username": "alt_demo", "alt_tenant_name": "alt_demo", - "admin_username": "admin", "admin_tenant_name": "admin" }, "compute": @@ -25,15 +20,7 @@ "image_ref": "a8d70acb-f1c4-4171-b0ce-d73e5de21a9d", "image_ref_alt": "6182b1da-e64d-4440-b0ef-c0afa4d77abb", "flavor_ref": "1", - "flavor_ref_alt": "1", - "image_ssh_user": "root", - "image_ssh_password": "password", - "image_alt_ssh_user": "root", - "image_alt_ssh_password": "password" - }, - "cli": - { - "enable": "False" + "flavor_ref_alt": "1" } }, diff --git a/refstack/refstack_config.py b/refstack/refstack_config.py index a99d7679..b67d0074 100644 --- a/refstack/refstack_config.py +++ b/refstack/refstack_config.py @@ -43,20 +43,24 @@ class RefStackConfig(object): def get_app_address(self): '''Return address of the Web App server.''' - return self.refstack_config["app_address"] + return self.get_data_for_key("app_address") def get_tempest_url(self): '''Return the URL for tempest test code download.''' - return self.refstack_config["tempest_url"] + return self.get_data_for_key("tempest_url") def get_tempest_config(self): '''Return customized tempest config parameters.''' - return self.refstack_config["tempest_config"] + return self.get_data_for_key("tempest_config") def get_tempest_testcases(self): '''Return a JSON of tempest testcase.''' - return self.refstack_config["tempest_testcases"] + return self.get_data_for_key("tempest_testcases") def get_test_mode(self): '''Return the tempest test mode.''' - return self.refstack_config["test_mode"] + return self.get_data_for_key("test_mode") + + def get_data_for_key(self, key): + '''Return the value for the key specified.''' + return self.refstack_config.get(key, None) diff --git a/refstack/tools/tempest_tester.py b/refstack/tools/tempest_tester.py index f22beff2..9ea50dee 100755 --- a/refstack/tools/tempest_tester.py +++ b/refstack/tools/tempest_tester.py @@ -17,11 +17,31 @@ from docker_buildfile import DockerBuildFile import json import os +from refstack.extensions import db +from refstack.models import Cloud +from refstack.models import Test from refstack.refstack_config import RefStackConfig -import time configData = RefStackConfig() +# Common tempest conf values to be used for all tests +# - Image user and password can be set to any value for testing purpose +# - We do not test OpenStack CLI +# Vendors running their own Refstack can override these using config file. +common_tempest_conf = { + "compute": + { + "image_ssh_user": "root", + "image_ssh_password": "password", + "image_alt_ssh_user": "root", + "image_alt_ssh_password": "password" + }, + "cli": + { + "enabled": "False" + } +} + class TempestTester(object): '''Utility class to handle tempest test.''' @@ -31,34 +51,72 @@ class TempestTester(object): cloudObj = None def __init__(self, test_id=None): - '''Init method loads specified id.''' + '''Init method loads specified id. - ''' If test_id exists, this is an existing test. Else this is a new - test. Test_id wll be created later in an other module. + If test_id exists, this is an existing test. + Otherwise, this is a new test, and test_id will be created later. ''' if test_id: self.test_id = test_id - ''' TODO: Retrieve testObj and cloudObj ''' + self.testObj = Test.query.filter_by(id=test_id).first() + if self.testObj is not None: + self.cloudObj = Cloud.query.filter_by( + id=self.testObj.cloud_id).first() def generate_miniconf(self): '''Return a JSON object representing the mini tempest conf.''' - ''' TODO: Construct the JSON from cloud db obj ''' - ''' ForNow: Return the JSON in vendor config ''' - conf = configData.get_tempest_config() + # Get custom tempest config from config file + custom_tempest_conf = configData.get_tempest_config() - return json.dumps(conf) + # Construct cloud specific tempest config from db + if self.cloudObj: + cloud_tempest_conf = { + "identity": + { + "uri": self.cloudObj.endpoint, + "uri_v3": self.cloudObj.endpoint_v3, + "username": self.cloudObj.test_user, + "alt_username": self.cloudObj.test_user, + "admin_username": self.cloudObj.admin_user + } + } + else: + cloud_tempest_conf = dict() + + # Merge all the config data together + # - Start with common config + # - Insert/Overwrite with values from custom config + # - Insert/Overwrite with values from cloud DB + tempest_conf = common_tempest_conf + self._merge_config(tempest_conf, custom_tempest_conf) + self._merge_config(tempest_conf, cloud_tempest_conf) + + return json.dumps(tempest_conf) + + def _merge_config(self, dic1, dic2): + '''Insert data from dictionary dic2 into dictionary dic1. + + dic1 and dic2 are in the format of section, key, value. + ''' + if not all([dic1, dic2]): + return + + for section, data in dic2.items(): + if section in dic1: + dic1[section].update(data) + else: + dic1.update({section: data}) def generate_testcases(self): '''Return a JSON array of the tempest testcases to be executed.''' - ''' TODO: Depends on DefCore's decision, either do the full test or - allow users to specify what to test - ''' - ''' ForNow: Return the JSON in vendor config ''' - conf = configData.get_tempest_testcases() + # Set to full tempest test unless it is specified in the config file + testcases = configData.get_tempest_testcases() + if not testcases: + testcases = {"testcases": ["tempest"]} - return json.dumps(conf) + return json.dumps(testcases) def process_resultfile(self, filename): '''Process the tempest result file.''' @@ -72,13 +130,22 @@ class TempestTester(object): def test_cloud(self, cloud_id, extraConfJSON=None): '''Create and execute a new test with the provided extraConfJSON.''' - ''' TODO: Retrieve the cloud obj from DB ''' + # Retrieve the cloud obj from DB + self.cloudObj = Cloud.query.filter_by(id=cloud_id).first() - ''' TODO: Create new test obj in DB and get the real unique test_id''' - ''' ForNow: use timestamp as the test_id ''' - self.test_id = time.strftime("%m%d%H%M") + if not self.cloudObj: + return - ''' invoke execute_test ''' + # Create new test object in DB and get the real unique test_id + self.testObj = Test() + self.testObj.cloud_id = self.cloudObj.id + self.testObj.cloud = self.cloudObj + db.session.add(self.testObj) + db.session.commit() + + self.test_id = self.testObj.id + + # Invoke execute_test self.execute_test(extraConfJSON) def execute_test(self, extraConfJSON=None): @@ -90,8 +157,14 @@ class TempestTester(object): ''' TODO: Initial test status in DB ''' + if configData.get_test_mode(): + test_mode = configData.get_test_mode().upper() + else: + # Default to use docker if not specified in the config file + test_mode = 'DOCKER' + try: - options[configData.get_test_mode()](extraConfJSON) + options[test_mode](extraConfJSON) except KeyError: print 'Error: Invalid test mode in config file'