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