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