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