Fix clearwater test results parsing
[functest.git] / functest / opnfv_tests / vnf / ims / heat_ims.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2018 Kontron, Orange and others.
4 #
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9
10 """HeatIms testcase implementation."""
11
12 from __future__ import division
13
14 import logging
15 import os
16 import re
17 import time
18 import yaml
19
20 import pkg_resources
21 from xtesting.core import testcase
22
23 from functest.core import singlevm
24 from functest.opnfv_tests.vnf.ims import clearwater
25 from functest.utils import config
26 from functest.utils import env
27
28 __author__ = "Valentin Boucher <valentin.boucher@kontron.com>"
29
30
31 class HeatIms(singlevm.VmReady2):
32     # pylint: disable=too-many-instance-attributes
33     """Clearwater vIMS deployed with Heat Orchestrator Case."""
34
35     __logger = logging.getLogger(__name__)
36
37     filename_alt = ('/home/opnfv/functest/images/'
38                     'ubuntu-14.04-server-cloudimg-amd64-disk1.img')
39
40     flavor_alt_ram = 2048
41     flavor_alt_vcpus = 2
42     flavor_alt_disk = 25
43
44     quota_security_group = 20
45     quota_security_group_rule = 100
46     quota_port = 50
47
48     def __init__(self, **kwargs):
49         """Initialize HeatIms testcase object."""
50         if "case_name" not in kwargs:
51             kwargs["case_name"] = "heat_ims"
52         super(HeatIms, self).__init__(**kwargs)
53
54         # Retrieve the configuration
55         try:
56             self.config = getattr(
57                 config.CONF, 'vnf_{}_config'.format(self.case_name))
58         except Exception:
59             raise Exception("VNF config file not found")
60
61         self.case_dir = pkg_resources.resource_filename(
62             'functest', 'opnfv_tests/vnf/ims')
63         config_file = os.path.join(self.case_dir, self.config)
64
65         self.vnf = dict(
66             descriptor=get_config("vnf.descriptor", config_file),
67             parameters=get_config("vnf.inputs", config_file)
68         )
69         self.details['vnf'] = dict(
70             descriptor_version=self.vnf['descriptor']['version'],
71             name=get_config("vnf.name", config_file),
72             version=get_config("vnf.version", config_file),
73         )
74         self.__logger.debug("VNF configuration: %s", self.vnf)
75
76         self.image_alt = None
77         self.flavor_alt = None
78         self.keypair = None
79         self.stack = None
80         self.clearwater = None
81         self.role = None
82
83     def execute(self):
84         # pylint: disable=too-many-locals,too-many-statements
85         """
86         Prepare Tenant/User
87
88         network, security group, fip, VM creation
89         """
90         self.orig_cloud.set_network_quotas(
91             self.project.project.name,
92             security_group=self.quota_security_group,
93             security_group_rule=self.quota_security_group_rule,
94             port=self.quota_port)
95         if not self.orig_cloud.get_role("heat_stack_owner"):
96             self.role = self.orig_cloud.create_role("heat_stack_owner")
97         self.orig_cloud.grant_role(
98             "heat_stack_owner", user=self.project.user.id,
99             project=self.project.project.id,
100             domain=self.project.domain.id)
101         self.keypair = self.cloud.create_keypair(
102             '{}-kp_{}'.format(self.case_name, self.guid))
103         self.__logger.debug("keypair: %s", self.keypair)
104
105         if (self.deploy_vnf() and self.test_vnf()):
106             self.result = 100
107             return 0
108         self.result = 1/3 * 100
109         return 1
110
111     def run(self, **kwargs):
112         """Deploy and test clearwater
113
114         Here are the main actions:
115         - deploy clearwater stack via heat
116         - test the vnf instance
117
118         Returns:
119         - TestCase.EX_OK
120         - TestCase.EX_RUN_ERROR on error
121         """
122         status = testcase.TestCase.EX_RUN_ERROR
123         try:
124             assert self.cloud
125             self.start_time = time.time()
126             self.result = 0
127             if not self.execute():
128                 self.result = 100
129                 status = testcase.TestCase.EX_OK
130         except Exception:  # pylint: disable=broad-except
131             self.__logger.exception('Cannot run %s', self.case_name)
132         finally:
133             self.stop_time = time.time()
134         return status
135
136     def deploy_vnf(self):
137         """Deploy Clearwater IMS."""
138         start_time = time.time()
139
140         self.image_alt = self.publish_image_alt()
141         self.flavor_alt = self.create_flavor_alt()
142         # KeyPair + Image + Flavor OK
143
144         descriptor = self.vnf['descriptor']
145         parameters = self.vnf['parameters']
146
147         parameters['public_mgmt_net_id'] = self.ext_net.id
148         parameters['public_sig_net_id'] = self.ext_net.id
149         parameters['flavor'] = self.flavor_alt.name
150         parameters['image'] = self.image_alt.name
151         parameters['key_name'] = self.keypair.name
152         parameters['external_mgmt_dns_ip'] = env.get('NAMESERVER')
153         parameters['external_sig_dns_ip'] = env.get('NAMESERVER')
154
155         self.__logger.info("Create Heat Stack")
156         self.stack = self.cloud.create_stack(
157             name=descriptor.get('name'),
158             template_file=descriptor.get('file_name'),
159             wait=True, **parameters)
160         self.__logger.debug("stack: %s", self.stack)
161
162         servers = self.cloud.list_servers(detailed=True)
163         self.__logger.debug("servers: %s", servers)
164         for server in servers:
165             if not self.check_regex_in_console(
166                     server.name, regex='Cloud-init .* finished at ', loop=60):
167                 return False
168             if 'ellis' in server.name:
169                 self.__logger.debug("server: %s", server)
170                 ellis_ip = server.public_v4
171
172         assert ellis_ip
173         self.clearwater = clearwater.ClearwaterTesting(self.case_name,
174                                                        ellis_ip)
175         # This call can take time and many retry because Heat is
176         # an infrastructure orchestrator so when Heat say "stack created"
177         # it means that all OpenStack ressources are created but not that
178         # Clearwater are up and ready (Cloud-Init script still running)
179         self.clearwater.availability_check_by_creating_numbers()
180
181         duration = time.time() - start_time
182
183         self.details['vnf'].update(status='PASS', duration=duration)
184         self.result += 1/3 * 100
185
186         return True
187
188     def test_vnf(self):
189         """Run test on clearwater ims instance."""
190         start_time = time.time()
191
192         outputs = self.cloud.get_stack(self.stack.id).outputs
193         self.__logger.debug("stack outputs: %s", outputs)
194         dns_ip = re.findall(r'[0-9]+(?:\.[0-9]+){3}', str(outputs))[0]
195
196         if not dns_ip:
197             return False
198
199         short_result = self.clearwater.run_clearwater_live_test(
200             dns_ip=dns_ip,
201             public_domain=self.vnf['parameters']["zone"])
202         duration = time.time() - start_time
203         self.__logger.info(short_result)
204         self.details['test_vnf'] = dict(result=short_result,
205                                         duration=duration)
206         try:
207             vnf_test_rate = short_result['passed'] / (
208                 short_result['total'] - short_result['skipped'])
209             # orchestrator + vnf + test_vnf
210             self.result += vnf_test_rate / 3 * 100
211         except ZeroDivisionError:
212             self.__logger.error("No test has been executed")
213             self.details['test_vnf'].update(status='FAIL')
214             return False
215         except Exception:  # pylint: disable=broad-except
216             self.__logger.exception("Cannot calculate results")
217             self.details['test_vnf'].update(status='FAIL')
218             return False
219         return True if vnf_test_rate > 0 else False
220
221     def clean(self):
222         """Clean created objects/functions."""
223         assert self.cloud
224         try:
225             if self.stack:
226                 self.cloud.delete_stack(self.stack.id, wait=True)
227         except Exception:  # pylint: disable=broad-except
228             self.__logger.exception("Cannot clean stack ressources")
229         super(HeatIms, self).clean()
230         if self.role:
231             self.orig_cloud.delete_role(self.role.id)
232
233
234 # ----------------------------------------------------------
235 #
236 #               YAML UTILS
237 #
238 # -----------------------------------------------------------
239 def get_config(parameter, file_path):
240     """
241     Get config parameter.
242
243     Returns the value of a given parameter in file.yaml
244     parameter must be given in string format with dots
245     Example: general.openstack.image_name
246     """
247     with open(file_path) as config_file:
248         file_yaml = yaml.safe_load(config_file)
249     config_file.close()
250     value = file_yaml
251     for element in parameter.split("."):
252         value = value.get(element)
253         if value is None:
254             raise ValueError("The parameter %s is not defined in"
255                              " reporting.yaml" % parameter)
256     return value