New testcase creation named "cloudify_ims_perf"
[functest.git] / functest / opnfv_tests / vnf / ims / cloudify_ims_perf.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2017 Orange, IXIA 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 """CloudifyImsPerf testcase implementation."""
11
12 import logging
13 import os
14 import time
15
16 import json
17 import yaml
18 import paramiko
19 import dns.resolver
20 from jinja2 import Environment, FileSystemLoader
21
22
23 from functest.energy import energy
24 from functest.opnfv_tests.openstack.snaps import snaps_utils
25 import functest.opnfv_tests.vnf.ims.cloudify_ims as cloudify_ims
26 from functest.utils.constants import CONST
27
28 from snaps.openstack.create_network import (NetworkSettings, SubnetSettings,
29                                             OpenStackNetwork, PortSettings)
30 from snaps.openstack.create_security_group import (SecurityGroupSettings,
31                                                    SecurityGroupRuleSettings,
32                                                    Direction, Protocol,
33                                                    OpenStackSecurityGroup)
34 from snaps.openstack.create_router import RouterSettings, OpenStackRouter
35 from snaps.openstack.create_instance import (VmInstanceSettings,
36                                              FloatingIpSettings,
37                                              OpenStackVmInstance)
38 from snaps.openstack.create_flavor import FlavorSettings, OpenStackFlavor
39 from snaps.openstack.create_image import ImageSettings
40
41 from ixia.utils.IxChassisUtils import ChassisRestAPI
42 import ixia.utils.IxLoadUtils as IxLoadUtils
43 import ixia.utils.IxRestUtils as IxRestUtils
44
45 __author__ = "Valentin Boucher <valentin.boucher@orange.com>"
46
47
48 class CloudifyImsPerf(cloudify_ims.CloudifyIms):
49     """Clearwater vIMS deployed with Cloudify Orchestrator Case."""
50
51     __logger = logging.getLogger(__name__)
52
53     def __init__(self, **kwargs):
54         """Initialize CloudifyIms testcase object."""
55         if "case_name" not in kwargs:
56             kwargs["case_name"] = "cloudify_ims_perf"
57         super(CloudifyImsPerf, self).__init__(**kwargs)
58
59         # Retrieve the configuration
60         try:
61             self.config = CONST.__getattribute__(
62                 'vnf_{}_config'.format(self.case_name))
63         except Exception:
64             raise Exception("VNF config file not found")
65
66         self.snaps_creds = ''
67         self.created_object = []
68
69         config_file = os.path.join(self.case_dir, self.config)
70         self.orchestrator = dict(
71             requirements=get_config("orchestrator.requirements", config_file),
72         )
73         self.details['orchestrator'] = dict(
74             name=get_config("orchestrator.name", config_file),
75             version=get_config("orchestrator.version", config_file),
76             status='ERROR',
77             result=''
78         )
79         self.__logger.debug("Orchestrator configuration %s", self.orchestrator)
80         self.vnf = dict(
81             descriptor=get_config("vnf.descriptor", config_file),
82             inputs=get_config("vnf.inputs", config_file),
83             requirements=get_config("vnf.requirements", config_file)
84         )
85         self.details['vnf'] = dict(
86             descriptor_version=self.vnf['descriptor']['version'],
87             name=get_config("vnf.name", config_file),
88             version=get_config("vnf.version", config_file),
89         )
90         self.__logger.debug("VNF configuration: %s", self.vnf)
91
92         self.test = dict(
93             version=get_config("vnf_test_suite.version", config_file),
94             inputs=get_config("vnf_test_suite.inputs", config_file),
95             requirements=get_config("vnf_test_suite.requirements", config_file)
96         )
97
98         self.details['test_vnf'] = dict(
99             name=get_config("vnf_test_suite.name", config_file),
100             version=get_config("vnf_test_suite.version", config_file),
101             requirements=get_config("vnf_test_suite.requirements", config_file)
102         )
103         self.images = get_config("tenant_images", config_file)
104         self.__logger.info("Images needed for vIMS: %s", self.images)
105
106     def test_vnf(self):
107         """Run IXIA Stress test on clearwater ims instance."""
108         start_time = time.time()
109
110         cfy_client = self.orchestrator['object']
111
112         outputs = cfy_client.deployments.outputs.get(
113             self.vnf['descriptor'].get('name'))['outputs']
114         dns_ip = outputs['dns_ip']
115         ellis_ip = outputs['ellis_ip']
116
117         self.__logger.info("Creating full IXIA network ...")
118         subnet_settings = SubnetSettings(name='ixia_management_subnet',
119                                          cidr='10.10.10.0/24')
120         network_settings = NetworkSettings(name='ixia_management_network',
121                                            subnet_settings=[subnet_settings])
122         network_creator = OpenStackNetwork(self.snaps_creds, network_settings)
123         network_creator.create()
124         self.created_object.append(network_creator)
125         ext_net_name = snaps_utils.get_ext_net_name(self.snaps_creds)
126         router_creator = OpenStackRouter(
127             self.snaps_creds,
128             RouterSettings(
129                 name='ixia_management_router',
130                 external_gateway=ext_net_name,
131                 internal_subnets=[subnet_settings.name]))
132         router_creator.create()
133         self.created_object.append(router_creator)
134
135         # security group creation
136         self.__logger.info("Creating security groups for IXIA VMs")
137         sg_rules = list()
138         sg_rules.append(
139             SecurityGroupRuleSettings(sec_grp_name="ixia_management",
140                                       direction=Direction.ingress,
141                                       protocol=Protocol.tcp, port_range_min=1,
142                                       port_range_max=65535))
143         sg_rules.append(
144             SecurityGroupRuleSettings(sec_grp_name="ixia_management",
145                                       direction=Direction.ingress,
146                                       protocol=Protocol.udp, port_range_min=1,
147                                       port_range_max=65535))
148         sg_rules.append(
149             SecurityGroupRuleSettings(sec_grp_name="ixia_management",
150                                       direction=Direction.ingress,
151                                       protocol=Protocol.icmp))
152
153         ixia_managment_sg_settings = SecurityGroupSettings(
154                                         name="ixia_management",
155                                         rule_settings=sg_rules)
156         securit_group_creator = OpenStackSecurityGroup(
157             self.snaps_creds,
158             ixia_managment_sg_settings)
159
160         securit_group_creator.create()
161         self.created_object.append(securit_group_creator)
162
163         sg_rules = list()
164         sg_rules.append(
165             SecurityGroupRuleSettings(sec_grp_name="ixia_ssh_http",
166                                       direction=Direction.ingress,
167                                       protocol=Protocol.tcp, port_range_min=1,
168                                       port_range_max=65535))
169
170         ixia_ssh_http_sg_settings = SecurityGroupSettings(
171                                         name="ixia_ssh_http",
172                                         rule_settings=sg_rules)
173         securit_group_creator = OpenStackSecurityGroup(
174             self.snaps_creds,
175             ixia_ssh_http_sg_settings)
176
177         securit_group_creator.create()
178         self.created_object.append(securit_group_creator)
179
180         chassis_flavor_settings = FlavorSettings(
181             name="ixia_vChassis",
182             ram=4096,
183             disk=40,
184             vcpus=2)
185         flavor_creator = OpenStackFlavor(self.snaps_creds,
186                                          chassis_flavor_settings)
187         flavor_creator.create()
188         self.created_object.append(flavor_creator)
189
190         card_flavor_settings = FlavorSettings(
191             name="ixia_vCard",
192             ram=4096,
193             disk=4,
194             vcpus=2)
195         flavor_creator = OpenStackFlavor(self.snaps_creds,
196                                          card_flavor_settings)
197         flavor_creator.create()
198         self.created_object.append(flavor_creator)
199
200         load_flavor_settings = FlavorSettings(
201             name="ixia_vLoad",
202             ram=8192,
203             disk=100,
204             vcpus=4)
205         flavor_creator = OpenStackFlavor(self.snaps_creds,
206                                          load_flavor_settings)
207         flavor_creator.create()
208         self.created_object.append(flavor_creator)
209
210         chassis_image_settings = ImageSettings(
211             name=self.test['requirements']['chassis']['image'],
212             image_user='admin',
213             exists=True)
214
215         card_image_settings = ImageSettings(
216             name=self.test['requirements']['card']['image'],
217             image_user='admin',
218             exists=True)
219
220         load_image_settings = ImageSettings(
221             name=self.test['requirements']['load']['image'],
222             image_user='admin',
223             exists=True)
224
225         chassis_port_settings = PortSettings(
226                                      name='ixia_chassis_port',
227                                      network_name=network_settings.name)
228
229         card1_port1_settings = PortSettings(
230                                      name='ixia_card1_port1',
231                                      network_name=network_settings.name)
232
233         card2_port1_settings = PortSettings(
234                                      name='ixia_card2_port1',
235                                      network_name=network_settings.name)
236
237         card1_port2_settings = PortSettings(
238                                      name='ixia_card1_port2',
239                                      network_name="cloudify_ims_network")
240
241         card2_port2_settings = PortSettings(
242                                      name='ixia_card2_port2',
243                                      network_name="cloudify_ims_network")
244
245         load_port_settings = PortSettings(
246                                      name='ixia_load_port',
247                                      network_name=network_settings.name)
248
249         chassis_settings = VmInstanceSettings(
250             name='ixia_vChassis',
251             flavor=chassis_flavor_settings.name,
252             port_settings=[chassis_port_settings],
253             security_group_names=[ixia_ssh_http_sg_settings.name,
254                                   ixia_managment_sg_settings.name],
255             floating_ip_settings=[FloatingIpSettings(
256                 name='ixia_vChassis_fip',
257                 port_name=chassis_port_settings.name,
258                 router_name=router_creator.router_settings.name)])
259
260         vm_creator = OpenStackVmInstance(self.snaps_creds,
261                                          chassis_settings,
262                                          chassis_image_settings)
263
264         self.__logger.info("Creating Ixia vChassis VM")
265         vm_creator.create()
266         fip_chassis = vm_creator.get_floating_ip().ip
267         self.created_object.append(vm_creator)
268
269         card1_settings = VmInstanceSettings(
270             name='ixia_vCard1',
271             flavor=card_flavor_settings.name,
272             port_settings=[card1_port1_settings, card1_port2_settings],
273             security_group_names=[ixia_managment_sg_settings.name])
274
275         vm_creator = OpenStackVmInstance(self.snaps_creds,
276                                          card1_settings,
277                                          card_image_settings)
278
279         self.__logger.info("Creating Ixia vCard1 VM")
280         vm_creator.create()
281         vcard_ips = list()
282         vcard_ips_p2 = list()
283         vcard_ips.append(vm_creator.get_port_ip('ixia_card1_port1'))
284         vcard_ips_p2.append(vm_creator.get_port_ip('ixia_card1_port2'))
285         self.created_object.append(vm_creator)
286
287         card2_settings = VmInstanceSettings(
288             name='ixia_vCard2',
289             flavor=card_flavor_settings.name,
290             port_settings=[card2_port1_settings, card2_port2_settings],
291             security_group_names=[ixia_managment_sg_settings.name])
292
293         vm_creator = OpenStackVmInstance(self.snaps_creds,
294                                          card2_settings,
295                                          card_image_settings)
296
297         self.__logger.info("Creating Ixia vCard2 VM")
298         vm_creator.create()
299         vcard_ips.append(vm_creator.get_port_ip('ixia_card2_port1'))
300         vcard_ips_p2.append(vm_creator.get_port_ip('ixia_card2_port2'))
301         self.created_object.append(vm_creator)
302
303         load_settings = VmInstanceSettings(
304             name='ixia_vLoad',
305             flavor=load_flavor_settings.name,
306             port_settings=[load_port_settings],
307             security_group_names=[ixia_ssh_http_sg_settings.name,
308                                   ixia_managment_sg_settings.name],
309             floating_ip_settings=[FloatingIpSettings(
310                 name='ixia_vLoad_fip',
311                 port_name=load_port_settings.name,
312                 router_name=router_creator.router_settings.name)])
313
314         vm_creator = OpenStackVmInstance(self.snaps_creds,
315                                          load_settings,
316                                          load_image_settings)
317
318         self.__logger.info("Creating Ixia vLoad VM")
319         vm_creator.create()
320         fip_load = vm_creator.get_floating_ip().ip
321         self.created_object.append(vm_creator)
322
323         self.__logger.info("Chassis IP is: %s", fip_chassis)
324         login_url = "https://" + str(fip_chassis) + "/api/v1/auth/session"
325         cards_url = "https://" + str(fip_chassis) + "/api/v2/ixos/cards/"
326
327         payload = json.dumps({"username": "admin",
328                               "password": "admin",
329                               "rememberMe": "false"})
330         api_key = json.loads((
331             ChassisRestAPI.postWithPayload(login_url, payload)))["apiKey"]
332
333         self.__logger.info("Adding 2 card back inside the ixia chassis...")
334
335         for ip in vcard_ips:
336             payload = {"ipAddress": str(ip)}
337             response = json.loads(ChassisRestAPI.postOperation(cards_url,
338                                                                api_key,
339                                                                payload))
340             count = 0
341             while (int(
342                  ChassisRestAPI.getWithHeaders(response['url'],
343                                                api_key)['progress']) != 100):
344                 self.__logger.debug("Operation did not finish yet. \
345                                     Waiting for 1 more second..")
346                 time.sleep(1)
347                 if count > 60:
348                     raise Exception("Adding card take more than 60 seconds")
349                 count += 1
350
351         ssh = paramiko.SSHClient()
352         ssh.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy())
353         ssh.connect(fip_chassis, username="admin", password="admin")
354         cmd = "set license-check disable"
355         run_blocking_ssh_command(ssh, cmd)
356         cmd = "restart-service ixServer"
357         run_blocking_ssh_command(ssh, cmd)
358
359         self.config_ellis(ellis_ip)
360
361         # Get IPs of P-CSCF
362         resolver = dns.resolver.Resolver()
363         resolver.nameservers = [dns_ip]
364         result = resolver.query("bono.clearwater.local")
365
366         iplistims = ''
367         i = 0
368         for rdata in result:
369             i = i + 1
370             print rdata.address
371             iplistims += str(rdata.address)
372             if i != len(result):
373                 iplistims += ';'
374
375         kResourcesUrl = 'http://%s:%s/api/v0/resources' % (fip_load, 8080)
376
377         kRxfPath = r"REG_CALL_OPNFV_v13.rxf"
378         test_filname = self.test['inputs']['test_filname']
379         kGatewaySharedFolder = '/mnt/ixload-share/'
380         kRxfRelativeUploadPath = 'uploads/%s' % os.path.split(kRxfPath)[1]
381         kRxfAbsoluteUploadPath = os.path.join(kGatewaySharedFolder,
382                                               kRxfRelativeUploadPath)
383         kChassisList = [str(fip_chassis)]
384         dataFileNameList = [test_filname,
385                             'Registration_only_LPS.tst',
386                             'SIPCall.tst']
387
388         kPortListPerCommunityCommunity = {"VoIP1@VM1": [(1, 1, 1)],
389                                           "VoIP2@VM2": [(1, 2, 1)]}
390
391         kStatsToDisplayDict = self.test['inputs']['stats']
392         connection = IxRestUtils.getConnection(fip_load, 8080)
393
394         self.__logger.info("Creating a new session...")
395         sessionUrl = IxLoadUtils.createSession(connection,
396                                                self.test['version'])
397
398         license_server = self.test['inputs']['licenseServer']
399         IxLoadUtils.configureLicenseServer(connection,
400                                            sessionUrl,
401                                            license_server)
402
403         files_dir = os.path.join(self.case_dir, 'ixia/files')
404         target_file = open(os.path.join(files_dir, test_filname), 'w')
405         j2_env = Environment(loader=FileSystemLoader(files_dir),
406                              trim_blocks=True)
407         self.test['inputs'].update(dict(
408                                     ipchassis=fip_chassis,
409                                     ipcard1=vcard_ips_p2[0],
410                                     ipcard2=vcard_ips_p2[1],
411                                     iplistims=iplistims
412         ))
413
414         target_file.write(
415             j2_env.get_template(test_filname + '.template').render(
416                 self.test['inputs']
417             ))
418         target_file.close()
419
420         self.__logger.info('Uploading files %s...' % kRxfPath)
421         for dataFile in dataFileNameList:
422             localFilePath = os.path.join(files_dir, dataFile)
423             remoteFilePath = os.path.join(kGatewaySharedFolder,
424                                           'uploads/%s' % dataFile)
425             IxLoadUtils.uploadFile(connection, kResourcesUrl,
426                                    localFilePath, remoteFilePath)
427         self.__logger.info('Upload file finished.')
428
429         self.__logger.info("Loading repository %s..." % kRxfAbsoluteUploadPath)
430         IxLoadUtils.loadRepository(connection, sessionUrl,
431                                    kRxfAbsoluteUploadPath)
432
433         self.__logger.info("Clearing chassis list...")
434         IxLoadUtils.clearChassisList(connection, sessionUrl)
435
436         self.__logger.info("Adding chassis %s..." % (kChassisList))
437         IxLoadUtils.addChassisList(connection, sessionUrl, kChassisList)
438
439         self.__logger.info("Assigning new ports...")
440         IxLoadUtils.assignPorts(connection, sessionUrl,
441                                 kPortListPerCommunityCommunity)
442
443         self.__logger.info("Starting the test...")
444         IxLoadUtils.runTest(connection, sessionUrl)
445
446         self.__logger.info("Polling values for stats %s..." % (
447                                                         kStatsToDisplayDict))
448         result = IxLoadUtils.pollStats(connection, sessionUrl,
449                                        kStatsToDisplayDict)
450         self.__logger.info("Test finished.")
451         self.__logger.info("Checking test status...")
452         testRunError = IxLoadUtils.getTestRunError(connection, sessionUrl)
453
454         self.__logger.info(result)
455         duration = time.time() - start_time
456         self.details['test_vnf'].update(status='PASS',
457                                         result=result,
458                                         duration=duration)
459         if testRunError:
460             self.__logger.info("The test exited with following error: %s" % (
461                                                             testRunError))
462             self.details['test_vnf'].update(status='FAIL', duration=duration)
463             return False
464         else:
465             self.__logger.info("The test completed successfully.")
466             self.details['test_vnf'].update(status='PASS', duration=duration)
467             self.result += 1/3 * 100
468             return True
469
470     def clean(self):
471         """Clean created objects/functions."""
472         super(CloudifyImsPerf, self).clean()
473
474     @energy.enable_recording
475     def run(self, **kwargs):
476         """Execute CloudifyIms test case."""
477         return super(CloudifyImsPerf, self).run(**kwargs)
478
479
480 # ----------------------------------------------------------
481 #
482 #               YAML UTILS
483 #
484 # -----------------------------------------------------------
485 def get_config(parameter, file_path):
486     """
487     Get config parameter.
488
489     Returns the value of a given parameter in file.yaml
490     parameter must be given in string format with dots
491     Example: general.openstack.image_name
492     """
493     with open(file_path) as config_file:
494         file_yaml = yaml.safe_load(config_file)
495     config_file.close()
496     value = file_yaml
497     for element in parameter.split("."):
498         value = value.get(element)
499         if value is None:
500             raise ValueError("The parameter %s is not defined in"
501                              " reporting.yaml" % parameter)
502     return value
503
504
505 def run_blocking_ssh_command(ssh, cmd, error_msg="Unable to run this command"):
506     """Command to run ssh command with the exit status."""
507     stdin, stdout, stderr = ssh.exec_command(cmd)
508     if stdout.channel.recv_exit_status() != 0:
509         raise Exception(error_msg)