blob: 036f4154f293cb066d39848c63cc17fd994962f9 [file] [log] [blame]
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +03001# Copyright 2018 Mirantis, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030015import json
Oleksii Butenko71d76f32018-06-05 17:46:34 +030016import os
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030017
18from tcp_tests import logger
19from tcp_tests import settings
20
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030021LOG = logger.logger
22
23TEMPEST_CFG_DIR = '/tmp/test'
24
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030025
26class RuntestManager(object):
27 """Helper manager for execution tempest via runtest-formula"""
28
29 image_name = settings.TEMPEST_IMAGE
30 image_version = settings.TEMPEST_IMAGE_VERSION
31 container_name = 'run-tempest-ci'
32 master_host = "cfg01"
Dennis Dmitriev70cefed2018-09-17 15:41:35 +030033 control_host = "ctl01"
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030034 class_name = "runtest"
35 run_cmd = '/bin/bash -c "run-tempest"'
36
Dennis Dmitriev70cefed2018-09-17 15:41:35 +030037 def __init__(self, config, underlay, salt_api, cluster_name,
Oleksii Butenko74566102018-09-11 11:55:13 +030038 domain_name, tempest_threads,
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030039 tempest_pattern=settings.TEMPEST_PATTERN,
40 run_cmd=None, target='gtw01'):
Dennis Dmitriev70cefed2018-09-17 15:41:35 +030041 self.__config = config
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030042 self.underlay = underlay
43 self.__salt_api = salt_api
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030044 self.cluster_name = cluster_name
45 self.domain_name = domain_name
46 self.tempest_threads = tempest_threads
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030047 self.tempest_pattern = tempest_pattern
48 self.run_cmd = run_cmd or self.run_cmd
Dennis Dmitriev70cefed2018-09-17 15:41:35 +030049 self.target_name = self.underlay.get_target_node_names(target)[0]
50 self.master_name = self.underlay.get_target_node_names(
51 self.master_host)[0]
52 self.control_name = self.underlay.get_target_node_names(
53 self.control_host)[0]
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030054
55 @property
56 def salt_api(self):
57 return self.__salt_api
58
Dennis Dmitriev70cefed2018-09-17 15:41:35 +030059 @property
60 def runtest_pillar(self):
61 public_net = self.__config.underlay.dhcp_ranges[
62 settings.EXTERNAL_ADDRESS_POOL_NAME]
63 public_gateway = public_net["gateway"].encode("ascii")
64 public_cidr = public_net["cidr"].encode("ascii")
65 public_allocation_start = public_net["start"].encode("ascii")
66 public_allocation_end = public_net["end"].encode("ascii")
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +030067
Dennis Dmitriev70cefed2018-09-17 15:41:35 +030068 return {
69 'classes': ['service.runtest.tempest',
70 'service.runtest.tempest.public_net',
71 'service.runtest.tempest.services.manila.glance'],
72 'parameters': {
73 '_param': {
74 'runtest_tempest_cfg_dir': TEMPEST_CFG_DIR,
75 'runtest_tempest_cfg_name': 'tempest.conf',
76 'runtest_tempest_public_net': 'public',
77 'openstack_public_neutron_subnet_gateway': public_gateway,
78 'openstack_public_neutron_subnet_cidr': public_cidr,
79 'openstack_public_neutron_subnet_allocation_start':
80 public_allocation_start,
81 'openstack_public_neutron_subnet_allocation_end':
82 public_allocation_end,
83 'tempest_test_target': self.target_name.encode("ascii"),
84 },
85 'neutron': {
86 'client': {
87 'enabled': True
88 }
89 },
90 'runtest': {
91 'enabled': True,
92 'keystonerc_node': 'ctl01*',
93 'tempest': {
94 'enabled': True,
95 'cfg_dir': '${_param:runtest_tempest_cfg_dir}',
96 'cfg_name': '${_param:runtest_tempest_cfg_name}',
97 'DEFAULT': {
98 'log_file': 'tempest.log'
99 },
100 'compute': {
101 'build_timeout': 600,
102 'max_microversion': 2.53,
103 'min_compute_nodes': 2,
104 'min_microversion': 2.1,
105 'volume_device_name': 'vdc'
106 },
107 'convert_to_uuid': {
108 'network': {
109 'public_network_id':
110 '${_param:runtest_tempest_public_net}'
111 }
112 },
113 'dns_feature_enabled': {
114 'api_admin': False,
115 'api_v1': False,
116 'api_v2': True,
117 'api_v2_quotas': True,
118 'api_v2_root_recordsets': True,
119 'bug_1573141_fixed': True
120 },
121 'heat_plugin': {
122 'floating_network_name':
123 '${_param:runtest_tempest_public_net}'
124 },
125 'network': {
126 'floating_network_name':
127 '${_param:runtest_tempest_public_net}'
128 },
129 'share': {
130 'capability_snapshot_support': True,
131 'run_driver_assisted_migration_tests': False,
132 'run_manage_unmanage_snapshot_tests': False,
133 'run_manage_unmanage_tests': False,
134 'run_migration_with_preserve_snapshots_tests':
135 False,
136 'run_quota_tests': True,
137 'run_replication_tests': False,
138 'run_snapshot_tests': True,
139 }}}}}
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300140
Oleksii Butenko71d76f32018-06-05 17:46:34 +0300141 def fetch_arficats(self, username=None, file_format='xml'):
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300142 with self.underlay.remote(node_name=self.target_name,
143 username=None) as tgt:
Oleksii Butenko71d76f32018-06-05 17:46:34 +0300144 result = tgt.execute('find {} -name "report_*.{}"'.format(
145 TEMPEST_CFG_DIR, file_format))
146 LOG.debug("Find result {0}".format(result))
147 assert len(result['stdout']) > 0, ('No report found, please check'
148 ' if test run was successful.')
149 report = result['stdout'][0].rstrip()
150 LOG.debug("Found files {0}".format(report))
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300151 tgt.download(
Oleksii Butenko71d76f32018-06-05 17:46:34 +0300152 destination=report, # noqa
153 target=os.getcwd())
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300154
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300155 def store_runtest_model(self, runtest_pillar=None):
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300156 with self.underlay.yaml_editor(
157 file_path="/srv/salt/reclass/classes/cluster/"
158 "{cluster_name}/infra/"
159 "{class_name}.yml".format(
160 cluster_name=self.cluster_name,
161 class_name=self.class_name),
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300162 node_name=self.master_name) as editor:
163 editor.content = runtest_pillar or self.runtest_pillar
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300164 with self.underlay.yaml_editor(
165 file_path="/srv/salt/reclass/nodes/_generated/"
166 "cfg01.{domain_name}.yml".format(
167 domain_name=self.domain_name),
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300168 node_name=self.master_name) as editor:
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300169 editor.content['classes'].append(
170 'cluster.{cluster_name}.infra.{class_name}'.format(
171 cluster_name=self.cluster_name,
172 class_name=self.class_name))
173
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300174 def save_runtime_logs(self, logs=None, inspect=None):
175 if logs:
176 with open("{path}/{target}_tempest_run.log".format(
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300177 path=settings.LOGS_DIR,
178 target=self.target_name), 'w') as f:
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300179 LOG.info("Save tempest console log")
180 container_log = logs
Oleksii Butenko71d76f32018-06-05 17:46:34 +0300181 f.write(container_log.encode('ascii', 'ignore'))
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300182
183 if inspect:
Oleksii Butenko71d76f32018-06-05 17:46:34 +0300184 with open("{path}/{target}_tempest_container_info.json.log".format(
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300185 path=settings.LOGS_DIR,
186 target=self.target_name), 'w') as f:
Oleksii Butenko71d76f32018-06-05 17:46:34 +0300187 LOG.info("Save tempest container inspect data")
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300188
189 container_inspect = json.dumps(inspect,
190 indent=4, sort_keys=True)
191 f.write(container_inspect)
192
Tatyana Leontovich61a821d2018-08-21 12:30:51 +0300193 def prepare(self, dpdk=None):
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300194 self.store_runtest_model()
Oleksii Butenko5cd0a162018-06-14 18:18:10 +0300195
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300196 salt_cmd = "salt -l info --hard-crash --state-output=mixed "
197 salt_call_cmd = "salt-call -l info --hard-crash --state-output=mixed "
198 commands = [
199 {
200 'description': "Sync salt objects for runtest model",
201 'node_name': self.master_name,
202 'cmd': ("set -ex;" +
203 salt_cmd + "'*' saltutil.refresh_pillar && " +
204 salt_cmd + "'*' saltutil.sync_all")},
205 {
206 'description': ("Install docker.io package and "
207 "enable packets forwarding"),
208 'node_name': self.target_name,
209 'cmd': ("set -ex;" +
210 salt_call_cmd + " pkg.install docker.io && " +
211 " iptables --policy FORWARD ACCEPT")},
212 {
213 'description': "Install PyPI docker package",
214 'node_name': self.target_name,
215 'cmd': ("set -ex;" +
216 salt_call_cmd + " pip.install setuptools && " +
217 salt_call_cmd + " pip.install docker")},
218 {
219 'description': "Run salt.minion state for runtest formula",
220 'node_name': self.master_name,
221 'cmd': ("set -ex;" +
222 salt_call_cmd + " state.sls salt.minion && "
223 " sleep 20")},
224 {
225 'description': "Enforce keystone state for neutronv2",
226 'node_name': self.master_name,
227 'cmd': ("set -ex;" +
228 salt_call_cmd + " state.sls keystone.client")},
229 {
230 'description': "Create networks for Tempest tests",
231 'node_name': self.master_name,
232 'cmd': ("set -ex;" +
233 salt_call_cmd + " state.sls neutron.client")},
234 {
235 'description': "Create flavors for Tempest tests",
236 'node_name': self.master_name,
237 'cmd': ("set -ex;" +
238 salt_call_cmd + " state.sls nova.client")},
239 {
240 'description': "Create cirros image for Tempest",
241 'node_name': self.master_name,
242 'cmd': ("set -ex;" +
243 salt_call_cmd + " state.sls glance.client")},
244 {
245 'description': "Generate config for Tempest",
246 'node_name': self.master_name,
247 'cmd': ("set -ex;" +
248 salt_call_cmd + " state.sls runtest")},
249 ]
Oleksii Butenko5cd0a162018-06-14 18:18:10 +0300250
Tatyana Leontovich61a821d2018-08-21 12:30:51 +0300251 if dpdk:
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300252 commands.append({
253 'description': "Configure flavor for DPDK",
254 'node_name': self.control_name,
255 'cmd': ("set -ex;" +
256 salt_call_cmd + " cmd.run "
257 " '. /root/keystonercv3;"
258 " openstack flavor set m1.tiny_test"
259 " --property hw:mem_page_size=small'")},
260 )
Oleksii Butenko5cd0a162018-06-14 18:18:10 +0300261
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300262 self.__salt_api.execute_commands(commands=commands,
263 label="Prepare for Tempest")
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300264
265 def run_tempest(self, timeout=600):
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300266 tgt = self.target_name
267 image_nameversion = "{}:{}".format(self.image_name, self.image_version)
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300268
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300269 docker_args = (
270 " --name {container_name} "
271 " -e ARGS=\"-r {tempest_pattern} -w {tempest_threads}\""
272 " -v {cfg_dir}/tempest.conf:/etc/tempest/tempest.conf"
273 " -v /tmp/:/tmp/"
274 " -v {cfg_dir}:/root/tempest"
275 " -v /etc/ssl/certs/:/etc/ssl/certs/"
276 " --rm"
277 " {image_nameversion} {run_cmd}"
278 .format(
279 container_name=self.container_name,
280 image_nameversion=image_nameversion,
281 tempest_pattern=self.tempest_pattern,
282 tempest_threads=self.tempest_threads,
283 cfg_dir=TEMPEST_CFG_DIR,
284 run_cmd=self.run_cmd,
285 ))
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300286
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300287 commands = [
288 {
289 'description': "Run Tempest tests {0}".format(
290 image_nameversion),
291 'node_name': self.target_name,
292 'cmd': ("set -ex;" +
293 " docker rm --force {container_name} || true;"
294 " docker run {docker_args}"
295 .format(container_name=self.container_name,
296 docker_args=docker_args)),
297 'timeout': timeout},
298 ]
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300299
Dennis Dmitriev70cefed2018-09-17 15:41:35 +0300300 self.__salt_api.execute_commands(commands=commands,
301 label="Run Tempest tests")
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300302
303 inspect_res = self.salt_api.local(tgt,
304 'dockerng.inspect',
305 self.container_name)
306 inspect = inspect_res['return'][0]
307 inspect = next(inspect.iteritems())[1]
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300308 logs_res = self.salt_api.local(tgt,
309 'dockerng.logs',
310 self.container_name)
311 logs = logs_res['return'][0]
312 logs = next(logs.iteritems())[1]
Dmitry Tyzhnenkoc56b77e2018-05-21 11:01:43 +0300313
314 res = self.salt_api.local(tgt, 'dockerng.rm', self.container_name)
315 LOG.info("Tempest container was removed".format(
316 json.dumps(res, indent=4)))
317
318 return {'inspect': inspect,
319 'logs': logs}
Oleksii Butenkoe82441d2018-06-12 16:01:33 +0300320
Tatyana Leontovich61a821d2018-08-21 12:30:51 +0300321 def prepare_and_run_tempest(self, username='root', dpdk=None):
Oleksii Butenkoe82441d2018-06-12 16:01:33 +0300322 """
323 Run tempest tests
324 """
325 tempest_timeout = settings.TEMPEST_TIMEOUT
Tatyana Leontovich61a821d2018-08-21 12:30:51 +0300326 self.prepare(dpdk=dpdk)
Oleksii Butenkoe82441d2018-06-12 16:01:33 +0300327 test_res = self.run_tempest(tempest_timeout)
328 self.fetch_arficats(username=username)
329 self.save_runtime_logs(**test_res)