3 # Copyright (c) 2016 Orange and others.
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
14 from scp import SCPClient
16 from cloudify_rest_client import CloudifyClient
17 from cloudify_rest_client.executions import Execution
19 import functest.opnfv_tests.vnf.ims.clearwater_ims_base as clearwater_ims_base
20 from functest.utils.constants import CONST
21 import functest.utils.openstack_utils as os_utils
23 from snaps.openstack.os_credentials import OSCreds
24 from snaps.openstack.create_network import NetworkSettings, SubnetSettings, \
26 from snaps.openstack.create_security_group import SecurityGroupSettings, \
27 SecurityGroupRuleSettings,\
28 Direction, Protocol, \
29 OpenStackSecurityGroup
30 from snaps.openstack.create_router import RouterSettings, OpenStackRouter
31 from snaps.openstack.create_instance import VmInstanceSettings, \
34 from snaps.openstack.create_flavor import FlavorSettings, OpenStackFlavor
35 from snaps.openstack.create_image import ImageSettings, OpenStackImage
36 from snaps.openstack.create_keypairs import KeypairSettings, OpenStackKeypair
37 from snaps.openstack.create_network import PortSettings
39 from functest.opnfv_tests.openstack.snaps import snaps_utils
42 __author__ = "Valentin Boucher <valentin.boucher@orange.com>"
45 class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase):
46 """Clearwater vIMS deployed with Cloudify Orchestrator Case"""
48 __logger = logging.getLogger(__name__)
50 def __init__(self, **kwargs):
51 if "case_name" not in kwargs:
52 kwargs["case_name"] = "cloudify_ims"
53 super(CloudifyIms, self).__init__(**kwargs)
55 # Retrieve the configuration
57 self.config = CONST.__getattribute__(
58 'vnf_{}_config'.format(self.case_name))
60 raise Exception("VNF config file not found")
63 self.created_object = []
65 config_file = os.path.join(self.case_dir, self.config)
66 self.orchestrator = dict(
67 requirements=get_config("orchestrator.requirements", config_file),
69 self.details['orchestrator'] = dict(
70 name=get_config("orchestrator.name", config_file),
71 version=get_config("orchestrator.version", config_file),
75 self.__logger.debug("Orchestrator configuration %s", self.orchestrator)
77 descriptor=get_config("vnf.descriptor", config_file),
78 inputs=get_config("vnf.inputs", config_file),
79 requirements=get_config("vnf.requirements", config_file)
81 self.details['vnf'] = dict(
82 descriptor_version=self.vnf['descriptor']['version'],
83 name=get_config("vnf.name", config_file),
84 version=get_config("vnf.version", config_file),
86 self.__logger.debug("VNF configuration: %s", self.vnf)
88 self.details['test_vnf'] = dict(
89 name=get_config("vnf_test_suite.name", config_file),
90 version=get_config("vnf_test_suite.version", config_file)
92 self.images = get_config("tenant_images", config_file)
93 self.__logger.info("Images needed for vIMS: %s", self.images)
96 super(CloudifyIms, self).prepare()
98 self.__logger.info("Additional pre-configuration steps")
100 self.snaps_creds = OSCreds(
101 username=self.creds['username'],
102 password=self.creds['password'],
103 auth_url=self.creds['auth_url'],
104 project_name=self.creds['tenant'],
105 identity_api_version=int(os_utils.get_keystone_client_version()))
108 self.__logger.info("Upload some OS images if it doesn't exist")
109 for image_name, image_url in self.images.iteritems():
110 self.__logger.info("image: %s, url: %s", image_name, image_url)
111 if image_url and image_name:
112 image_creator = OpenStackImage(
114 ImageSettings(name=image_name,
118 image_creator.create()
119 # self.created_object.append(image_creator)
121 def deploy_orchestrator(self):
123 Deploy Cloudify Manager
125 network, security group, fip, VM creation
129 start_time = time.time()
130 self.__logger.info("Creating keypair ...")
131 kp_file = os.path.join(self.data_dir, "cloudify_ims.pem")
132 keypair_settings = KeypairSettings(name='cloudify_ims_kp',
133 private_filepath=kp_file)
134 keypair_creator = OpenStackKeypair(self.snaps_creds, keypair_settings)
135 keypair_creator.create()
136 self.created_object.append(keypair_creator)
138 self.__logger.info("Creating full network ...")
139 subnet_settings = SubnetSettings(name='cloudify_ims_subnet',
140 cidr='10.67.79.0/24')
141 network_settings = NetworkSettings(name='cloudify_ims_network',
142 subnet_settings=[subnet_settings])
143 network_creator = OpenStackNetwork(self.snaps_creds, network_settings)
144 network_creator.create()
145 self.created_object.append(network_creator)
146 ext_net_name = snaps_utils.get_ext_net_name(self.snaps_creds)
147 router_creator = OpenStackRouter(
150 name='cloudify_ims_router',
151 external_gateway=ext_net_name,
152 internal_subnets=[subnet_settings.name]))
153 router_creator.create()
154 self.created_object.append(router_creator)
156 # security group creation
157 self.__logger.info("Creating security group for cloudify manager vm")
160 SecurityGroupRuleSettings(sec_grp_name="sg-cloudify-manager",
161 direction=Direction.ingress,
162 protocol=Protocol.tcp, port_range_min=1,
163 port_range_max=65535))
165 SecurityGroupRuleSettings(sec_grp_name="sg-cloudify-manager",
166 direction=Direction.ingress,
167 protocol=Protocol.udp, port_range_min=1,
168 port_range_max=65535))
170 securit_group_creator = OpenStackSecurityGroup(
172 SecurityGroupSettings(
173 name="sg-cloudify-manager",
174 rule_settings=sg_rules))
176 securit_group_creator.create()
177 self.created_object.append(securit_group_creator)
179 # orchestrator VM flavor
180 self.__logger.info("Get or create flavor for cloudify manager vm ...")
182 flavor_settings = FlavorSettings(
183 name=self.orchestrator['requirements']['flavor']['name'],
184 ram=self.orchestrator['requirements']['flavor']['ram_min'],
187 flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings)
188 flavor_creator.create()
189 self.created_object.append(flavor_creator)
190 image_settings = ImageSettings(
191 name=self.orchestrator['requirements']['os_image'],
195 port_settings = PortSettings(name='cloudify_manager_port',
196 network_name=network_settings.name)
198 manager_settings = VmInstanceSettings(
199 name='cloudify_manager',
200 flavor=flavor_settings.name,
201 port_settings=[port_settings],
202 security_group_names=[securit_group_creator.sec_grp_settings.name],
203 floating_ip_settings=[FloatingIpSettings(
204 name='cloudify_manager_fip',
205 port_name=port_settings.name,
206 router_name=router_creator.router_settings.name)])
208 manager_creator = OpenStackVmInstance(self.snaps_creds,
213 self.__logger.info("Creating cloudify manager VM")
214 manager_creator.create()
215 self.created_object.append(manager_creator)
217 public_auth_url = os_utils.get_endpoint('identity')
219 self.__logger.info("Set creds for cloudify manager")
220 cfy_creds = dict(keystone_username=self.tenant_name,
221 keystone_password=self.tenant_name,
222 keystone_tenant_name=self.tenant_name,
223 keystone_url=public_auth_url)
225 cfy_client = CloudifyClient(host=manager_creator.get_floating_ip().ip,
228 tenant='default_tenant')
230 self.orchestrator['object'] = cfy_client
232 self.__logger.info("Attemps running status of the Manager")
235 while str(cfy_status) != 'running' and retry:
237 cfy_status = cfy_client.manager.get_status()['status']
238 except Exception: # pylint: disable=broad-except
239 self.__logger.warning("Cloudify Manager isn't " +
240 "up and running. Retrying ...")
244 if str(cfy_status) == 'running':
245 self.__logger.info("Cloudify Manager is up and running")
247 raise Exception("Cloudify Manager isn't up and running")
249 self.__logger.info("Put OpenStack creds in manager")
250 secrets_list = cfy_client.secrets.list()
251 for k, val in cfy_creds.iteritems():
252 if not any(d.get('key', None) == k for d in secrets_list):
253 cfy_client.secrets.create(k, val)
255 cfy_client.secrets.update(k, val)
257 duration = time.time() - start_time
259 self.__logger.info("Put private keypair in manager")
260 if manager_creator.vm_ssh_active(block=True):
261 ssh = manager_creator.ssh_client()
262 scp = SCPClient(ssh.get_transport())
263 scp.put(kp_file, '~/')
264 cmd = "sudo cp ~/cloudify_ims.pem /etc/cloudify/"
265 ssh.exec_command(cmd)
266 cmd = "sudo chmod 444 /etc/cloudify/cloudify_ims.pem"
267 ssh.exec_command(cmd)
268 cmd = "sudo yum install -y gcc python-devel"
269 ssh.exec_command(cmd)
271 self.details['orchestrator'].update(status='PASS', duration=duration)
273 self.vnf['inputs'].update(dict(
274 external_network_name=ext_net_name,
275 network_name=network_settings.name
279 def deploy_vnf(self):
281 Deploy Clearwater IMS
283 start_time = time.time()
285 self.__logger.info("Upload VNFD")
286 cfy_client = self.orchestrator['object']
287 descriptor = self.vnf['descriptor']
288 cfy_client.blueprints.publish_archive(descriptor.get('url'),
289 descriptor.get('name'),
290 descriptor.get('file_name'))
292 self.__logger.info("Get or create flavor for all clearwater vm")
293 self.exist_obj['flavor2'], flavor_id = os_utils.get_or_create_flavor(
294 self.vnf['requirements']['flavor']['name'],
295 self.vnf['requirements']['flavor']['ram_min'],
300 self.vnf['inputs'].update(dict(
304 self.__logger.info("Create VNF Instance")
305 cfy_client.deployments.create(descriptor.get('name'),
306 descriptor.get('name'),
307 self.vnf.get('inputs'))
309 wait_for_execution(cfy_client,
310 _get_deployment_environment_creation_execution(
311 cfy_client, descriptor.get('name')),
315 self.__logger.info("Start the VNF Instance deployment")
316 execution = cfy_client.executions.start(descriptor.get('name'),
319 execution = wait_for_execution(cfy_client, execution, self.__logger)
321 duration = time.time() - start_time
323 self.__logger.info(execution)
324 if execution.status == 'terminated':
325 self.details['vnf'].update(status='PASS', duration=duration)
328 self.details['vnf'].update(status='FAIL', duration=duration)
333 Run test on clearwater ims instance
335 start_time = time.time()
337 cfy_client = self.orchestrator['object']
339 outputs = cfy_client.deployments.outputs.get(
340 self.vnf['descriptor'].get('name'))['outputs']
341 dns_ip = outputs['dns_ip']
342 ellis_ip = outputs['ellis_ip']
343 self.config_ellis(ellis_ip)
346 vims_test_result = self.run_clearwater_live_test(
348 public_domain=self.vnf['inputs']["public_domain"])
349 duration = time.time() - start_time
350 short_result = sig_test_format(vims_test_result)
351 self.__logger.info(short_result)
352 self.details['test_vnf'].update(status='PASS',
354 full_result=vims_test_result,
362 cfy_client = self.orchestrator['object']
363 dep_name = self.vnf['descriptor'].get('name')
364 # kill existing execution
365 self.__logger.info('Deleting the current deployment')
366 exec_list = cfy_client.executions.list(dep_name)
367 for execution in exec_list:
368 if execution['status'] == "started":
370 cfy_client.executions.cancel(execution['id'],
373 self.__logger.warn("Can't cancel the current exec")
375 execution = cfy_client.executions.start(
378 parameters=dict(ignore_failure=True),
381 wait_for_execution(cfy_client, execution, self.__logger)
382 cfy_client.deployments.delete(self.vnf['descriptor'].get('name'))
383 cfy_client.blueprints.delete(self.vnf['descriptor'].get('name'))
385 self.__logger.warn("Some issue during the undeployment ..")
386 self.__logger.warn("Tenant clean continue ..")
388 self.__logger.info('Remove the cloudify manager OS object ..')
389 for creator in reversed(self.created_object):
392 except Exception as e:
393 self.logger.error('Unexpected error cleaning - %s', e)
394 super(CloudifyIms, self).clean()
397 # ----------------------------------------------------------
401 # -----------------------------------------------------------
402 def get_config(parameter, file_path):
404 Returns the value of a given parameter in file.yaml
405 parameter must be given in string format with dots
406 Example: general.openstack.image_name
408 with open(file_path) as config_file:
409 file_yaml = yaml.safe_load(config_file)
412 for element in parameter.split("."):
413 value = value.get(element)
415 raise ValueError("The parameter %s is not defined in"
416 " reporting.yaml" % parameter)
420 def wait_for_execution(client, execution, logger, timeout=2400, ):
422 Wait for a workflow execution on Cloudify Manager
424 # if execution already ended - return without waiting
425 if execution.status in Execution.END_STATES:
428 if timeout is not None:
429 deadline = time.time() + timeout
431 # Poll for execution status and execution logs, until execution ends
432 # and we receive an event of type in WORKFLOW_END_TYPES
436 execution_ended = False
438 event_list = client.events.list(
439 execution_id=execution.id,
443 sort='@timestamp').items
445 offset = offset + len(event_list)
446 for event in event_list:
447 logger.debug(event.get('message'))
449 if timeout is not None:
450 if time.time() > deadline:
452 'execution of operation {0} for deployment {1} '
453 'timed out'.format(execution.workflow_id,
454 execution.deployment_id))
456 # update the remaining timeout
457 timeout = deadline - time.time()
459 if not execution_ended:
460 execution = client.executions.get(execution.id)
461 execution_ended = execution.status in Execution.END_STATES
471 def _get_deployment_environment_creation_execution(client, deployment_id):
473 Get the execution id of a env preparation
475 network, security group, fip, VM creation
477 executions = client.executions.list(deployment_id=deployment_id)
478 for execution in executions:
479 if execution.workflow_id == 'create_deployment_environment':
481 raise RuntimeError('Failed to get create_deployment_environment '
482 'workflow execution.'
483 'Available executions: {0}'.format(executions))
486 def sig_test_format(sig_test):
488 Process the signaling result to have a short result
493 for data_test in sig_test:
494 if data_test['result'] == "Passed":
496 elif data_test['result'] == "Failed":
498 elif data_test['result'] == "Skipped":
500 total_sig_test_result = {}
501 total_sig_test_result['passed'] = nb_passed
502 total_sig_test_result['failures'] = nb_failures
503 total_sig_test_result['skipped'] = nb_skipped
504 return total_sig_test_result