#!/usr/bin/python
#
-# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
# and others. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# This script is responsible for deploying virtual environments
import argparse
import logging
-import os
import re
+import time
+from jinja2 import Environment, FileSystemLoader
+import os
+import yaml
+
from snaps import file_utils
from snaps.openstack.create_flavor import FlavorSettings, OpenStackFlavor
-from snaps.openstack.create_image import ImageSettings
+from snaps.openstack.create_image import ImageSettings, OpenStackImage
from snaps.openstack.create_instance import VmInstanceSettings
-from snaps.openstack.create_network import PortSettings, NetworkSettings
-from snaps.openstack.create_router import RouterSettings
-from snaps.openstack.create_keypairs import KeypairSettings
+from snaps.openstack.create_keypairs import KeypairSettings, OpenStackKeypair
+from snaps.openstack.create_network import (
+ PortSettings, NetworkSettings, OpenStackNetwork)
+from snaps.openstack.create_project import OpenStackProject, ProjectSettings
+from snaps.openstack.create_qos import QoSSettings, OpenStackQoS
+from snaps.openstack.create_router import RouterSettings, OpenStackRouter
+from snaps.openstack.create_security_group import (
+ OpenStackSecurityGroup, SecurityGroupSettings)
+from snaps.openstack.create_user import OpenStackUser, UserSettings
+from snaps.openstack.create_volume import OpenStackVolume, VolumeSettings
+from snaps.openstack.create_volume_type import (
+ OpenStackVolumeType, VolumeTypeSettings)
from snaps.openstack.os_credentials import OSCreds, ProxySettings
from snaps.openstack.utils import deploy_utils
from snaps.provisioning import ansible_utils
__author__ = 'spisarski'
-logger = logging.getLogger('deploy_venv')
+logger = logging.getLogger('snaps_launcher')
ARG_NOT_SET = "argument not set"
+DEFAULT_CREDS_KEY = 'admin'
+
+
+def __get_creds_dict(os_conn_config):
+ """
+ Returns a dict of OSCreds where the key is the creds name.
+ For backwards compatibility, credentials not contained in a list (only
+ one) will be returned with the key of None
+ :param os_conn_config: the credential configuration
+ :return: a dict of OSCreds objects
+ """
+ if 'connection' in os_conn_config:
+ return {DEFAULT_CREDS_KEY: __get_os_credentials(os_conn_config)}
+ elif 'connections' in os_conn_config:
+ out = dict()
+ for os_conn_dict in os_conn_config['connections']:
+ config = os_conn_dict.get('connection')
+ if not config:
+ raise Exception('Invalid connection format')
+
+ name = config.get('name')
+ if not name:
+ raise Exception('Connection config requires a name field')
+
+ out[name] = __get_os_credentials(os_conn_dict)
+ return out
+
+
+def __get_creds(os_creds_dict, os_user_dict, inst_config):
+ """
+ Returns the appropriate credentials
+ :param os_creds_dict: a dictionary of OSCreds objects where the name is the
+ key
+ :param os_user_dict: a dictionary of OpenStackUser objects where the name
+ is the key
+ :param inst_config:
+ :return: an OSCreds instance or None
+ """
+ os_creds = os_creds_dict.get(DEFAULT_CREDS_KEY)
+ if 'os_user' in inst_config:
+ os_user_conf = inst_config['os_user']
+ if 'name' in os_user_conf:
+ user_creator = os_user_dict.get(os_user_conf['name'])
+ if user_creator:
+ return user_creator.get_os_creds(
+ project_name=os_user_conf.get('project_name'))
+ elif 'os_creds_name' in inst_config:
+ if 'os_creds_name' in inst_config:
+ os_creds = os_creds_dict[inst_config['os_creds_name']]
+ return os_creds
def __get_os_credentials(os_conn_config):
"""
- Returns an object containing all of the information required to access OpenStack APIs
+ Returns an object containing all of the information required to access
+ OpenStack APIs
:param os_conn_config: The configuration holding the credentials
:return: an OSCreds instance
"""
+ config = os_conn_config.get('connection')
+ if not config:
+ raise Exception('Invalid connection configuration')
+
proxy_settings = None
- http_proxy = os_conn_config.get('http_proxy')
+ http_proxy = config.get('http_proxy')
if http_proxy:
tokens = re.split(':', http_proxy)
- ssh_proxy_cmd = os_conn_config.get('ssh_proxy_cmd')
- proxy_settings = ProxySettings(tokens[0], tokens[1], ssh_proxy_cmd)
+ ssh_proxy_cmd = config.get('ssh_proxy_cmd')
+ proxy_settings = ProxySettings(host=tokens[0], port=tokens[1],
+ ssh_proxy_cmd=ssh_proxy_cmd)
+ else:
+ if 'proxy_settings' in config:
+ host = config['proxy_settings'].get('host')
+ port = config['proxy_settings'].get('port')
+ if host and host != 'None' and port and port != 'None':
+ proxy_settings = ProxySettings(**config['proxy_settings'])
+
+ if proxy_settings:
+ config['proxy_settings'] = proxy_settings
+ else:
+ if config.get('proxy_settings'):
+ del config['proxy_settings']
- return OSCreds(username=os_conn_config.get('username'),
- password=os_conn_config.get('password'),
- auth_url=os_conn_config.get('auth_url'),
- project_name=os_conn_config.get('project_name'),
- proxy_settings=proxy_settings)
+ return OSCreds(**config)
def __parse_ports_config(config):
"""
Parses the "ports" configuration
:param config: The dictionary to parse
- :param os_creds: The OpenStack credentials object
:return: a list of PortConfig objects
"""
out = list()
for port_config in config:
- out.append(PortSettings(config=port_config.get('port')))
+ out.append(PortSettings(**port_config.get('port')))
return out
-def __create_flavors(os_conn_config, flavors_config, cleanup=False):
- """
- Returns a dictionary of flavors where the key is the image name and the value is the image object
- :param os_conn_config: The OpenStack connection credentials
- :param flavors_config: The list of image configurations
- :param cleanup: Denotes whether or not this is being called for cleanup or not
- :return: dictionary
- """
- flavors = {}
-
- if flavors_config:
- try:
- for flavor_config_dict in flavors_config:
- flavor_config = flavor_config_dict.get('flavor')
- if flavor_config and flavor_config.get('name'):
- flavor_creator = OpenStackFlavor(__get_os_credentials(os_conn_config),
- FlavorSettings(flavor_config))
- flavor_creator.create(cleanup=cleanup)
- flavors[flavor_config['name']] = flavor_creator
- except Exception as e:
- for key, flavor_creator in flavors.iteritems():
- flavor_creator.clean()
- raise e
- logger.info('Created configured flavors')
-
- return flavors
-
-
-def __create_images(os_conn_config, images_config, cleanup=False):
- """
- Returns a dictionary of images where the key is the image name and the value is the image object
- :param os_conn_config: The OpenStack connection credentials
- :param images_config: The list of image configurations
- :param cleanup: Denotes whether or not this is being called for cleanup or not
- :return: dictionary
- """
- images = {}
-
- if images_config:
- try:
- for image_config_dict in images_config:
- image_config = image_config_dict.get('image')
- if image_config and image_config.get('name'):
- images[image_config['name']] = deploy_utils.create_image(__get_os_credentials(os_conn_config),
- ImageSettings(image_config), cleanup)
- except Exception as e:
- for key, image_creator in images.iteritems():
- image_creator.clean()
- raise e
- logger.info('Created configured images')
-
- return images
-
-
-def __create_networks(os_conn_config, network_confs, cleanup=False):
- """
- Returns a dictionary of networks where the key is the network name and the value is the network object
- :param os_conn_config: The OpenStack connection credentials
- :param network_confs: The list of network configurations
- :param cleanup: Denotes whether or not this is being called for cleanup or not
- :return: dictionary
- """
- network_dict = {}
-
- if network_confs:
- try:
- for network_conf in network_confs:
- net_name = network_conf['network']['name']
- os_creds = __get_os_credentials(os_conn_config)
- network_dict[net_name] = deploy_utils.create_network(
- os_creds, NetworkSettings(config=network_conf['network']), cleanup)
- except Exception as e:
- for key, net_creator in network_dict.iteritems():
- net_creator.clean()
- raise e
-
- logger.info('Created configured networks')
-
- return network_dict
-
-
-def __create_routers(os_conn_config, router_confs, cleanup=False):
+def __create_instances(os_creds_dict, creator_class, config_class, config,
+ config_key, cleanup=False, os_users_dict=None):
"""
- Returns a dictionary of networks where the key is the network name and the value is the network object
- :param os_conn_config: The OpenStack connection credentials
- :param router_confs: The list of router configurations
- :param cleanup: Denotes whether or not this is being called for cleanup or not
+ Returns a dictionary of SNAPS creator objects where the key is the name
+ :param os_creds_dict: Dictionary of OSCreds objects where the key is the
+ name
+ :param config: The list of configurations for the same type
+ :param config_key: The list of configurations for the same type
+ :param cleanup: Denotes whether or not this is being called for cleanup
:return: dictionary
"""
- router_dict = {}
- os_creds = __get_os_credentials(os_conn_config)
+ out = {}
- if router_confs:
- try:
- for router_conf in router_confs:
- router_name = router_conf['router']['name']
- router_dict[router_name] = deploy_utils.create_router(
- os_creds, RouterSettings(config=router_conf['router']), cleanup)
- except Exception as e:
- for key, router_creator in router_dict.iteritems():
- router_creator.clean()
- raise e
-
- logger.info('Created configured networks')
-
- return router_dict
-
-
-def __create_keypairs(os_conn_config, keypair_confs, cleanup=False):
- """
- Returns a dictionary of keypairs where the key is the keypair name and the value is the keypair object
- :param os_conn_config: The OpenStack connection credentials
- :param keypair_confs: The list of keypair configurations
- :param cleanup: Denotes whether or not this is being called for cleanup or not
- :return: dictionary
- """
- keypairs_dict = {}
- if keypair_confs:
+ if config:
try:
- for keypair_dict in keypair_confs:
- keypair_config = keypair_dict['keypair']
- kp_settings = KeypairSettings(keypair_config)
- keypairs_dict[keypair_config['name']] = deploy_utils.create_keypair(
- __get_os_credentials(os_conn_config), kp_settings, cleanup)
+ for config_dict in config:
+ inst_config = config_dict.get(config_key)
+ if inst_config:
+ creator = creator_class(
+ __get_creds(os_creds_dict, os_users_dict, inst_config),
+ config_class(**inst_config))
+
+ if cleanup:
+ creator.initialize()
+ else:
+ creator.create()
+ out[inst_config['name']] = creator
+ logger.info('Created configured %s', config_key)
except Exception as e:
- for key, keypair_creator in keypairs_dict.iteritems():
- keypair_creator.clean()
- raise e
+ logger.error('Unexpected error instantiating creator [%s] '
+ 'with exception %s', creator_class, e)
- logger.info('Created configured keypairs')
-
- return keypairs_dict
+ return out
-def __create_instances(os_conn_config, instances_config, image_dict, keypairs_dict, cleanup=False):
+def __create_vm_instances(os_creds_dict, os_users_dict, instances_config,
+ image_dict, keypairs_dict, cleanup=False):
"""
- Returns a dictionary of instances where the key is the instance name and the value is the VM object
- :param os_conn_config: The OpenStack connection credentials
+ Returns a dictionary of OpenStackVmInstance objects where the key is the
+ instance name
+ :param os_creds_dict: Dictionary of OSCreds objects where the key is the
+ name
+ :param os_users_dict: Dictionary of OpenStackUser objects where the key is
+ the username
:param instances_config: The list of VM instance configurations
- :param image_dict: A dictionary of images that will probably be used to instantiate the VM instance
- :param keypairs_dict: A dictionary of keypairs that will probably be used to instantiate the VM instance
- :param cleanup: Denotes whether or not this is being called for cleanup or not
+ :param image_dict: A dictionary of images that will probably be used to
+ instantiate the VM instance
+ :param keypairs_dict: A dictionary of keypairs that will probably be used
+ to instantiate the VM instance
+ :param cleanup: Denotes whether or not this is being called for cleanup
:return: dictionary
"""
- os_creds = __get_os_credentials(os_conn_config)
-
vm_dict = {}
if instances_config:
if image_dict:
image_creator = image_dict.get(conf.get('imageName'))
if image_creator:
- instance_settings = VmInstanceSettings(config=instance_config['instance'])
- kp_name = conf.get('keypair_name')
- vm_dict[conf['name']] = deploy_utils.create_vm_instance(
- os_creds, instance_settings, image_creator.image_settings,
- keypair_creator=keypairs_dict[kp_name], cleanup=cleanup)
+ instance_settings = VmInstanceSettings(
+ **instance_config['instance'])
+ kp_creator = keypairs_dict.get(
+ conf.get('keypair_name'))
+ vm_dict[conf[
+ 'name']] = deploy_utils.create_vm_instance(
+ __get_creds(
+ os_creds_dict, os_users_dict, conf),
+ instance_settings,
+ image_creator.image_settings,
+ keypair_creator=kp_creator,
+ init_only=cleanup)
else:
- raise Exception('Image creator instance not found. Cannot instantiate')
+ raise Exception('Image creator instance not found.'
+ ' Cannot instantiate')
else:
- raise Exception('Image dictionary is None. Cannot instantiate')
+ raise Exception('Image dictionary is None. Cannot '
+ 'instantiate')
else:
- raise Exception('Instance configuration is None. Cannot instantiate')
+ raise Exception('Instance configuration is None. Cannot '
+ 'instantiate')
+ logger.info('Created configured instances')
except Exception as e:
- logger.error('Unexpected error creating instances. Attempting to cleanup environment - ' + e.message)
- for key, inst_creator in vm_dict.iteritems():
- inst_creator.clean()
- raise e
-
- logger.info('Created configured instances')
-
+ logger.error('Unexpected error creating VM instances - %s', e)
return vm_dict
-def __apply_ansible_playbooks(ansible_configs, os_conn_config, vm_dict, image_dict, flavor_dict, env_file):
+def __apply_ansible_playbooks(ansible_configs, os_creds_dict, vm_dict,
+ image_dict, flavor_dict, env_file):
"""
Applies ansible playbooks to running VMs with floating IPs
:param ansible_configs: a list of Ansible configurations
- :param os_conn_config: the OpenStack connection configuration used to create an OSCreds instance
- :param vm_dict: the dictionary of newly instantiated VMs where the name is the key
- :param image_dict: the dictionary of newly instantiated images where the name is the key
- :param flavor_dict: the dictionary of newly instantiated flavors where the name is the key
- :param env_file: the path of the environment for setting the CWD so playbook location is relative to the deployment
- file
+ :param os_creds_dict: Dictionary of OSCreds objects where the key is the
+ name
+ :param vm_dict: the dictionary of newly instantiated VMs where the name is
+ the key
+ :param image_dict: the dictionary of newly instantiated images where the
+ name is the key
+ :param flavor_dict: the dictionary of newly instantiated flavors where the
+ name is the key
+ :param env_file: the path of the environment for setting the CWD so
+ playbook location is relative to the deployment file
:return: t/f - true if successful
"""
logger.info("Applying Ansible Playbooks")
if ansible_configs:
# Ensure all hosts are accepting SSH session requests
- for vm_inst in vm_dict.values():
+ for vm_inst in list(vm_dict.values()):
if not vm_inst.vm_ssh_active(block=True):
- logger.warn("Timeout waiting for instance to respond to SSH requests")
+ logger.warning(
+ "Timeout waiting for instance to respond to SSH requests")
return False
- # Set CWD so the deployment file's playbook location can leverage relative paths
+ # Set CWD so the deployment file's playbook location can leverage
+ # relative paths
orig_cwd = os.getcwd()
env_dir = os.path.dirname(env_file)
os.chdir(env_dir)
# Apply playbooks
for ansible_config in ansible_configs:
- os_creds = __get_os_credentials(os_conn_config)
- __apply_ansible_playbook(ansible_config, os_creds, vm_dict, image_dict, flavor_dict)
+ if 'pre_sleep_time' in ansible_config:
+ try:
+ sleep_time = int(ansible_config['pre_sleep_time'])
+ logger.info('Waiting %s seconds to apply playbooks',
+ sleep_time)
+ time.sleep(sleep_time)
+ except:
+ pass
+
+ os_creds = os_creds_dict.get(None, 'admin')
+ __apply_ansible_playbook(ansible_config, os_creds, vm_dict,
+ image_dict, flavor_dict)
# Return to original directory
os.chdir(orig_cwd)
return True
-def __apply_ansible_playbook(ansible_config, os_creds, vm_dict, image_dict, flavor_dict):
+def __apply_ansible_playbook(ansible_config, os_creds, vm_dict, image_dict,
+ flavor_dict):
"""
Applies an Ansible configuration setting
:param ansible_config: the configuration settings
:param os_creds: the OpenStack credentials object
- :param vm_dict: the dictionary of newly instantiated VMs where the name is the key
- :param image_dict: the dictionary of newly instantiated images where the name is the key
- :param flavor_dict: the dictionary of newly instantiated flavors where the name is the key
+ :param vm_dict: the dictionary of newly instantiated VMs where the name is
+ the key
+ :param image_dict: the dictionary of newly instantiated images where the
+ name is the key
+ :param flavor_dict: the dictionary of newly instantiated flavors where the
+ name is the key
"""
if ansible_config:
- remote_user, floating_ips, private_key_filepath, proxy_settings = __get_connection_info(ansible_config, vm_dict)
+ (remote_user, floating_ips, private_key_filepath,
+ proxy_settings) = __get_connection_info(
+ ansible_config, vm_dict)
if floating_ips:
retval = ansible_utils.apply_playbook(
- ansible_config['playbook_location'], floating_ips, remote_user, private_key_filepath,
- variables=__get_variables(ansible_config.get('variables'), os_creds, vm_dict, image_dict, flavor_dict),
+ ansible_config['playbook_location'], floating_ips, remote_user,
+ private_key_filepath,
+ variables=__get_variables(ansible_config.get('variables'),
+ os_creds, vm_dict, image_dict,
+ flavor_dict),
proxy_setting=proxy_settings)
if retval != 0:
# Not a fatal type of event
- logger.warn('Unable to apply playbook found at location - ' + ansible_config('playbook_location'))
+ logger.warning(
+ 'Unable to apply playbook found at location - %s',
+ ansible_config.get('playbook_location'))
def __get_connection_info(ansible_config, vm_dict):
(remote_user, [floating_ips], private_key_filepath, proxy_settings)
:param ansible_config: the configuration settings
:param vm_dict: the dictionary of VMs where the VM name is the key
- :return: tuple where the first element is the user and the second is a list of floating IPs and the third is the
- private key file location and the fourth is an instance of the snaps.ProxySettings class
- (note: in order to work, each of the hosts need to have the same sudo_user and private key file location values)
+ :return: tuple where the first element is the user and the second is a list
+ of floating IPs and the third is the
+ private key file location and the fourth is an instance of the
+ snaps.ProxySettings class
+ (note: in order to work, each of the hosts need to have the same sudo_user
+ and private key file location values)
"""
if ansible_config.get('hosts'):
hosts = ansible_config['hosts']
if len(hosts) > 0:
floating_ips = list()
remote_user = None
- private_key_filepath = None
+ pk_file = None
proxy_settings = None
for host in hosts:
vm = vm_dict.get(host)
if fip:
floating_ips.append(fip.ip)
else:
- raise Exception('Could not find floating IP for VM - ' + vm.name)
+ raise Exception(
+ 'Could not find floating IP for VM - ' +
+ vm.name)
- private_key_filepath = vm.keypair_settings.private_filepath
+ pk_file = vm.keypair_settings.private_filepath
proxy_settings = vm.get_os_creds().proxy_settings
else:
logger.error('Could not locate VM with name - ' + host)
- return remote_user, floating_ips, private_key_filepath, proxy_settings
+ return remote_user, floating_ips, pk_file, proxy_settings
return None
def __get_variables(var_config, os_creds, vm_dict, image_dict, flavor_dict):
"""
- Returns a dictionary of substitution variables to be used for Ansible templates
+ Returns a dictionary of substitution variables to be used for Ansible
+ templates
:param var_config: the variable configuration settings
:param os_creds: the OpenStack credentials object
- :param vm_dict: the dictionary of newly instantiated VMs where the name is the key
- :param image_dict: the dictionary of newly instantiated images where the name is the key
- :param flavor_dict: the dictionary of newly instantiated flavors where the name is the key
+ :param vm_dict: the dictionary of newly instantiated VMs where the name is
+ the key
+ :param image_dict: the dictionary of newly instantiated images where the
+ name is the key
+ :param flavor_dict: the dictionary of newly instantiated flavors where the
+ name is the key
:return: dictionary or None
"""
if var_config and vm_dict and len(vm_dict) > 0:
variables = dict()
- for key, value in var_config.iteritems():
- value = __get_variable_value(value, os_creds, vm_dict, image_dict, flavor_dict)
+ for key, value in var_config.items():
+ value = __get_variable_value(value, os_creds, vm_dict, image_dict,
+ flavor_dict)
if key and value:
variables[key] = value
- logger.info("Set Jinga2 variable with key [" + key + "] the value [" + value + ']')
+ logger.info(
+ "Set Jinga2 variable with key [%s] the value [%s]",
+ key, value)
else:
- logger.warn('Key [' + str(key) + '] or Value [' + str(value) + '] must not be None')
+ logger.warning('Key [%s] or Value [%s] must not be None',
+ str(key), str(value))
return variables
return None
-def __get_variable_value(var_config_values, os_creds, vm_dict, image_dict, flavor_dict):
+def __get_variable_value(var_config_values, os_creds, vm_dict, image_dict,
+ flavor_dict):
"""
- Returns the associated variable value for use by Ansible for substitution purposes
+ Returns the associated variable value for use by Ansible for substitution
+ purposes
:param var_config_values: the configuration dictionary
:param os_creds: the OpenStack credentials object
- :param vm_dict: the dictionary of newly instantiated VMs where the name is the key
- :param image_dict: the dictionary of newly instantiated images where the name is the key
- :param flavor_dict: the dictionary of newly instantiated flavors where the name is the key
+ :param vm_dict: the dictionary of newly instantiated VMs where the name is
+ the key
+ :param image_dict: the dictionary of newly instantiated images where the
+ name is the key
+ :param flavor_dict: the dictionary of newly instantiated flavors where the
+ name is the key
:return:
"""
if var_config_values['type'] == 'string':
return __get_os_creds_variable_value(var_config_values, os_creds)
if var_config_values['type'] == 'port':
return __get_vm_port_variable_value(var_config_values, vm_dict)
+ if var_config_values['type'] == 'floating_ip':
+ return __get_vm_fip_variable_value(var_config_values, vm_dict)
if var_config_values['type'] == 'image':
return __get_image_variable_value(var_config_values, image_dict)
if var_config_values['type'] == 'flavor':
"""
Returns the associated value contained on a VM instance
:param var_config_values: the configuration dictionary
- :param vm_dict: the dictionary containing all VMs where the key is the VM's name
+ :param vm_dict: the dictionary containing all VMs where the key is the VM's
+ name
:return: the value
"""
vm = vm_dict.get(var_config_values['vm_name'])
"""
Returns the associated OS credentials value
:param var_config_values: the configuration dictionary
- :param vm_dict: the dictionary containing all VMs where the key is the VM's name
+ :param vm_dict: the dictionary containing all VMs where the key is the VM's
+ name
:return: the value
"""
port_name = var_config_values.get('port_name')
return vm.get_port_ip(port_name)
+def __get_vm_fip_variable_value(var_config_values, vm_dict):
+ """
+ Returns the floating IP value if found
+ :param var_config_values: the configuration dictionary
+ :param vm_dict: the dictionary containing all VMs where the key is the VM's
+ name
+ :return: the floating IP string value or None
+ """
+ fip_name = var_config_values.get('fip_name')
+ vm_name = var_config_values.get('vm_name')
+
+ if vm_name:
+ vm = vm_dict.get(vm_name)
+ if vm:
+ fip = vm.get_floating_ip(fip_name)
+ if fip:
+ return fip.ip
+
+
def __get_image_variable_value(var_config_values, image_dict):
"""
Returns the associated image value
:param var_config_values: the configuration dictionary
- :param image_dict: the dictionary containing all images where the key is the name
+ :param image_dict: the dictionary containing all images where the key is
+ the name
:return: the value
"""
logger.info("Retrieving image values")
if var_config_values.get('image_name'):
image_creator = image_dict.get(var_config_values['image_name'])
if image_creator:
- if var_config_values.get('value') and var_config_values['value'] == 'id':
+ if var_config_values.get('value') and \
+ var_config_values['value'] == 'id':
return image_creator.get_image().id
- if var_config_values.get('value') and var_config_values['value'] == 'user':
+ if var_config_values.get('value') and \
+ var_config_values['value'] == 'user':
return image_creator.image_settings.image_user
logger.info("Returning none")
"""
Returns the associated flavor value
:param var_config_values: the configuration dictionary
- :param flavor_dict: the dictionary containing all flavor creators where the key is the name
+ :param flavor_dict: the dictionary containing all flavor creators where the
+ key is the name
:return: the value or None
"""
logger.info("Retrieving flavor values")
if var_config_values.get('flavor_name'):
flavor_creator = flavor_dict.get(var_config_values['flavor_name'])
if flavor_creator:
- if var_config_values.get('value') and var_config_values['value'] == 'id':
+ if var_config_values.get('value') and \
+ var_config_values['value'] == 'id':
return flavor_creator.get_flavor().id
- logger.info("Returning none")
- return None
-
def main(arguments):
"""
- Will need to set environment variable ANSIBLE_HOST_KEY_CHECKING=False or ...
- Create a file located in /etc/ansible/ansible/cfg or ~/.ansible.cfg containing the following content:
+ Will need to set environment variable ANSIBLE_HOST_KEY_CHECKING=False or
+ Create a file located in /etc/ansible/ansible/cfg or ~/.ansible.cfg
+ containing the following content:
[defaults]
host_key_checking = False
logging.basicConfig(level=log_level)
logger.info('Starting to Deploy')
- config = file_utils.read_yaml(arguments.environment)
- logger.info('Read configuration file - ' + arguments.environment)
+
+ # Apply env_file/substitution file to template
+ env = Environment(loader=FileSystemLoader(
+ searchpath=os.path.dirname(arguments.tmplt_file)))
+ template = env.get_template(os.path.basename(arguments.tmplt_file))
+
+ env_dict = dict()
+ if arguments.env_file:
+ env_dict = file_utils.read_yaml(arguments.env_file)
+ output = template.render(**env_dict)
+
+ config = yaml.load(output)
if config:
os_config = config.get('openstack')
- image_dict = {}
- network_dict = {}
- router_dict = {}
- keypairs_dict = {}
- vm_dict = {}
+ creators = list()
+ vm_dict = dict()
+ images_dict = dict()
+ flavors_dict = dict()
+ os_creds_dict = dict()
+ clean = arguments.clean is not ARG_NOT_SET
if os_config:
+ os_creds_dict = __get_creds_dict(os_config)
+
try:
- os_conn_config = os_config.get('connection')
+ # Create projects
+ projects_dict = __create_instances(
+ os_creds_dict, OpenStackProject, ProjectSettings,
+ os_config.get('projects'), 'project', clean)
+ creators.append(projects_dict)
+
+ # Create users
+ users_dict = __create_instances(
+ os_creds_dict, OpenStackUser, UserSettings,
+ os_config.get('users'), 'user', clean)
+ creators.append(users_dict)
+
+ # Associate new users to projects
+ if not clean:
+ for project_creator in projects_dict.values():
+ users = project_creator.project_settings.users
+ for user_name in users:
+ user_creator = users_dict.get(user_name)
+ if user_creator:
+ project_creator.assoc_user(
+ user_creator.get_user())
# Create flavors
- flavor_dict = __create_flavors(os_conn_config, os_config.get('flavors'),
- arguments.clean is not ARG_NOT_SET)
+ flavors_dict = __create_instances(
+ os_creds_dict, OpenStackFlavor, FlavorSettings,
+ os_config.get('flavors'), 'flavor', clean, users_dict)
+ creators.append(flavors_dict)
+
+ # Create QoS specs
+ qos_dict = __create_instances(
+ os_creds_dict, OpenStackQoS, QoSSettings,
+ os_config.get('qos_specs'), 'qos_spec', clean, users_dict)
+ creators.append(qos_dict)
+
+ # Create volume types
+ vol_type_dict = __create_instances(
+ os_creds_dict, OpenStackVolumeType, VolumeTypeSettings,
+ os_config.get('volume_types'), 'volume_type', clean,
+ users_dict)
+ creators.append(vol_type_dict)
+
+ # Create volume types
+ vol_dict = __create_instances(
+ os_creds_dict, OpenStackVolume, VolumeSettings,
+ os_config.get('volumes'), 'volume', clean, users_dict)
+ creators.append(vol_dict)
# Create images
- image_dict = __create_images(os_conn_config, os_config.get('images'),
- arguments.clean is not ARG_NOT_SET)
+ images_dict = __create_instances(
+ os_creds_dict, OpenStackImage, ImageSettings,
+ os_config.get('images'), 'image', clean, users_dict)
+ creators.append(images_dict)
- # Create network
- network_dict = __create_networks(os_conn_config, os_config.get('networks'),
- arguments.clean is not ARG_NOT_SET)
+ # Create networks
+ creators.append(__create_instances(
+ os_creds_dict, OpenStackNetwork, NetworkSettings,
+ os_config.get('networks'), 'network', clean, users_dict))
- # Create network
- router_dict = __create_routers(os_conn_config, os_config.get('routers'),
- arguments.clean is not ARG_NOT_SET)
+ # Create routers
+ creators.append(__create_instances(
+ os_creds_dict, OpenStackRouter, RouterSettings,
+ os_config.get('routers'), 'router', clean, users_dict))
# Create keypairs
- keypairs_dict = __create_keypairs(os_conn_config, os_config.get('keypairs'),
- arguments.clean is not ARG_NOT_SET)
+ keypairs_dict = __create_instances(
+ os_creds_dict, OpenStackKeypair, KeypairSettings,
+ os_config.get('keypairs'), 'keypair', clean, users_dict)
+ creators.append(keypairs_dict)
+
+ # Create security groups
+ creators.append(__create_instances(
+ os_creds_dict, OpenStackSecurityGroup,
+ SecurityGroupSettings,
+ os_config.get('security_groups'), 'security_group', clean,
+ users_dict))
# Create instance
- vm_dict = __create_instances(os_conn_config, os_config.get('instances'), image_dict, keypairs_dict,
- arguments.clean is not ARG_NOT_SET)
- logger.info('Completed creating/retrieving all configured instances')
+ vm_dict = __create_vm_instances(
+ os_creds_dict, users_dict, os_config.get('instances'),
+ images_dict, keypairs_dict,
+ arguments.clean is not ARG_NOT_SET)
+ creators.append(vm_dict)
+ logger.info(
+ 'Completed creating/retrieving all configured instances')
except Exception as e:
- logger.error('Unexpected error deploying environment. Rolling back due to - ' + e.message)
- __cleanup(vm_dict, keypairs_dict, router_dict, network_dict, image_dict, flavor_dict, True)
- raise e
-
+ logger.error(
+ 'Unexpected error deploying environment. Rolling back due'
+ ' to - ' + str(e))
+ raise
# Must enter either block
if arguments.clean is not ARG_NOT_SET:
# Cleanup Environment
- __cleanup(vm_dict, keypairs_dict, router_dict, network_dict, image_dict, flavor_dict,
- arguments.clean_image is not ARG_NOT_SET)
+ __cleanup(creators, arguments.clean_image is not ARG_NOT_SET)
elif arguments.deploy is not ARG_NOT_SET:
logger.info('Configuring NICs where required')
- for vm in vm_dict.itervalues():
+ for vm in vm_dict.values():
vm.config_nics()
logger.info('Completed NIC configuration')
# Provision VMs
ansible_config = config.get('ansible')
if ansible_config and vm_dict:
- if not __apply_ansible_playbooks(ansible_config, os_conn_config, vm_dict, image_dict, flavor_dict,
- arguments.environment):
+ if not __apply_ansible_playbooks(ansible_config,
+ os_creds_dict, vm_dict,
+ images_dict, flavors_dict,
+ arguments.tmplt_file):
logger.error("Problem applying ansible playbooks")
else:
- logger.error('Unable to read configuration file - ' + arguments.environment)
+ logger.error(
+ 'Unable to read configuration file - ' + arguments.tmplt_file)
exit(1)
exit(0)
-def __cleanup(vm_dict, keypairs_dict, router_dict, network_dict, image_dict, flavor_dict, clean_image=False):
- for key, vm_inst in vm_dict.iteritems():
- vm_inst.clean()
- for key, kp_inst in keypairs_dict.iteritems():
- kp_inst.clean()
- for key, router_inst in router_dict.iteritems():
- router_inst.clean()
- for key, net_inst in network_dict.iteritems():
- net_inst.clean()
- if clean_image:
- for key, image_inst in image_dict.iteritems():
- image_inst.clean()
- for key, flavor_inst in flavor_dict.iteritems():
- flavor_inst.clean()
+def __cleanup(creators, clean_image=False):
+ for creator_dict in reversed(creators):
+ for key, creator in creator_dict.items():
+ if ((isinstance(creator, OpenStackImage) and clean_image)
+ or not isinstance(creator, OpenStackImage)):
+ try:
+ creator.clean()
+ except Exception as e:
+ logger.warning('Error cleaning component - %s', e)
if __name__ == '__main__':
- # To ensure any files referenced via a relative path will begin from the diectory in which this file resides
+ # To ensure any files referenced via a relative path will begin from the
+ # directory in which this file resides
os.chdir(os.path.dirname(os.path.realpath(__file__)))
parser = argparse.ArgumentParser()
- parser.add_argument('-d', '--deploy', dest='deploy', nargs='?', default=ARG_NOT_SET,
- help='When used, environment will be deployed and provisioned')
- parser.add_argument('-c', '--clean', dest='clean', nargs='?', default=ARG_NOT_SET,
- help='When used, the environment will be removed')
- parser.add_argument('-i', '--clean-image', dest='clean_image', nargs='?', default=ARG_NOT_SET,
- help='When cleaning, if this is set, the image will be cleaned too')
- parser.add_argument('-e', '--env', dest='environment', required=True,
- help='The environment configuration YAML file - REQUIRED')
- parser.add_argument('-l', '--log-level', dest='log_level', default='INFO', help='Logging Level (INFO|DEBUG)')
+ parser.add_argument(
+ '-d', '--deploy', dest='deploy', nargs='?', default=ARG_NOT_SET,
+ help='When used, environment will be deployed and provisioned')
+ parser.add_argument(
+ '-c', '--clean', dest='clean', nargs='?', default=ARG_NOT_SET,
+ help='When used, the environment will be removed')
+ parser.add_argument(
+ '-i', '--clean-image', dest='clean_image', nargs='?',
+ default=ARG_NOT_SET,
+ help='When cleaning, if this is set, the image will be cleaned too')
+ parser.add_argument(
+ '-t', '--tmplt', dest='tmplt_file', required=True,
+ help='The SNAPS deployment template YAML file - REQUIRED')
+ parser.add_argument(
+ '-e', '--env-file', dest='env_file',
+ help='Yaml file containing substitution values to the env file')
+ parser.add_argument(
+ '-l', '--log-level', dest='log_level', default='INFO',
+ help='Logging Level (INFO|DEBUG)')
args = parser.parse_args()
if args.deploy is ARG_NOT_SET and args.clean is ARG_NOT_SET:
- print 'Must enter either -d for deploy or -c for cleaning up and environment'
+ print(
+ 'Must enter either -d for deploy or -c for cleaning up and '
+ 'environment')
exit(1)
if args.deploy is not ARG_NOT_SET and args.clean is not ARG_NOT_SET:
- print 'Cannot enter both options -d/--deploy and -c/--clean'
+ print('Cannot enter both options -d/--deploy and -c/--clean')
exit(1)
main(args)