Fixed comment
[snaps.git] / snaps / openstack / utils / launch_utils.py
1 #
2 # Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
3 #                    and others.  All rights reserved.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at:
8 #
9 #     http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17 # This utility makes it easy to create OpenStack objects
18 import logging
19 import re
20 import socket
21 import struct
22
23 import os
24 import time
25 from keystoneauth1.exceptions import Unauthorized
26
27 from snaps.config.flavor import FlavorConfig
28 from snaps.config.image import ImageConfig
29 from snaps.config.keypair import KeypairConfig
30 from snaps.config.network import PortConfig, NetworkConfig
31 from snaps.config.project import ProjectConfig
32 from snaps.config.qos import QoSConfig
33 from snaps.config.router import RouterConfig
34 from snaps.config.security_group import SecurityGroupConfig
35 from snaps.config.user import UserConfig
36 from snaps.config.vm_inst import VmInstanceConfig
37 from snaps.config.volume import VolumeConfig
38 from snaps.config.volume_type import VolumeTypeConfig
39 from snaps.openstack.create_flavor import OpenStackFlavor
40 from snaps.openstack.create_image import OpenStackImage
41 from snaps.openstack.create_keypairs import OpenStackKeypair
42 from snaps.openstack.create_network import OpenStackNetwork
43 from snaps.openstack.create_project import OpenStackProject
44 from snaps.openstack.create_qos import OpenStackQoS
45 from snaps.openstack.create_router import OpenStackRouter
46 from snaps.openstack.create_security_group import OpenStackSecurityGroup
47 from snaps.openstack.create_user import OpenStackUser
48 from snaps.openstack.create_volume import OpenStackVolume
49 from snaps.openstack.create_volume_type import OpenStackVolumeType
50 from snaps.openstack.os_credentials import OSCreds, ProxySettings
51 from snaps.openstack.utils import deploy_utils, neutron_utils
52 from snaps.provisioning import ansible_utils
53
54 logger = logging.getLogger('lanuch_utils')
55 DEFAULT_CREDS_KEY = 'admin'
56
57
58 def launch_config(config, tmplt_file, deploy, clean, clean_image):
59     """
60     Launches all objects and applies any configured ansible playbooks
61     :param config: the environment configuration dict object
62     :param tmplt_file: the path to the SNAPS-OO template file
63     :param deploy: when True deploy
64     :param clean: when True clean
65     :param clean_image: when True clean the image when clean is True
66     """
67     os_config = config.get('openstack')
68
69     creators = list()
70     vm_dict = dict()
71     images_dict = dict()
72     flavors_dict = dict()
73     networks_dict = dict()
74     routers_dict = dict()
75     os_creds_dict = dict()
76
77     if os_config:
78         os_creds_dict = __get_creds_dict(os_config)
79
80         # Create projects
81         projects_dict = __create_instances(
82             os_creds_dict, OpenStackProject, ProjectConfig,
83             os_config.get('projects'), 'project', clean)
84         creators.append(projects_dict)
85
86         # Create users
87         users_dict = __create_instances(
88             os_creds_dict, OpenStackUser, UserConfig,
89             os_config.get('users'), 'user', clean)
90         creators.append(users_dict)
91
92         # Associate new users to projects
93         if not clean:
94             for project_creator in projects_dict.values():
95                 users = project_creator.project_settings.users
96                 for user_name in users:
97                     user_creator = users_dict.get(user_name)
98                     if user_creator:
99                         project_creator.assoc_user(
100                             user_creator.get_user())
101
102         # Create flavors
103         flavors_dict = __create_instances(
104             os_creds_dict, OpenStackFlavor, FlavorConfig,
105             os_config.get('flavors'), 'flavor', clean, users_dict)
106         creators.append(flavors_dict)
107
108         # Create QoS specs
109         qos_dict = __create_instances(
110             os_creds_dict, OpenStackQoS, QoSConfig,
111             os_config.get('qos_specs'), 'qos_spec', clean, users_dict)
112         creators.append(qos_dict)
113
114         # Create volume types
115         vol_type_dict = __create_instances(
116             os_creds_dict, OpenStackVolumeType, VolumeTypeConfig,
117             os_config.get('volume_types'), 'volume_type', clean,
118             users_dict)
119         creators.append(vol_type_dict)
120
121         # Create volumes
122         vol_dict = __create_instances(
123             os_creds_dict, OpenStackVolume, VolumeConfig,
124             os_config.get('volumes'), 'volume', clean, users_dict)
125         creators.append(vol_dict)
126
127         # Create images
128         images_dict = __create_instances(
129             os_creds_dict, OpenStackImage, ImageConfig,
130             os_config.get('images'), 'image', clean, users_dict)
131         creators.append(images_dict)
132
133         # Create networks
134         networks_dict = __create_instances(
135             os_creds_dict, OpenStackNetwork, NetworkConfig,
136             os_config.get('networks'), 'network', clean, users_dict)
137         creators.append(networks_dict)
138
139         # Create routers
140         routers_dict = __create_instances(
141             os_creds_dict, OpenStackRouter, RouterConfig,
142             os_config.get('routers'), 'router', clean, users_dict)
143         creators.append(routers_dict)
144
145         # Create keypairs
146         keypairs_dict = __create_instances(
147             os_creds_dict, OpenStackKeypair, KeypairConfig,
148             os_config.get('keypairs'), 'keypair', clean, users_dict)
149         creators.append(keypairs_dict)
150
151         # Create security groups
152         creators.append(__create_instances(
153             os_creds_dict, OpenStackSecurityGroup,
154             SecurityGroupConfig,
155             os_config.get('security_groups'), 'security_group', clean,
156             users_dict))
157
158         # Create instance
159         vm_dict = __create_vm_instances(
160             os_creds_dict, users_dict, os_config.get('instances'),
161             images_dict, keypairs_dict, clean)
162         creators.append(vm_dict)
163         logger.info(
164             'Completed creating/retrieving all configured instances')
165
166     # Must enter either block
167     if clean:
168         # Cleanup Environment
169         __cleanup(creators, clean_image)
170     elif deploy:
171         # Provision VMs
172         ansible_config = config.get('ansible')
173         if ansible_config and vm_dict:
174             if not __apply_ansible_playbooks(
175                     ansible_config, os_creds_dict, vm_dict, images_dict,
176                     flavors_dict, networks_dict, routers_dict, tmplt_file):
177                 logger.error("Problem applying ansible playbooks")
178
179
180 def __get_creds_dict(os_conn_config):
181     """
182     Returns a dict of OSCreds where the key is the creds name.
183     For backwards compatibility, credentials not contained in a list (only
184     one) will be returned with the key of None
185     :param os_conn_config: the credential configuration
186     :return: a dict of OSCreds objects
187     """
188     if 'connection' in os_conn_config:
189         return {DEFAULT_CREDS_KEY: __get_os_credentials(os_conn_config)}
190     elif 'connections' in os_conn_config:
191         out = dict()
192         for os_conn_dict in os_conn_config['connections']:
193             config = os_conn_dict.get('connection')
194             if not config:
195                 raise Exception('Invalid connection format')
196
197             name = config.get('name')
198             if not name:
199                 raise Exception('Connection config requires a name field')
200
201             out[name] = __get_os_credentials(os_conn_dict)
202         return out
203
204
205 def __get_creds(os_creds_dict, os_user_dict, inst_config):
206     """
207     Returns the appropriate credentials
208     :param os_creds_dict: a dictionary of OSCreds objects where the name is the
209                           key
210     :param os_user_dict: a dictionary of OpenStackUser objects where the name
211                          is the key
212     :param inst_config:
213     :return: an OSCreds instance or None
214     """
215     os_creds = os_creds_dict.get(DEFAULT_CREDS_KEY)
216     if 'os_user' in inst_config:
217         os_user_conf = inst_config['os_user']
218         if 'name' in os_user_conf:
219             user_creator = os_user_dict.get(os_user_conf['name'])
220             if user_creator:
221                 return user_creator.get_os_creds(
222                     project_name=os_user_conf.get('project_name'))
223     elif 'os_creds_name' in inst_config:
224         if 'os_creds_name' in inst_config:
225             os_creds = os_creds_dict[inst_config['os_creds_name']]
226     return os_creds
227
228
229 def __get_os_credentials(os_conn_config):
230     """
231     Returns an object containing all of the information required to access
232     OpenStack APIs
233     :param os_conn_config: The configuration holding the credentials
234     :return: an OSCreds instance
235     """
236     config = os_conn_config.get('connection')
237     if not config:
238         raise Exception('Invalid connection configuration')
239
240     proxy_settings = None
241     http_proxy = config.get('http_proxy')
242     if http_proxy:
243         tokens = re.split(':', http_proxy)
244         ssh_proxy_cmd = config.get('ssh_proxy_cmd')
245         proxy_settings = ProxySettings(host=tokens[0], port=tokens[1],
246                                        ssh_proxy_cmd=ssh_proxy_cmd)
247     else:
248         if 'proxy_settings' in config:
249             host = config['proxy_settings'].get('host')
250             port = config['proxy_settings'].get('port')
251             if host and host != 'None' and port and port != 'None':
252                 proxy_settings = ProxySettings(**config['proxy_settings'])
253
254     if proxy_settings:
255         config['proxy_settings'] = proxy_settings
256     else:
257         if config.get('proxy_settings'):
258             del config['proxy_settings']
259
260     return OSCreds(**config)
261
262
263 def __parse_ports_config(config):
264     """
265     Parses the "ports" configuration
266     :param config: The dictionary to parse
267     :return: a list of PortConfig objects
268     """
269     out = list()
270     for port_config in config:
271         out.append(PortConfig(**port_config.get('port')))
272     return out
273
274
275 def __create_instances(os_creds_dict, creator_class, config_class, config,
276                        config_key, cleanup=False, os_users_dict=None):
277     """
278     Returns a dictionary of SNAPS creator objects where the key is the name
279     :param os_creds_dict: Dictionary of OSCreds objects where the key is the
280                           name
281     :param config: The list of configurations for the same type
282     :param config_key: The list of configurations for the same type
283     :param cleanup: Denotes whether or not this is being called for cleanup
284     :return: dictionary
285     """
286     out = {}
287
288     if config:
289         for config_dict in config:
290             inst_config = config_dict.get(config_key)
291             if inst_config:
292                 creds = __get_creds(os_creds_dict, os_users_dict, inst_config)
293                 if creds:
294                     creator = creator_class(
295                         creds,
296                         config_class(**inst_config))
297
298                     if creator:
299                         if cleanup:
300                             try:
301                                 creator.initialize()
302                             except Unauthorized as e:
303                                 logger.warn(
304                                     'Unable to initialize creator [%s] - %s',
305                                     creator, e)
306                         else:
307                             creator.create()
308
309                         out[inst_config['name']] = creator
310
311         logger.info('Initialized configured %ss', config_key)
312
313     return out
314
315
316 def __create_vm_instances(os_creds_dict, os_users_dict, instances_config,
317                           image_dict, keypairs_dict, cleanup=False):
318     """
319     Returns a dictionary of OpenStackVmInstance objects where the key is the
320     instance name
321     :param os_creds_dict: Dictionary of OSCreds objects where the key is the
322                           name
323     :param os_users_dict: Dictionary of OpenStackUser objects where the key is
324                           the username
325     :param instances_config: The list of VM instance configurations
326     :param image_dict: A dictionary of images that will probably be used to
327                        instantiate the VM instance
328     :param keypairs_dict: A dictionary of keypairs that will probably be used
329                           to instantiate the VM instance
330     :param cleanup: Denotes whether or not this is being called for cleanup
331     :return: dictionary
332     """
333     vm_dict = {}
334
335     if instances_config:
336         for instance_config in instances_config:
337             conf = instance_config.get('instance')
338             if conf:
339                 if image_dict:
340                     image_creator = image_dict.get(conf.get('imageName'))
341                     if image_creator:
342                         instance_settings = VmInstanceConfig(
343                             **instance_config['instance'])
344                         kp_creator = keypairs_dict.get(
345                             conf.get('keypair_name'))
346
347                         try:
348                             vm_dict[conf[
349                                 'name']] = deploy_utils.create_vm_instance(
350                                 __get_creds(
351                                     os_creds_dict, os_users_dict, conf),
352                                 instance_settings,
353                                 image_creator.image_settings,
354                                 keypair_creator=kp_creator,
355                                 init_only=cleanup)
356                         except Unauthorized as e:
357                             if not cleanup:
358                                 logger.warn('Unable to initialize VM - %s', e)
359                                 raise
360                     else:
361                         raise Exception('Image creator instance not found.'
362                                         ' Cannot instantiate')
363                 else:
364                     if not cleanup:
365                         raise Exception('Image dictionary is None. Cannot '
366                                         'instantiate')
367             else:
368                 raise Exception('Instance configuration is None. Cannot '
369                                 'instantiate')
370         logger.info('Created configured instances')
371
372     return vm_dict
373
374
375 def __apply_ansible_playbooks(ansible_configs, os_creds_dict, vm_dict,
376                               image_dict, flavor_dict, networks_dict,
377                               routers_dict, tmplt_file):
378     """
379     Applies ansible playbooks to running VMs with floating IPs
380     :param ansible_configs: a list of Ansible configurations
381     :param os_creds_dict: Dictionary of OSCreds objects where the key is the
382                           name
383     :param vm_dict: the dictionary of newly instantiated VMs where the name is
384                     the key
385     :param image_dict: the dictionary of newly instantiated images where the
386                        name is the key
387     :param flavor_dict: the dictionary of newly instantiated flavors where the
388                         name is the key
389     :param networks_dict: the dictionary of newly instantiated networks where
390                           the name is the key
391     :param routers_dict: the dictionary of newly instantiated routers where
392                           the name is the key
393     :param tmplt_file: the path of the SNAPS-OO template file for setting the
394                        CWD so playbook location is relative to the deployment
395                        file
396     :return: t/f - true if successful
397     """
398     logger.info("Applying Ansible Playbooks")
399     if ansible_configs:
400         # Set CWD so the deployment file's playbook location can leverage
401         # relative paths
402         orig_cwd = os.getcwd()
403         env_dir = os.path.dirname(tmplt_file)
404         os.chdir(env_dir)
405
406         # Apply playbooks
407         for ansible_config in ansible_configs:
408             # Ensure all hosts are accepting SSH session requests
409             for vm_name in ansible_config['hosts']:
410                 vm_inst = vm_dict.get(vm_name)
411                 if vm_inst:
412                     if not vm_inst.vm_ssh_active(block=True):
413                         logger.warning(
414                             'Timeout waiting for instance to respond to '
415                             'SSH requests')
416                         return False
417
418             os_creds = os_creds_dict.get('admin-creds')
419             __apply_ansible_playbook(
420                 ansible_config, os_creds, vm_dict, image_dict, flavor_dict,
421                 networks_dict, routers_dict)
422
423         # Return to original directory
424         os.chdir(orig_cwd)
425
426     return True
427
428
429 def __apply_ansible_playbook(ansible_config, os_creds, vm_dict, image_dict,
430                              flavor_dict, networks_dict, routers_dict):
431     """
432     Applies an Ansible configuration setting
433     :param ansible_config: the configuration settings
434     :param os_creds: the OpenStack admin credentials object
435     :param vm_dict: the dictionary of newly instantiated VMs where the name is
436                     the key
437     :param image_dict: the dictionary of newly instantiated images where the
438                        name is the key
439     :param flavor_dict: the dictionary of newly instantiated flavors where the
440                         name is the key
441     :param networks_dict: the dictionary of newly instantiated networks where
442                           the name is the key
443     :param routers_dict: the dictionary of newly instantiated routers where
444                           the name is the key
445     """
446     if ansible_config:
447         (remote_user, floating_ips, private_key_filepath,
448          proxy_settings) = __get_connection_info(
449             ansible_config, vm_dict)
450         if floating_ips:
451             for key, vm_creator in vm_dict.items():
452                 fip = vm_creator.get_floating_ip()
453                 if fip and fip.ip in floating_ips:
454                     if not vm_creator.cloud_init_complete(block=True):
455                         raise Exception(
456                             'Cannot apply playbooks as cloud-init has not '
457                             'completed')
458
459             variables = __get_variables(
460                 ansible_config.get('variables'), os_creds, vm_dict, image_dict,
461                 flavor_dict, networks_dict, routers_dict)
462
463             retval = ansible_utils.apply_playbook(
464                 ansible_config['playbook_location'], floating_ips, remote_user,
465                 ssh_priv_key_file_path=private_key_filepath,
466                 variables=variables,
467                 proxy_setting=proxy_settings)
468             if retval != 0:
469                 # Not a fatal type of event
470                 raise Exception(
471                     'Error applying playbook found at location - %s',
472                     ansible_config.get('playbook_location'))
473             elif ansible_config.get('post_processing'):
474                 post_proc_config = ansible_config['post_processing']
475                 if 'sleep' in post_proc_config:
476                     time.sleep(post_proc_config['sleep'])
477                 if 'reboot' in post_proc_config:
478                     for vm_name in post_proc_config['reboot']:
479                         if vm_name in vm_dict:
480                             logger.info('Rebooting VM - %s', vm_name)
481                             vm_dict[vm_name].reboot()
482
483             return retval
484
485
486 def __get_connection_info(ansible_config, vm_dict):
487     """
488     Returns a tuple of data required for connecting to the running VMs
489     (remote_user, [floating_ips], private_key_filepath, proxy_settings)
490     :param ansible_config: the configuration settings
491     :param vm_dict: the dictionary of VMs where the VM name is the key
492     :return: tuple where the first element is the user and the second is a list
493              of floating IPs and the third is the
494     private key file location and the fourth is an instance of the
495     snaps.ProxySettings class
496     (note: in order to work, each of the hosts need to have the same sudo_user
497     and private key file location values)
498     """
499     if ansible_config.get('hosts'):
500         hosts = ansible_config['hosts']
501         if len(hosts) > 0:
502             floating_ips = list()
503             remote_user = None
504             pk_file = None
505             proxy_settings = None
506             for host in hosts:
507                 vm = vm_dict.get(host)
508                 if vm:
509                     fip = vm.get_floating_ip()
510                     if fip:
511                         remote_user = vm.get_image_user()
512
513                         if fip:
514                             floating_ips.append(fip.ip)
515                         else:
516                             raise Exception(
517                                 'Could not find floating IP for VM - ' +
518                                 vm.name)
519
520                         pk_file = vm.keypair_settings.private_filepath
521                         proxy_settings = vm.get_os_creds().proxy_settings
522                 else:
523                     logger.error('Could not locate VM with name - ' + host)
524
525             return remote_user, floating_ips, pk_file, proxy_settings
526     return None
527
528
529 def __get_variables(var_config, os_creds, vm_dict, image_dict, flavor_dict,
530                     networks_dict, routers_dict):
531     """
532     Returns a dictionary of substitution variables to be used for Ansible
533     templates
534     :param var_config: the variable configuration settings
535     :param os_creds: the OpenStack admin credentials object
536     :param vm_dict: the dictionary of newly instantiated VMs where the name is
537                     the key
538     :param image_dict: the dictionary of newly instantiated images where the
539                        name is the key
540     :param flavor_dict: the dictionary of newly instantiated flavors where the
541                         name is the key
542     :param networks_dict: the dictionary of newly instantiated networks where
543                           the name is the key
544     :param routers_dict: the dictionary of newly instantiated routers where
545                           the name is the key
546     :return: dictionary or None
547     """
548     if var_config and vm_dict and len(vm_dict) > 0:
549         variables = dict()
550         for key, value in var_config.items():
551             value = __get_variable_value(
552                 value, os_creds, vm_dict, image_dict, flavor_dict,
553                 networks_dict, routers_dict)
554             if key and value:
555                 variables[key] = value
556                 logger.info(
557                     "Set Jinga2 variable with key [%s] the value [%s]",
558                     key, value)
559             else:
560                 raise Exception(
561                     'Key - [' + str(key) + '] or Value [' + str(value)
562                     + '] must not be None')
563         return variables
564     return None
565
566
567 def __get_variable_value(var_config_values, os_creds, vm_dict, image_dict,
568                          flavor_dict, networks_dict, routers_dict):
569     """
570     Returns the associated variable value for use by Ansible for substitution
571     purposes
572     :param var_config_values: the configuration dictionary
573     :param os_creds: the OpenStack admin credentials object
574     :param vm_dict: the dictionary of newly instantiated VMs where the name is
575                     the key
576     :param image_dict: the dictionary of newly instantiated images where the
577                        name is the key
578     :param flavor_dict: the dictionary of newly instantiated flavors where the
579                         name is the key
580     :param networks_dict: the dictionary of newly instantiated networks where
581                           the name is the key
582     :param routers_dict: the dictionary of newly instantiated routers where
583                           the name is the key
584     :return:
585     """
586     if var_config_values['type'] == 'string':
587         return __get_string_variable_value(var_config_values)
588     if var_config_values['type'] == 'vm-attr':
589         return __get_vm_attr_variable_value(var_config_values, vm_dict)
590     if var_config_values['type'] == 'os_creds':
591         return __get_os_creds_variable_value(var_config_values, os_creds)
592     if var_config_values['type'] == 'network':
593         return __get_network_variable_value(var_config_values, networks_dict)
594     if var_config_values['type'] == 'router':
595         return __get_router_variable_value(var_config_values, routers_dict,
596                                            os_creds)
597     if var_config_values['type'] == 'port':
598         return __get_vm_port_variable_value(var_config_values, vm_dict)
599     if var_config_values['type'] == 'floating_ip':
600         return __get_vm_fip_variable_value(var_config_values, vm_dict)
601     if var_config_values['type'] == 'image':
602         return __get_image_variable_value(var_config_values, image_dict)
603     if var_config_values['type'] == 'flavor':
604         return __get_flavor_variable_value(var_config_values, flavor_dict)
605     return None
606
607
608 def __get_string_variable_value(var_config_values):
609     """
610     Returns the associated string value
611     :param var_config_values: the configuration dictionary
612     :return: the value contained in the dictionary with the key 'value'
613     """
614     return var_config_values['value']
615
616
617 def __get_vm_attr_variable_value(var_config_values, vm_dict):
618     """
619     Returns the associated value contained on a VM instance
620     :param var_config_values: the configuration dictionary
621     :param vm_dict: the dictionary containing all VMs where the key is the VM's
622                     name
623     :return: the value
624     """
625     vm = vm_dict.get(var_config_values['vm_name'])
626     if vm:
627         if var_config_values['value'] == 'floating_ip':
628             return vm.get_floating_ip().ip
629         if var_config_values['value'] == 'image_user':
630             return vm.get_image_user()
631
632
633 def __get_os_creds_variable_value(var_config_values, os_creds):
634     """
635     Returns the associated OS credentials value
636     :param var_config_values: the configuration dictionary
637     :param os_creds: the admin OpenStack OSCreds object
638     :return: the value
639     """
640     if os_creds:
641         if var_config_values['value'] == 'username':
642             logger.info("Returning OS username")
643             return os_creds.username
644         elif var_config_values['value'] == 'password':
645             logger.info("Returning OS password")
646             return os_creds.password
647         elif var_config_values['value'] == 'auth_url':
648             logger.info("Returning OS auth_url")
649             return os_creds.auth_url
650         elif var_config_values['value'] == 'project_name':
651             logger.info("Returning OS project_name")
652             return os_creds.project_name
653
654
655 def __get_network_variable_value(var_config_values, networks_dict):
656     """
657     Returns the associated network value
658     :param var_config_values: the configuration dictionary
659     :param networks_dict: the dictionary containing all networks where the key
660                           is the network name
661     :return: the value
662     """
663     net_name = var_config_values.get('network_name')
664
665     if net_name and networks_dict.get(net_name):
666         network_creator = networks_dict[net_name]
667
668         if 'subnet_name' in var_config_values:
669             subnet_name = var_config_values.get('subnet_name')
670             if subnet_name:
671                 for subnet in network_creator.get_network().subnets:
672                     if subnet_name == subnet.name:
673                         if 'value' in var_config_values:
674                             if 'gateway_ip' == var_config_values['value']:
675                                 return subnet.gateway_ip
676                             if 'ip_range' == var_config_values['value']:
677                                 return subnet.start + ' ' + subnet.end
678                             if 'ip_range_start' == var_config_values['value']:
679                                 return subnet.start
680                             if 'ip_range_end' == var_config_values['value']:
681                                 return subnet.end
682                             if 'cidr' == var_config_values['value']:
683                                 return subnet.cidr
684                             if 'cidr_ip' == var_config_values['value']:
685                                 cidr_split = subnet.cidr.split('/')
686                                 return cidr_split[0]
687                             if 'netmask' == var_config_values['value']:
688                                 cidr_split = subnet.cidr.split('/')
689                                 cidr_bits = 32 - int(cidr_split[1])
690                                 netmask = socket.inet_ntoa(
691                                     struct.pack(
692                                         '!I', (1 << 32) - (1 << cidr_bits)))
693                                 return netmask
694                             if 'broadcast_ip' == var_config_values['value']:
695                                 end_split = subnet.end.split('.')
696                                 broadcast_ip = (
697                                     end_split[0] + '.' + end_split[1] + '.'
698                                     + end_split[2] + '.255')
699                                 return broadcast_ip
700
701
702 def __get_router_variable_value(var_config_values, routers_dict, os_creds):
703     """
704     Returns the associated network value
705     :param var_config_values: the configuration dictionary
706     :param routers_dict: the dictionary containing all networks where the key
707                           is the network name
708     :param os_creds: the admin OpenStack credentials
709     :return: the value
710     """
711     router_name = var_config_values.get('router_name')
712     router_creator = routers_dict[router_name]
713
714     if router_creator:
715         if 'external_fixed_ip' == var_config_values.get('attr'):
716             neutron = neutron_utils.neutron_client(os_creds)
717             ext_nets = neutron_utils.get_external_networks(neutron)
718
719             subnet_name = var_config_values.get('subnet_name')
720
721             for ext_net in ext_nets:
722                 for subnet in ext_net.subnets:
723                     if subnet_name == subnet.name:
724                         router = router_creator.get_router()
725                         for fixed_ips in router.external_fixed_ips:
726                             if subnet.id == fixed_ips['subnet_id']:
727                                 return fixed_ips['ip_address']
728
729
730 def __get_vm_port_variable_value(var_config_values, vm_dict):
731     """
732     Returns the associated OS credentials value
733     :param var_config_values: the configuration dictionary
734     :param vm_dict: the dictionary containing all VMs where the key is the VM's
735                     name
736     :return: the value
737     """
738     port_name = var_config_values.get('port_name')
739     vm_name = var_config_values.get('vm_name')
740
741     if port_name and vm_name:
742         vm = vm_dict.get(vm_name)
743         if vm:
744             for vm_port in vm.get_vm_inst().ports:
745                 if vm_port.name == port_name:
746                     port_value_id = var_config_values.get('port_value')
747                     if port_value_id:
748                         if port_value_id == 'mac_address':
749                             return vm_port.mac_address
750                         if port_value_id == 'ip_address':
751                             return vm_port.ips[0]['ip_address']
752
753
754 def __get_vm_fip_variable_value(var_config_values, vm_dict):
755     """
756     Returns the floating IP value if found
757     :param var_config_values: the configuration dictionary
758     :param vm_dict: the dictionary containing all VMs where the key is the VM's
759                     name
760     :return: the floating IP string value or None
761     """
762     fip_name = var_config_values.get('fip_name')
763     vm_name = var_config_values.get('vm_name')
764
765     if vm_name:
766         vm = vm_dict.get(vm_name)
767         if vm:
768             fip = vm.get_floating_ip(fip_name)
769             if fip:
770                 return fip.ip
771
772
773 def __get_image_variable_value(var_config_values, image_dict):
774     """
775     Returns the associated image value
776     :param var_config_values: the configuration dictionary
777     :param image_dict: the dictionary containing all images where the key is
778                        the name
779     :return: the value
780     """
781     if image_dict:
782         if var_config_values.get('image_name'):
783             image_creator = image_dict.get(var_config_values['image_name'])
784             if image_creator:
785                 if (var_config_values.get('value')
786                         and var_config_values['value'] == 'id'):
787                     return image_creator.get_image().id
788                 if (var_config_values.get('value')
789                         and var_config_values['value'] == 'user'):
790                     return image_creator.image_settings.image_user
791
792
793 def __get_flavor_variable_value(var_config_values, flavor_dict):
794     """
795     Returns the associated flavor value
796     :param var_config_values: the configuration dictionary
797     :param flavor_dict: the dictionary containing all flavor creators where the
798                         key is the name
799     :return: the value or None
800     """
801     if flavor_dict:
802         if var_config_values.get('flavor_name'):
803             flavor_creator = flavor_dict.get(var_config_values['flavor_name'])
804             if flavor_creator:
805                 if (var_config_values.get('value')
806                         and var_config_values['value'] == 'id'):
807                     return flavor_creator.get_flavor().id
808
809
810 def __cleanup(creators, clean_image=False):
811     """
812     Cleans up environment
813     :param creators: the list of creators by type
814     :param clean_image: when true
815     :return:
816     """
817     for creator_dict in reversed(creators):
818         for key, creator in creator_dict.items():
819             if ((isinstance(creator, OpenStackImage) and clean_image)
820                     or not isinstance(creator, OpenStackImage)):
821                 creator.clean()