blob: c400556444f329907b869b8a1bd01bc4b9d0f925 [file] [log] [blame]
# Copyright 2018 Mirantis, Inc.
#
# 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 json
import os
import time
from devops.helpers import helpers
from tcp_tests import logger
from tcp_tests import settings
LOG = logger.logger
TEMPEST_CFG_DIR = '/tmp/test'
CONFIG = {
'classes': ['service.runtest.tempest',
'service.runtest.tempest.services.manila.glance'],
'parameters': {
'_param': {
'runtest_tempest_cfg_dir': TEMPEST_CFG_DIR,
'runtest_tempest_cfg_name': 'tempest.conf',
'runtest_tempest_public_net': 'net04_ext',
'tempest_test_target': 'gtw01*'
},
'neutron': {
'client': {
'enabled': True
}
},
'runtest': {
'enabled': True,
'keystonerc_node': 'ctl01*',
'tempest': {
'enabled': True,
'cfg_dir': '${_param:runtest_tempest_cfg_dir}',
'cfg_name': '${_param:runtest_tempest_cfg_name}',
'DEFAULT': {
'log_file': 'tempest.log'
},
'compute': {
'build_timeout': 600,
'max_microversion': 2.53,
'min_compute_nodes': 2,
'min_microversion': 2.1,
'volume_device_name': 'vdc'
},
'convert_to_uuid': {
'network': {
'public_network_id':
'${_param:runtest_tempest_public_net}'
}
},
'dns_feature_enabled': {
'api_admin': False,
'api_v1': False,
'api_v2': True,
'api_v2_quotas': True,
'api_v2_root_recordsets': True,
'bug_1573141_fixed': True
},
'heat_plugin': {
'floating_network_name':
'${_param:runtest_tempest_public_net}'
},
'network': {
'floating_network_name':
'${_param:runtest_tempest_public_net}'
},
'share': {
'capability_snapshot_support': True,
'run_driver_assisted_migration_tests': False,
'run_manage_unmanage_snapshot_tests': False,
'run_manage_unmanage_tests': False,
'run_migration_with_preserve_snapshots_tests': False,
'run_quota_tests': True,
'run_replication_tests': False,
'run_snapshot_tests': True,
}}}}}
class RuntestManager(object):
"""Helper manager for execution tempest via runtest-formula"""
image_name = settings.TEMPEST_IMAGE
image_version = settings.TEMPEST_IMAGE_VERSION
container_name = 'run-tempest-ci'
master_host = "cfg01"
master_tgt = "{}*".format(master_host)
class_name = "runtest"
run_cmd = '/bin/bash -c "run-tempest"'
def __init__(self, underlay, salt_api, cluster_name,
domain_name, tempest_threads,
tempest_pattern=settings.TEMPEST_PATTERN,
run_cmd=None, target='gtw01'):
self.underlay = underlay
self.__salt_api = salt_api
self.target = target
self.cluster_name = cluster_name
self.domain_name = domain_name
self.tempest_threads = tempest_threads
self.tempest_pattern = tempest_pattern
self.run_cmd = run_cmd or self.run_cmd
@property
def salt_api(self):
return self.__salt_api
def install_python_lib(self):
return self.salt_api.local(
"{}*".format(self.target),
'pip.install', 'docker'), None
def run_salt_minion_state(self):
return self.salt_api.local('cfg01*', 'state.sls', 'salt.minion')
def create_networks(self):
return self.salt_api.local('cfg01*', 'state.sls', 'neutron.client')
def create_flavors(self):
return self.salt_api.local('cfg01*', 'state.sls', 'nova.client')
def set_property(self):
return self.salt_api.local(
tgt='ctl01*',
fun='cmd.run',
args='. /root/keystonercv3; openstack '
'flavor set m1.tiny_test '
'--property hw:mem_page_size=small')
def create_cirros(self):
return self.salt_api.local('cfg01*', 'state.sls', 'glance.client')
def generate_config(self):
return self.salt_api.local('cfg01*', 'state.sls', 'runtest')
def fetch_arficats(self, username=None, file_format='xml'):
target_name = next(node_name for node_name
in self.underlay.node_names() if
self.target in node_name)
with self.underlay.remote(node_name=target_name, username=None) as tgt:
result = tgt.execute('find {} -name "report_*.{}"'.format(
TEMPEST_CFG_DIR, file_format))
LOG.debug("Find result {0}".format(result))
assert len(result['stdout']) > 0, ('No report found, please check'
' if test run was successful.')
report = result['stdout'][0].rstrip()
LOG.debug("Found files {0}".format(report))
tgt.download(
destination=report, # noqa
target=os.getcwd())
def store_runtest_model(self, config=CONFIG):
master_name = next(node_name for node_name
in self.underlay.node_names() if
self.master_host in node_name)
with self.underlay.yaml_editor(
file_path="/srv/salt/reclass/classes/cluster/"
"{cluster_name}/infra/"
"{class_name}.yml".format(
cluster_name=self.cluster_name,
class_name=self.class_name),
node_name=master_name) as editor:
editor.content = config
with self.underlay.yaml_editor(
file_path="/srv/salt/reclass/nodes/_generated/"
"cfg01.{domain_name}.yml".format(
domain_name=self.domain_name),
node_name=master_name) as editor:
editor.content['classes'].append(
'cluster.{cluster_name}.infra.{class_name}'.format(
cluster_name=self.cluster_name,
class_name=self.class_name))
self.salt_api.local('*', 'saltutil.refresh_pillar')
self.salt_api.local('*', 'saltutil.sync_all')
def save_runtime_logs(self, logs=None, inspect=None):
if logs:
with open("{path}/{target}_tempest_run.log".format(
path=settings.LOGS_DIR, target=self.target), 'w') as f:
LOG.info("Save tempest console log")
container_log = logs
f.write(container_log.encode('ascii', 'ignore'))
if inspect:
with open("{path}/{target}_tempest_container_info.json.log".format(
path=settings.LOGS_DIR, target=self.target), 'w') as f:
LOG.info("Save tempest container inspect data")
container_inspect = json.dumps(inspect,
indent=4, sort_keys=True)
f.write(container_inspect)
def prepare(self, dpdk=None):
self.store_runtest_model()
res = self.install_python_lib()
LOG.info(json.dumps(res, indent=4))
res = self.run_salt_minion_state()
LOG.info(json.dumps(res, indent=4))
time.sleep(20)
res = self.create_networks()
LOG.info(json.dumps(res, indent=4))
time.sleep(20)
res = self.create_flavors()
LOG.info(json.dumps(res, indent=4))
time.sleep(20)
if dpdk:
res = self.set_property()
LOG.info('Update flavor property')
LOG.info(json.dumps(res, indent=4))
time.sleep(20)
res = self.create_cirros()
LOG.info(json.dumps(res, indent=4))
time.sleep(20)
res = self.generate_config()
LOG.info(json.dumps(res, indent=4))
time.sleep(20)
def run_tempest(self, timeout=600):
tgt = "{}*".format(self.target)
params = {
"name": self.container_name,
"image": "{}:{}".format(self.image_name, self.image_version),
"environment": {
"ARGS": "-r {tempest_pattern} -w "
"{tempest_threads} ".format(
tempest_pattern=self.tempest_pattern,
tempest_threads=self.tempest_threads) # noqa
},
"binds": [
"{cfg_dir}/tempest.conf:/etc/tempest/tempest.conf".format(cfg_dir=TEMPEST_CFG_DIR), # noqa
"/tmp/:/tmp/",
"{cfg_dir}:/root/tempest".format(cfg_dir=TEMPEST_CFG_DIR),
"/etc/ssl/certs/:/etc/ssl/certs/"
],
"auto_remove": False,
"cmd": self.run_cmd
}
res = self.salt_api.local(tgt, 'dockerng.pull', "{}:{}".format(
self.image_name, self.image_version))
LOG.info("Tempest image has beed pulled- \n{}".format(
json.dumps(res, indent=4)))
res = self.salt_api.local(tgt, 'dockerng.create', kwargs=params)
LOG.info("Tempest container has been created - \n{}".format(
json.dumps(res, indent=4)))
res = self.salt_api.local(tgt, 'dockerng.start', self.container_name)
LOG.info("Tempest container has been started - \n{}".format(
json.dumps(res, indent=4)))
def wait_status(s):
inspect_res = self.salt_api.local(tgt,
'dockerng.inspect',
self.container_name)
if 'return' in inspect_res:
inspect = inspect_res['return']
inspect = inspect[0]
inspect = next(inspect.iteritems())[1]
status = inspect['State']['Status']
return status.lower() == s.lower()
return False
helpers.wait(lambda: wait_status('exited'),
timeout=timeout,
timeout_msg=('Tempest run didnt finished '
'in {}'.format(timeout)))
inspect_res = self.salt_api.local(tgt,
'dockerng.inspect',
self.container_name)
inspect = inspect_res['return'][0]
inspect = next(inspect.iteritems())[1]
if inspect['State']['ExitCode'] != 0:
LOG.error("Tempest running failed")
LOG.info("Tempest tests have been finished - \n{}".format(
json.dumps(res, indent=4)))
logs_res = self.salt_api.local(tgt,
'dockerng.logs',
self.container_name)
logs = logs_res['return'][0]
logs = next(logs.iteritems())[1]
LOG.info("Tempest result - \n{}".format(
logs.encode('ascii', 'ignore')))
res = self.salt_api.local(tgt, 'dockerng.rm', self.container_name)
LOG.info("Tempest container was removed".format(
json.dumps(res, indent=4)))
return {'inspect': inspect,
'logs': logs}
def prepare_and_run_tempest(self, username='root', dpdk=None):
"""
Run tempest tests
"""
tempest_timeout = settings.TEMPEST_TIMEOUT
self.prepare(dpdk=dpdk)
test_res = self.run_tempest(tempest_timeout)
self.fetch_arficats(username=username)
self.save_runtime_logs(**test_res)