d7f96f329d33f30b35175c1b0e06b9e5c65c9b30
[integration.git] / test / onaptests_bench / src / onaptests_bench / launcher.py
1 #!/usr/bin/env python3
2
3 # ============LICENSE_START=======================================================
4 #  Copyright (C) 2022 Orange, Ltd.
5 # ================================================================================
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 #      http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18 # SPDX-License-Identifier: Apache-2.0
19 # ============LICENSE_END=========================================================
20 #
21 # Launch basic_* tests in parallel and report results
22 # the possible basic tests are:
23 # - basic_onboarding
24 # - basic_vm
25 # - basic_network
26 # - basic_cnf
27 # - ...
28
29 # Dependencies:
30 #     See requirements.txt
31 #     The dashboard is based on bulma framework
32 #
33 # Environment:
34 #
35 # Example usage:
36 #       python launcher.py
37 #               -t <test>
38 #               -s <nb simultaneous occurences>
39 #               -d <duration>
40 #               -r <reporting path>
41 #
42 # the summary html page will be generated where the script is launched
43 """
44 Check ONAP certificates
45 """
46 import argparse
47 import logging
48 import os
49 import sys
50 import random
51 import string
52 import time
53 import docker  # pylint: disable=import-error
54
55 import onaptests_bench.reporting as Reporting
56
57 HOMEPATH = os.environ.get("HOME", "/home/ubuntu")
58
59 sys.path.append(f"{HOMEPATH}/onaptests_bench/src/onaptests_bench")
60
61 # Logger
62 LOG_LEVEL = 'INFO'
63 logging.basicConfig()
64 LOGGER = logging.getLogger("onaptests_bench")
65 LOGGER.setLevel(LOG_LEVEL)
66 TEST_LIST = ['basic_onboard', 'basic_vm', 'basic_vm_macro',
67              'basic_network', 'basic_cnf']
68 DEFAULT_TEST = TEST_LIST[0]
69 DEFAULT_SIMU_TESTS = 5
70 DEFAULT_TEST_DURATION = 180 # duration in minutes
71 RESULT_PATH = "/tmp"
72 ONAPTEST_BENCH_WAIT_TIMER = 40
73 ONAPTESTS_PATH = "/usr/lib/python3.8/site-packages/onaptests"
74 ONAPTESTS_SETTINGS = f"{ONAPTESTS_PATH}/configuration/settings.py"
75 ONAPTESTS_SERVICE_DIR = f"{ONAPTESTS_PATH}/templates/vnf-services"
76
77 CLUSTER_IP = "127.0.0.1"
78
79 # Get arguments
80 PARSER = argparse.ArgumentParser()
81 PARSER.add_argument(
82     '-t',
83     '--test',
84     choices=TEST_LIST,
85     help=('Select your test (basic_onboard, basic_vm, basic_network, basic_cnf).' +
86           'If not set, basic_onboarding is considered'),
87     default=DEFAULT_TEST)
88 PARSER.add_argument(
89     '-s',
90     '--simu',
91     type=int,
92     help='Number of simultaneous tests',
93     default=DEFAULT_SIMU_TESTS)
94 PARSER.add_argument(
95     '-d',
96     '--duration',
97     type=int,
98     help='Test duration (in minutes)',
99     default=DEFAULT_TEST_DURATION)
100 PARSER.add_argument(
101     '-r',
102     '--reporting',
103     help='Result directory',
104     default=RESULT_PATH)
105 PARSER.add_argument(
106     '-i',
107     '--ip',
108     help='Cluster IP',
109     default=CLUSTER_IP)
110
111 ARGS = PARSER.parse_args()
112
113 def prepare_test_config():
114     """Check the test execution.
115        We supposed that basic_vm tests are already available in /tmp/xtesting
116        If not the tests cannot be executed."""
117     LOGGER.info("Prepare the test, verify that the test can be run")
118
119 def get_container_name():
120     """Set Container name."""
121     result_str = ''.join(random.choice(string.ascii_letters) for i in range(8))
122     container_name = ARGS.test + "_" + result_str
123     return container_name
124
125 def clean_test_device(docker_client, test):
126     """Clean test resources."""
127     container_list = docker_client.containers.list(
128         all=True,
129         filters={'label':'test='+test})
130     LOGGER.info("Containers cleanup before: %s containers", len(container_list))
131
132     for container in container_list:
133         container.stop()
134         container.remove()
135
136 def retrieve_onap_ip():
137     """Retrieve ONAP IP from /etc/hosts"""
138     filepath = '/etc/hosts'
139     with open(filepath) as fp_config:
140         line = fp_config.readline()
141         while line:
142             line = fp_config.readline()
143             if "so.api.simpledemo.onap.org" in line:
144                 onap_ip = line.split()[0]
145                 return onap_ip
146     return None
147
148 def execute_test(serie_number, test_number,
149                  docker_client):
150     """Execute one test."""
151     LOGGER.info("Execute test n° %s", test_number + 1)
152
153     volume_reporting = (ARGS.reporting + '/serie' + str(serie_number) +
154                         '/test' + str(test_number + 1))
155     if ARGS.ip == CLUSTER_IP:
156         onap_ip = retrieve_onap_ip()
157     else:
158         onap_ip = ARGS.ip
159
160     this_container = docker_client.containers.run(
161         "nexus3.onap.org:10003/onap/xtesting-smoke-usecases-pythonsdk:master",
162         command="run_tests -t " + ARGS.test,
163         name=get_container_name(),
164         labels={"test":ARGS.test},
165         stdout=True,
166         stderr=True,
167         stream=False,
168         detach=True,
169         extra_hosts={'portal.api.simpledemo.onap.org':onap_ip,
170                      'vid.api.simpledemo.onap.org':onap_ip,
171                      'sdc.api.fe.simpledemo.onap.org':onap_ip,
172                      'sdc.api.be.simpledemo.onap.org':onap_ip,
173                      'aai.api.sparky.simpledemo.onap.org':onap_ip,
174                      'so.api.simpledemo.onap.org':onap_ip,
175                      'sdnc.api.simpledemo.onap.org':onap_ip,
176                      'sdc.workflow.plugin.simpledemo.onap.org':onap_ip,
177                      'sdc.dcae.plugin.simpledemo.onap.org':onap_ip,
178                      'msb.api.simpledemo.onap.org':onap_ip},
179         volumes={'/tmp/xtesting/smoke-usecases/' + ARGS.test + '/env':{'bind': '/var/lib/xtesting/conf/env_file', 'mode': 'rw'},  # pylint: disable=line-too-long
180                  f'{HOMEPATH}/.config/openstack/clouds.yaml':{'bind': '/root/.config/openstack/clouds.yaml', 'mode': 'rw'},  # pylint: disable=line-too-long
181                  volume_reporting:{'bind':'/var/lib/xtesting/results', 'mode': 'rw'},
182                  f'{HOMEPATH}/.kube/config':{'bind':'/root/.kube/config', 'mode': 'rw'},
183                  os.path.dirname(os.path.abspath(__file__)) + '/artifacts/settings.py':{'bind': ONAPTESTS_SETTINGS, 'mode': 'rw'},  # pylint: disable=line-too-long
184                  f'/tmp/xtesting/smoke-usecases/{ARGS.test}/{ARGS.test}-service.yaml': {'bind': f'{ONAPTESTS_SERVICE_DIR}/{ARGS.test}-service.yaml', 'mode': 'rw'}})  # pylint: disable=line-too-long
185
186     return this_container
187
188 def launch_test_serie(serie_number,
189                       docker_client, serie_containers):
190     """Launch a serie of n tests."""
191     for test_number in range(ARGS.simu):
192         container = execute_test(serie_number, test_number,
193                                  docker_client)
194         serie_containers.append(container)
195     return serie_containers
196
197 def get_terminated_serie_status(running_containers):
198     """Check if the dockers in the list are terminated and get exit codes"""
199     LOGGER.info("check terminated dockers")
200     exit_codes = []
201     exit_codes.clear()
202
203     for container in running_containers:
204         try:
205             # wait for the container to finish within a certain time
206             result = container.wait(timeout=60*ONAPTEST_BENCH_WAIT_TIMER)
207             exit_code = result["StatusCode"]
208         except Exception as timeout:  # pylint: disable=broad-except
209             #if the container didn't finish in the allocated time
210             # raise timeout exception and sto the container
211             LOGGER.error(timeout)
212             LOGGER.error("docker not terminating in allocated time")
213             container.stop()
214             exit_code = -1
215         LOGGER.info("exit code : %s", str(exit_code))
216         exit_codes.append(exit_code)
217     return exit_codes
218
219 def generate_report():
220     """Build reporting."""
221     LOGGER.info("Generate the report")
222     test = Reporting.OnaptestBenchReporting(
223         nb_simultaneous_tests=ARGS.simu,
224         duration=ARGS.duration,
225         res_dir_path=ARGS.reporting,
226         reporting_dir=ARGS.reporting)
227     test.generate_reporting()
228
229 def main():
230     """Entry point"""
231     # ***************************************************************************
232     # ***************************************************************************
233     # start of the test
234     # ***************************************************************************
235     # ***************************************************************************
236     test_client = docker.from_env()
237     serie_containers = []
238     exit_codes = []
239
240     prepare_test_config()
241
242     t_end = time.time() + 60 * float(ARGS.duration)
243
244     # clean previous container no longer used to avoid saturation
245
246
247     LOGGER.info("****************************")
248     LOGGER.info("Launch the tests")
249     LOGGER.info("Testcase: %s", ARGS.test)
250     LOGGER.info("Number of simultaneous tests : %s", ARGS.simu)
251     LOGGER.info("Test duration : %s m", ARGS.duration)
252     LOGGER.info("Reporting path : %s", ARGS.reporting)
253     LOGGER.info("****************************")
254
255     try:
256         # keep on launching series until we reached the duration expected by the tester
257         serie_number = 1
258         while time.time() < t_end:
259             clean_test_device(test_client, ARGS.test)
260             LOGGER.info("Serie : %s", str(serie_number))
261             serie_containers.clear()
262             # launch the serie
263             serie_containers = launch_test_serie(
264                 serie_number,
265                 test_client,
266                 serie_containers)
267             LOGGER.info("Containers of serie %s created", str(serie_number))
268             exit_codes = get_terminated_serie_status(serie_containers)
269             LOGGER.info("Serie terminated")
270             LOGGER.debug(exit_codes)
271             remaining_time = int(t_end - time.time())
272             if remaining_time > 0:
273                 LOGGER.info("%s s remaining, restart a serie...", remaining_time)
274             serie_number += 1
275
276     except Exception as error:  # pylint: disable=broad-except
277         LOGGER.error(error)
278         LOGGER.error(">>>> Onaptests_bench FAIL")
279         LOGGER.error("do you have the correct env file?")
280         LOGGER.error("do you have the correctcluster IP?")
281         sys.exit(1)
282
283     else:
284         LOGGER.info(">>>> Onaptests_bench successfully executed")
285
286     finally:
287         generate_report()