Updates to the ansible API implementation to allow for
[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             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
473             if 'post_processing' in ansible_config:
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(RebootType.hard)
482
483
484 def __get_connection_info(ansible_config, vm_dict):
485     """
486     Returns a tuple of data required for connecting to the running VMs
487     (remote_user, [floating_ips], private_key_filepath, proxy_settings)
488     :param ansible_config: the configuration settings
489     :param vm_dict: the dictionary of VMs where the VM name is the key
490     :return: tuple where the first element is the user and the second is a list
491              of floating IPs and the third is the
492     private key file location and the fourth is an instance of the
493     snaps.ProxySettings class
494     (note: in order to work, each of the hosts need to have the same sudo_user
495     and private key file location values)
496     """
497     if ansible_config.get('hosts'):
498         hosts = ansible_config['hosts']
499         if len(hosts) > 0:
500             floating_ips = list()
501             remote_user = None
502             pk_file = None
503             proxy_settings = None
504             for host in hosts:
505                 vm = vm_dict.get(host)
506                 if vm:
507                     fip = vm.get_floating_ip()
508                     if fip:
509                         remote_user = vm.get_image_user()
510
511                         if fip:
512                             floating_ips.append(fip.ip)
513                         else:
514                             raise Exception(
515                                 'Could not find floating IP for VM - ' +
516                                 vm.name)
517
518                         pk_file = vm.keypair_settings.private_filepath
519                         proxy_settings = vm.get_os_creds().proxy_settings
520                 else:
521                     logger.error('Could not locate VM with name - ' + host)
522
523             return remote_user, floating_ips, pk_file, proxy_settings
524     return None
525
526
527 def __get_variables(var_config, os_creds_dict, vm_dict, image_dict,
528                     flavor_dict, networks_dict, routers_dict):
529     """
530     Returns a dictionary of substitution variables to be used for Ansible
531     templates
532     :param var_config: the variable configuration settings
533     :param os_creds_dict: dict where the key is the name and value is OSCreds
534     :param vm_dict: the dictionary of newly instantiated VMs where the name is
535                     the key
536     :param image_dict: the dictionary of newly instantiated images where the
537                        name is the key
538     :param flavor_dict: the dictionary of newly instantiated flavors where the
539                         name is the key
540     :param networks_dict: the dictionary of newly instantiated networks where
541                           the name is the key
542     :param routers_dict: the dictionary of newly instantiated routers where
543                           the name is the key
544     :return: dictionary or None
545     """
546     if var_config and vm_dict and len(vm_dict) > 0:
547         variables = dict()
548         for key, value in var_config.items():
549             value = __get_variable_value(
550                 value, os_creds_dict, vm_dict, image_dict, flavor_dict,
551                 networks_dict, routers_dict)
552             if key and value:
553                 variables[key] = value
554                 logger.info(
555                     "Set Jinga2 variable with key [%s] the value [%s]",
556                     key, value)
557             else:
558                 raise Exception(
559                     'Key - [' + str(key) + '] or Value [' + str(value)
560                     + '] must not be None')
561         return variables
562     return None
563
564
565 def __get_variable_value(var_config_values, os_creds_dict, vm_dict, image_dict,
566                          flavor_dict, networks_dict, routers_dict):
567     """
568     Returns the associated variable value for use by Ansible for substitution
569     purposes
570     :param var_config_values: the configuration dictionary
571     :param os_creds_dict: dict where the key is the name and value is OSCreds
572     :param vm_dict: the dictionary of newly instantiated VMs where the name is
573                     the key
574     :param image_dict: the dictionary of newly instantiated images where the
575                        name is the key
576     :param flavor_dict: the dictionary of newly instantiated flavors where the
577                         name is the key
578     :param networks_dict: the dictionary of newly instantiated networks where
579                           the name is the key
580     :param routers_dict: the dictionary of newly instantiated routers where
581                           the name is the key
582     :return:
583     """
584     if var_config_values['type'] == 'string':
585         return __get_string_variable_value(var_config_values)
586     if var_config_values['type'] == 'vm-attr':
587         return __get_vm_attr_variable_value(var_config_values, vm_dict)
588     if var_config_values['type'] == 'os_creds':
589         return __get_os_creds_variable_value(var_config_values, os_creds_dict)
590     if var_config_values['type'] == 'os_creds_dict':
591         return str(__get_os_creds_dict(var_config_values, os_creds_dict))
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_dict)
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     if var_config_values['type'] == 'vm-yaml':
606         return __create_yaml(var_config_values, vm_dict)
607     return None
608
609
610 def __get_string_variable_value(var_config_values):
611     """
612     Returns the associated string value
613     :param var_config_values: the configuration dictionary
614     :return: the value contained in the dictionary with the key 'value'
615     """
616     return var_config_values['value']
617
618
619 def __get_vm_attr_variable_value(var_config_values, vm_dict):
620     """
621     Returns the associated value contained on a VM instance
622     :param var_config_values: the configuration dictionary
623     :param vm_dict: the dictionary containing all VMs where the key is the VM's
624                     name
625     :return: the value
626     """
627     vm = vm_dict.get(var_config_values['vm_name'])
628     if vm:
629         if var_config_values['value'] == 'floating_ip':
630             return vm.get_floating_ip().ip
631         if var_config_values['value'] == 'image_user':
632             return vm.get_image_user()
633
634
635 def __get_os_creds_variable_value(var_config_values, os_creds_dict):
636     """
637     Returns the associated OS credentials value
638     :param var_config_values: the configuration dictionary
639     :param os_creds_dict: dict of OpenStack credentials where the key is the
640                           name
641     :return: the value
642     """
643     if 'creds_name' in var_config_values:
644         os_creds = os_creds_dict.get[var_config_values['creds_name']]
645     else:
646         os_creds = os_creds_dict.get('admin-creds')
647
648     if os_creds:
649         if var_config_values['value'] == 'username':
650             logger.info("Returning OS username")
651             return os_creds.username
652         elif var_config_values['value'] == 'password':
653             logger.info("Returning OS password")
654             return os_creds.password
655         elif var_config_values['value'] == 'auth_url':
656             logger.info("Returning OS auth_url")
657             return os_creds.auth_url
658         elif var_config_values['value'] == 'project_name':
659             logger.info("Returning OS project_name")
660             return os_creds.project_name
661
662
663 def __get_os_creds_dict(var_config_values, os_creds_dict):
664     """
665     Returns the associated OS credentials as a dict
666     :param var_config_values: the configuration dictionary
667     :param os_creds_dict: dict of creds where the key is the username
668     :return: the value dict
669     """
670     if 'creds_name' in var_config_values:
671         os_creds = os_creds_dict.get[var_config_values['creds_name']]
672     else:
673         os_creds = os_creds_dict.get('admin-creds')
674     if os_creds:
675         return os_creds.to_dict()
676
677
678 def __get_network_variable_value(var_config_values, networks_dict):
679     """
680     Returns the associated network value
681     :param var_config_values: the configuration dictionary
682     :param networks_dict: the dictionary containing all networks where the key
683                           is the network name
684     :return: the value
685     """
686     net_name = var_config_values.get('network_name')
687
688     if net_name and networks_dict.get(net_name):
689         network_creator = networks_dict[net_name]
690
691         if 'subnet_name' in var_config_values:
692             subnet_name = var_config_values.get('subnet_name')
693             if subnet_name:
694                 for subnet in network_creator.get_network().subnets:
695                     if subnet_name == subnet.name:
696                         if 'value' in var_config_values:
697                             if 'gateway_ip' == var_config_values['value']:
698                                 return subnet.gateway_ip
699                             if 'ip_range' == var_config_values['value']:
700                                 return subnet.start + ' ' + subnet.end
701                             if 'ip_range_start' == var_config_values['value']:
702                                 return subnet.start
703                             if 'ip_range_end' == var_config_values['value']:
704                                 return subnet.end
705                             if 'cidr' == var_config_values['value']:
706                                 return subnet.cidr
707                             if 'cidr_ip' == var_config_values['value']:
708                                 cidr_split = subnet.cidr.split('/')
709                                 return cidr_split[0]
710                             if 'netmask' == var_config_values['value']:
711                                 cidr_split = subnet.cidr.split('/')
712                                 cidr_bits = 32 - int(cidr_split[1])
713                                 netmask = socket.inet_ntoa(
714                                     struct.pack(
715                                         '!I', (1 << 32) - (1 << cidr_bits)))
716                                 return netmask
717                             if 'broadcast_ip' == var_config_values['value']:
718                                 end_split = subnet.end.split('.')
719                                 broadcast_ip = (
720                                     end_split[0] + '.' + end_split[1] + '.'
721                                     + end_split[2] + '.255')
722                                 return broadcast_ip
723
724
725 def __get_router_variable_value(var_config_values, routers_dict,
726                                 os_creds_dict):
727     """
728     Returns the associated network value
729     :param var_config_values: the configuration dictionary
730     :param routers_dict: the dictionary containing all networks where the key
731                           is the network name
732     :param os_creds_dict: dict of OpenStack credentials where the key is the
733                           name
734     :return: the value
735     """
736     if 'creds_name' in var_config_values:
737         os_creds = os_creds_dict.get[var_config_values['creds_name']]
738     else:
739         os_creds = os_creds_dict.get('admin-creds')
740
741     router_name = var_config_values.get('router_name')
742     router_creator = routers_dict[router_name]
743
744     if router_creator:
745         if 'external_fixed_ip' == var_config_values.get('attr'):
746             session = keystone_utils.keystone_session(os_creds)
747             neutron = neutron_utils.neutron_client(os_creds, session)
748             try:
749                 ext_nets = neutron_utils.get_external_networks(neutron)
750
751                 subnet_name = var_config_values.get('subnet_name')
752
753                 for ext_net in ext_nets:
754                     for subnet in ext_net.subnets:
755                         if subnet_name == subnet.name:
756                             router = router_creator.get_router()
757                             for fixed_ips in router.external_fixed_ips:
758                                 if subnet.id == fixed_ips['subnet_id']:
759                                     return fixed_ips['ip_address']
760             finally:
761                 keystone_utils.close_session(session)
762
763
764 def __get_vm_port_variable_value(var_config_values, vm_dict):
765     """
766     Returns the associated OS credentials value
767     :param var_config_values: the configuration dictionary
768     :param vm_dict: the dictionary containing all VMs where the key is the VM's
769                     name
770     :return: the value
771     """
772     port_name = var_config_values.get('port_name')
773     vm_name = var_config_values.get('vm_name')
774
775     if port_name and vm_name:
776         vm = vm_dict.get(vm_name)
777         if vm:
778             for vm_port in vm.get_vm_inst().ports:
779                 if vm_port.name == port_name:
780                     port_value_id = var_config_values.get('port_value')
781                     if port_value_id:
782                         if port_value_id == 'mac_address':
783                             return vm_port.mac_address
784                         if port_value_id == 'ip_address':
785                             return vm_port.ips[0]['ip_address']
786
787
788 def __get_vm_fip_variable_value(var_config_values, vm_dict):
789     """
790     Returns the floating IP value if found
791     :param var_config_values: the configuration dictionary
792     :param vm_dict: the dictionary containing all VMs where the key is the VM's
793                     name
794     :return: the floating IP string value or None
795     """
796     fip_name = var_config_values.get('fip_name')
797     vm_name = var_config_values.get('vm_name')
798
799     if vm_name:
800         vm = vm_dict.get(vm_name)
801         if vm:
802             fip = vm.get_floating_ip(fip_name)
803             if fip:
804                 return fip.ip
805
806
807 def __get_image_variable_value(var_config_values, image_dict):
808     """
809     Returns the associated image value
810     :param var_config_values: the configuration dictionary
811     :param image_dict: the dictionary containing all images where the key is
812                        the name
813     :return: the value
814     """
815     if image_dict:
816         if var_config_values.get('image_name'):
817             image_creator = image_dict.get(var_config_values['image_name'])
818             if image_creator:
819                 if (var_config_values.get('value')
820                         and var_config_values['value'] == 'id'):
821                     return image_creator.get_image().id
822                 if (var_config_values.get('value')
823                         and var_config_values['value'] == 'user'):
824                     return image_creator.image_settings.image_user
825
826
827 def __get_flavor_variable_value(var_config_values, flavor_dict):
828     """
829     Returns the associated flavor value
830     :param var_config_values: the configuration dictionary
831     :param flavor_dict: the dictionary containing all flavor creators where the
832                         key is the name
833     :return: the value or None
834     """
835     if flavor_dict:
836         if var_config_values.get('flavor_name'):
837             flavor_creator = flavor_dict.get(var_config_values['flavor_name'])
838             if flavor_creator:
839                 if (var_config_values.get('value')
840                         and var_config_values['value'] == 'id'):
841                     return flavor_creator.get_flavor().id
842
843
844 def __create_yaml(var_config_values, vm_dict):
845     """
846     Creates a yaml file containing an OpenStack pod's credentials with a list
847     of server IDs that can be used for obtaining SNAPS-OO instances for
848     manipulation such as rebooting
849     :param var_config_values: the configuration dictionary
850     :param vm_dict: the dictionary containing all vm creators where the
851                     key is the name
852     :return: the name of the generated file
853     """
854     out_dict = dict()
855     out_dict['vms'] = list()
856     req_vm_names = var_config_values.get('vms')
857
858     for name, vm_creator in vm_dict.items():
859         vm_inst = vm_creator.get_vm_inst()
860         if vm_inst and vm_inst.name in req_vm_names:
861             out_dict['vms'].append({
862                 'name': str(vm_inst.name),
863                 'id': str(vm_inst.id),
864                 'os_creds': vm_creator.get_os_creds().to_dict()
865             })
866
867     out_file = file_utils.persist_dict_to_yaml(
868         out_dict, var_config_values.get('file_name'))
869
870     if out_file:
871         return out_file.name
872
873
874 def __cleanup(creators, clean_image=False):
875     """
876     Cleans up environment
877     :param creators: the list of creators by type
878     :param clean_image: when true
879     :return:
880     """
881     for creator_dict in reversed(creators):
882         for key, creator in creator_dict.items():
883             if ((isinstance(creator, OpenStackImage) and clean_image)
884                     or not isinstance(creator, OpenStackImage)):
885                 creator.clean()