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