Enhancements to the SNAPS orchestrator/launcher 45/49745/1
authorspisarski <s.pisarski@cablelabs.com>
Thu, 28 Dec 2017 23:09:48 +0000 (16:09 -0700)
committerspisarski <s.pisarski@cablelabs.com>
Thu, 28 Dec 2017 23:09:48 +0000 (16:09 -0700)
Added support for more Ansible substitution values extracted
from OpenStack instances (i.e. subnet broadcast address, router
external IP for gateway configuration, CIDR IP, netmask, etc.)

Removed most try/except blocks to ensure processing does not
continue when a problem should arise

Added the ability to know when cloud-init has completed

Removed nic configuration from OpenStackVmInstance as userdata/
cloud-init/cloud-config should be performing that functionality

Fixed some logging messages

Misc launcher bug fixes

Change-Id: I73e7607ee158cce3d16f9c1c1fc7c32ef5899a1d
Signed-off-by: spisarski <s.pisarski@cablelabs.com>
19 files changed:
docs/how-to-use/IntegrationTests.rst
examples/launch.py
snaps/openstack/create_flavor.py
snaps/openstack/create_image.py
snaps/openstack/create_instance.py
snaps/openstack/tests/create_instance_tests.py
snaps/openstack/tests/openstack_tests.py
snaps/openstack/utils/launch_utils.py [new file with mode: 0644]
snaps/provisioning/ansible_pb/__init__.py [deleted file]
snaps/provisioning/ansible_pb/centos-network-setup/__init__.py [deleted file]
snaps/provisioning/ansible_pb/centos-network-setup/playbooks/__init__.py [deleted file]
snaps/provisioning/ansible_pb/centos-network-setup/playbooks/configure_host.yml [deleted file]
snaps/provisioning/ansible_pb/centos-network-setup/templates/ifcfg-interface [deleted file]
snaps/provisioning/ansible_pb/ubuntu-network-setup/__init__.py [deleted file]
snaps/provisioning/ansible_pb/ubuntu-network-setup/playbooks/__init__.py [deleted file]
snaps/provisioning/ansible_pb/ubuntu-network-setup/playbooks/configure_host.yml [deleted file]
snaps/provisioning/ansible_pb/ubuntu-network-setup/templates/ethN.cfg [deleted file]
snaps/provisioning/tests/ansible_utils_tests.py
snaps/test_suite_builder.py

index df8859f..b7aa864 100644 (file)
@@ -606,16 +606,6 @@ create_instance_tests.py - CreateInstanceFromThreePartImage
 |                                                     | Neutron 2     | delete it when using a 3-part image                       |
 +-----------------------------------------------------+---------------+-----------------------------------------------------------+
 
-create_instance_tests.py - CreateInstancePubPrivNetTests (Staging)
-------------------------------------------------------------------
-
-+---------------------------------------+---------------+-----------------------------------------------------------+
-| Test Name                             | API Versions  | Description                                               |
-+=======================================+===============+===========================================================+
-| test_dual_ports_dhcp                  | Nova 2        | Ensures that a VM with two ports/NICs can have its second |
-|                                       | Neutron 2     | NIC configured via SSH/Ansible after startup              |
-+---------------------------------------+---------------+-----------------------------------------------------------+
-
 create_instance_tests.py - CreateInstanceIPv6NetworkTests (Staging)
 -------------------------------------------------------------------
 
index 975d834..04bc5d6 100644 (file)
 # This script is responsible for deploying virtual environments
 import argparse
 import logging
-import re
 
-import time
 from jinja2 import Environment, FileSystemLoader
 import os
 import yaml
 
 from snaps import file_utils
-from snaps.config.flavor import FlavorConfig
-from snaps.config.image import ImageConfig
-from snaps.config.keypair import KeypairConfig
-from snaps.config.network import PortConfig, NetworkConfig
-from snaps.config.project import ProjectConfig
-from snaps.config.qos import QoSConfig
-from snaps.config.router import RouterConfig
-from snaps.config.security_group import SecurityGroupConfig
-from snaps.config.user import UserConfig
-from snaps.config.vm_inst import VmInstanceConfig
-from snaps.config.volume import VolumeConfig
-from snaps.config.volume_type import VolumeTypeConfig
-from snaps.openstack.create_flavor import OpenStackFlavor
-from snaps.openstack.create_image import OpenStackImage
-from snaps.openstack.create_keypairs import OpenStackKeypair
-from snaps.openstack.create_network import OpenStackNetwork
-from snaps.openstack.create_project import OpenStackProject
-from snaps.openstack.create_qos import OpenStackQoS
-from snaps.openstack.create_router import OpenStackRouter
-from snaps.openstack.create_security_group import OpenStackSecurityGroup
-from snaps.openstack.create_user import OpenStackUser
-from snaps.openstack.create_volume import OpenStackVolume
-from snaps.openstack.create_volume_type import OpenStackVolumeType
-from snaps.openstack.os_credentials import OSCreds, ProxySettings
-from snaps.openstack.utils import deploy_utils
-from snaps.provisioning import ansible_utils
+from snaps.openstack.utils import launch_utils
 
 __author__ = 'spisarski'
 
 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
-    :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 = config.get('http_proxy')
-    if http_proxy:
-        tokens = re.split(':', http_proxy)
-        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(**config)
-
-
-def __parse_ports_config(config):
-    """
-    Parses the "ports" configuration
-    :param config: The dictionary to parse
-    :return: a list of PortConfig objects
-    """
-    out = list()
-    for port_config in config:
-        out.append(PortConfig(**port_config.get('port')))
-    return out
-
-
-def __create_instances(os_creds_dict, creator_class, config_class, config,
-                       config_key, cleanup=False, os_users_dict=None):
-    """
-    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
-    """
-    out = {}
-
-    if config:
-        try:
-            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:
-            logger.error('Unexpected error instantiating creator [%s] '
-                         'with exception %s', creator_class, e)
-
-    return out
-
-
-def __create_vm_instances(os_creds_dict, os_users_dict, instances_config,
-                          image_dict, keypairs_dict, cleanup=False):
-    """
-    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
-    :return: dictionary
-    """
-    vm_dict = {}
-
-    if instances_config:
-        try:
-            for instance_config in instances_config:
-                conf = instance_config.get('instance')
-                if conf:
-                    if image_dict:
-                        image_creator = image_dict.get(conf.get('imageName'))
-                        if image_creator:
-                            instance_settings = VmInstanceConfig(
-                                **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')
-                    else:
-                        raise Exception('Image dictionary is None. Cannot '
-                                        'instantiate')
-                else:
-                    raise Exception('Instance configuration is None. Cannot '
-                                    'instantiate')
-            logger.info('Created configured instances')
-        except Exception as e:
-            logger.error('Unexpected error creating VM instances - %s', e)
-    return vm_dict
-
-
-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_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 list(vm_dict.values()):
-            if not vm_inst.vm_ssh_active(block=True):
-                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
-        orig_cwd = os.getcwd()
-        env_dir = os.path.dirname(env_file)
-        os.chdir(env_dir)
-
-        # Apply playbooks
-        for ansible_config in ansible_configs:
-            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):
-    """
-    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
-    """
-    if ansible_config:
-        (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),
-                proxy_setting=proxy_settings)
-            if retval != 0:
-                # Not a fatal type of event
-                logger.warning(
-                    'Unable to apply playbook found at location - %s',
-                    ansible_config.get('playbook_location'))
-
-
-def __get_connection_info(ansible_config, vm_dict):
-    """
-    Returns a tuple of data required for connecting to the running VMs
-    (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)
-    """
-    if ansible_config.get('hosts'):
-        hosts = ansible_config['hosts']
-        if len(hosts) > 0:
-            floating_ips = list()
-            remote_user = None
-            pk_file = None
-            proxy_settings = None
-            for host in hosts:
-                vm = vm_dict.get(host)
-                if vm:
-                    fip = vm.get_floating_ip()
-                    if fip:
-                        remote_user = vm.get_image_user()
-
-                        if fip:
-                            floating_ips.append(fip.ip)
-                        else:
-                            raise Exception(
-                                'Could not find floating IP for VM - ' +
-                                vm.name)
-
-                        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, 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
-    :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
-    :return: dictionary or None
-    """
-    if var_config and vm_dict and len(vm_dict) > 0:
-        variables = 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 [%s] the value [%s]",
-                    key, value)
-            else:
-                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):
-    """
-    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
-    :return:
-    """
-    if var_config_values['type'] == 'string':
-        return __get_string_variable_value(var_config_values)
-    if var_config_values['type'] == 'vm-attr':
-        return __get_vm_attr_variable_value(var_config_values, vm_dict)
-    if var_config_values['type'] == 'os_creds':
-        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':
-        return __get_flavor_variable_value(var_config_values, flavor_dict)
-    return None
-
-
-def __get_string_variable_value(var_config_values):
-    """
-    Returns the associated string value
-    :param var_config_values: the configuration dictionary
-    :return: the value contained in the dictionary with the key 'value'
-    """
-    return var_config_values['value']
-
-
-def __get_vm_attr_variable_value(var_config_values, vm_dict):
-    """
-    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
-    :return: the value
-    """
-    vm = vm_dict.get(var_config_values['vm_name'])
-    if vm:
-        if var_config_values['value'] == 'floating_ip':
-            return vm.get_floating_ip().ip
-        if var_config_values['value'] == 'image_user':
-            return vm.get_image_user()
-
-
-def __get_os_creds_variable_value(var_config_values, os_creds):
-    """
-    Returns the associated OS credentials value
-    :param var_config_values: the configuration dictionary
-    :param os_creds: the credentials
-    :return: the value
-    """
-    logger.info("Retrieving OS Credentials")
-    if os_creds:
-        if var_config_values['value'] == 'username':
-            logger.info("Returning OS username")
-            return os_creds.username
-        elif var_config_values['value'] == 'password':
-            logger.info("Returning OS password")
-            return os_creds.password
-        elif var_config_values['value'] == 'auth_url':
-            logger.info("Returning OS auth_url")
-            return os_creds.auth_url
-        elif var_config_values['value'] == 'project_name':
-            logger.info("Returning OS project_name")
-            return os_creds.project_name
-
-    logger.info("Returning none")
-    return None
-
-
-def __get_vm_port_variable_value(var_config_values, vm_dict):
-    """
-    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
-    :return: the value
-    """
-    port_name = var_config_values.get('port_name')
-    vm_name = var_config_values.get('vm_name')
-
-    if port_name and vm_name:
-        vm = vm_dict.get(vm_name)
-        if vm:
-            port_value_id = var_config_values.get('port_value')
-            if port_value_id:
-                if port_value_id == 'mac_address':
-                    return vm.get_port_mac(port_name)
-                if port_value_id == 'ip_address':
-                    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
-    :return: the value
-    """
-    logger.info("Retrieving image values")
-
-    if image_dict:
-        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':
-                    return image_creator.get_image().id
-                if var_config_values.get('value') and \
-                        var_config_values['value'] == 'user':
-                    return image_creator.image_settings.image_user
-
-    logger.info("Returning none")
-    return None
-
-
-def __get_flavor_variable_value(var_config_values, flavor_dict):
-    """
-    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
-    :return: the value or None
-    """
-    logger.info("Retrieving flavor values")
-
-    if flavor_dict:
-        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':
-                    return flavor_creator.get_flavor().id
 
 
 def main(arguments):
@@ -605,127 +66,11 @@ def main(arguments):
     config = yaml.load(output)
 
     if config:
-        os_config = config.get('openstack')
-
-        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:
-                # Create projects
-                projects_dict = __create_instances(
-                    os_creds_dict, OpenStackProject, ProjectConfig,
-                    os_config.get('projects'), 'project', clean)
-                creators.append(projects_dict)
-
-                # Create users
-                users_dict = __create_instances(
-                    os_creds_dict, OpenStackUser, UserConfig,
-                    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
-                flavors_dict = __create_instances(
-                    os_creds_dict, OpenStackFlavor, FlavorConfig,
-                    os_config.get('flavors'), 'flavor', clean, users_dict)
-                creators.append(flavors_dict)
-
-                # Create QoS specs
-                qos_dict = __create_instances(
-                    os_creds_dict, OpenStackQoS, QoSConfig,
-                    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, VolumeTypeConfig,
-                    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, VolumeConfig,
-                    os_config.get('volumes'), 'volume', clean, users_dict)
-                creators.append(vol_dict)
-
-                # Create images
-                images_dict = __create_instances(
-                    os_creds_dict, OpenStackImage, ImageConfig,
-                    os_config.get('images'), 'image', clean, users_dict)
-                creators.append(images_dict)
-
-                # Create networks
-                creators.append(__create_instances(
-                    os_creds_dict, OpenStackNetwork, NetworkConfig,
-                    os_config.get('networks'), 'network', clean, users_dict))
-
-                # Create routers
-                creators.append(__create_instances(
-                    os_creds_dict, OpenStackRouter, RouterConfig,
-                    os_config.get('routers'), 'router', clean, users_dict))
-
-                # Create keypairs
-                keypairs_dict = __create_instances(
-                    os_creds_dict, OpenStackKeypair, KeypairConfig,
-                    os_config.get('keypairs'), 'keypair', clean, users_dict)
-                creators.append(keypairs_dict)
-
-                # Create security groups
-                creators.append(__create_instances(
-                    os_creds_dict, OpenStackSecurityGroup,
-                    SecurityGroupConfig,
-                    os_config.get('security_groups'), 'security_group', clean,
-                    users_dict))
-
-                # Create instance
-                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 - ' + str(e))
-                raise
-
-        # Must enter either block
-        if arguments.clean is not ARG_NOT_SET:
-            # Cleanup Environment
-            __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.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_creds_dict, vm_dict,
-                                                 images_dict, flavors_dict,
-                                                 arguments.tmplt_file):
-                    logger.error("Problem applying ansible playbooks")
+        clean_image = arguments.clean_image is not ARG_NOT_SET
+        deploy = arguments.deploy is not ARG_NOT_SET
+        launch_utils.launch_config(
+            config, arguments.tmplt_file, deploy, clean, clean_image)
     else:
         logger.error(
             'Unable to read configuration file - ' + arguments.tmplt_file)
@@ -734,17 +79,6 @@ def main(arguments):
     exit(0)
 
 
-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
     # directory in which this file resides
index b866d43..65b9059 100644 (file)
@@ -71,8 +71,6 @@ class OpenStackFlavor(OpenStackComputeObject):
             if self.flavor_settings.metadata:
                 nova_utils.set_flavor_keys(self._nova, self.__flavor,
                                            self.flavor_settings.metadata)
-        else:
-            logger.info('Did not create flavor due to cleanup mode')
 
         return self.__flavor
 
index 2e7aa39..a5520e3 100644 (file)
@@ -57,6 +57,7 @@ class OpenStackImage(OpenStackCloudObject):
         self.__glance = glance_utils.glance_client(self._os_creds)
         self.__image = glance_utils.get_image(
             self.__glance, image_settings=self.image_settings)
+
         if self.__image:
             logger.info('Found image with name - ' + self.image_settings.name)
             return self.__image
@@ -70,6 +71,7 @@ class OpenStackImage(OpenStackCloudObject):
             self.__kernel_image = glance_utils.get_image(
                 self.__glance,
                 image_settings=self.image_settings.kernel_image_settings)
+
         if self.image_settings.ramdisk_image_settings:
             self.__ramdisk_image = glance_utils.get_image(
                 self.__glance,
@@ -97,6 +99,7 @@ class OpenStackImage(OpenStackCloudObject):
                         self.__glance,
                         self.image_settings.kernel_image_settings)
                 extra_properties['kernel_id'] = self.__kernel_image.id
+
             if self.image_settings.ramdisk_image_settings:
                 if not self.__ramdisk_image:
                     logger.info(
@@ -113,6 +116,7 @@ class OpenStackImage(OpenStackCloudObject):
 
             logger.info(
                 'Created image with name - %s', self.image_settings.name)
+
             if self.__image and self.image_active(block=True):
                 logger.info(
                     'Image is now active with name - %s',
@@ -122,8 +126,6 @@ class OpenStackImage(OpenStackCloudObject):
                 raise ImageCreationError(
                     'Image was not created or activated in the alloted amount'
                     'of time')
-        else:
-            logger.info('Did not create image due to cleanup mode')
 
         return self.__image
 
index 336c936..b68372e 100644 (file)
@@ -15,7 +15,6 @@
 import logging
 import time
 
-from neutronclient.common.exceptions import PortNotFoundClient
 from novaclient.exceptions import NotFound, BadRequest
 
 from snaps.config.vm_inst import VmInstanceConfig, FloatingIpConfig
@@ -33,6 +32,7 @@ logger = logging.getLogger('create_instance')
 POLL_INTERVAL = 3
 STATUS_ACTIVE = 'ACTIVE'
 STATUS_DELETED = 'DELETED'
+CLOUD_INIT_TIMEOUT = 120
 
 
 class OpenStackVmInstance(OpenStackComputeObject):
@@ -255,19 +255,25 @@ class OpenStackVmInstance(OpenStackComputeObject):
 
         # Cleanup floating IPs
         for name, floating_ip in self.__floating_ip_dict.items():
-            try:
-                logger.info('Deleting Floating IP - ' + floating_ip.ip)
-                neutron_utils.delete_floating_ip(self.__neutron, floating_ip)
-            except Exception as e:
-                logger.error('Error deleting Floating IP - ' + str(e))
+            logger.info('Deleting Floating IP - ' + floating_ip.ip)
+            neutron_utils.delete_floating_ip(self.__neutron, floating_ip)
+
         self.__floating_ip_dict = dict()
 
-        # Detach Volume
-        for volume_rec in self.__vm.volume_ids:
-            cinder = cinder_utils.cinder_client(self._os_creds)
-            volume = cinder_utils.get_volume_by_id(cinder, volume_rec['id'])
-            if volume:
-                try:
+        # Cleanup ports
+        for name, port in self.__ports:
+            logger.info('Deleting Port with ID - %s ', port.id)
+            neutron_utils.delete_port(self.__neutron, port)
+
+        self.__ports = list()
+
+        if self.__vm:
+            # Detach Volume
+            for volume_rec in self.__vm.volume_ids:
+                cinder = cinder_utils.cinder_client(self._os_creds)
+                volume = cinder_utils.get_volume_by_id(
+                    cinder, volume_rec['id'])
+                if volume:
                     vm = nova_utils.detach_volume(
                         self._nova, self.__neutron, self.__vm, volume, 30)
                     if vm:
@@ -275,50 +281,32 @@ class OpenStackVmInstance(OpenStackComputeObject):
                     else:
                         logger.warn(
                             'Timeout waiting to detach volume %s', volume.name)
-                except Exception as e:
-                    logger.error('Unexpected error detaching volume %s '
-                                 'with error %s', volume.name, e)
-            else:
-                logger.warn('Unable to detach volume with ID - [%s]',
-                            volume_rec['id'])
+                else:
+                    logger.warn('Unable to detach volume with ID - [%s]',
+                                volume_rec['id'])
 
-        # Cleanup ports
-        for name, port in self.__ports:
-            logger.info('Deleting Port with ID - %s ', port.id)
-            try:
-                neutron_utils.delete_port(self.__neutron, port)
-            except PortNotFoundClient as e:
-                logger.warning('Unexpected error deleting port - %s', e)
-                pass
-        self.__ports = list()
+            # Cleanup VM
+            logger.info(
+                'Deleting VM instance - ' + self.instance_settings.name)
 
-        # Cleanup VM
-        if self.__vm:
             try:
-                logger.info(
-                    'Deleting VM instance - ' + self.instance_settings.name)
                 nova_utils.delete_vm_instance(self._nova, self.__vm)
-            except Exception as e:
-                logger.error('Error deleting VM - %s', e)
+            except NotFound as e:
+                logger.warn('Instance already deleted - %s', e)
 
             # Block until instance cannot be found or returns the status of
             # DELETED
             logger.info('Checking deletion status')
 
-            try:
-                if self.vm_deleted(block=True):
-                    logger.info(
-                        'VM has been properly deleted VM with name - %s',
-                        self.instance_settings.name)
-                    self.__vm = None
-                else:
-                    logger.error(
-                        'VM not deleted within the timeout period of %s '
-                        'seconds', self.instance_settings.vm_delete_timeout)
-            except Exception as e:
+            if self.vm_deleted(block=True):
+                logger.info(
+                    'VM has been properly deleted VM with name - %s',
+                    self.instance_settings.name)
+                self.__vm = None
+            else:
                 logger.error(
-                    'Unexpected error while checking VM instance status - %s',
-                    e)
+                    'VM not deleted within the timeout period of %s '
+                    'seconds', self.instance_settings.vm_delete_timeout)
 
     def __query_ports(self, port_settings):
         """
@@ -489,25 +477,6 @@ class OpenStackVmInstance(OpenStackComputeObject):
         """
         return nova_utils.get_server_info(self._nova, self.__vm)
 
-    def config_nics(self):
-        """
-        Responsible for configuring NICs on RPM systems where the instance has
-        more than one configured port
-        :return: the value returned by ansible_utils.apply_ansible_playbook()
-        """
-        if len(self.__ports) > 1 and len(self.__floating_ip_dict) > 0:
-            if self.vm_active(block=True) and self.vm_ssh_active(block=True):
-                for key, port in self.__ports:
-                    port_index = self.__ports.index((key, port))
-                    if port_index > 0:
-                        nic_name = 'eth' + repr(port_index)
-                        retval = self.__config_nic(
-                            nic_name, port,
-                            self.__get_first_provisioning_floating_ip().ip)
-                        logger.info('Configured NIC - %s on VM - %s',
-                                    nic_name, self.instance_settings.name)
-                        return retval
-
     def __get_first_provisioning_floating_ip(self):
         """
         Returns the first floating IP tagged with the Floating IP name if
@@ -528,31 +497,6 @@ class OpenStackVmInstance(OpenStackComputeObject):
             for key, fip in self.__floating_ip_dict.items():
                 return fip
 
-    def __config_nic(self, nic_name, port, ip):
-        """
-        Although ports/NICs can contain multiple IPs, this code currently only
-        supports the first.
-
-        :param nic_name: Name of the interface
-        :param port: The port information containing the expected IP values.
-        :param ip: The IP on which to apply the playbook.
-        :return: the return value from ansible
-        """
-        port_ip = port.ips[0]['ip_address']
-        variables = {
-            'floating_ip': ip,
-            'nic_name': nic_name,
-            'nic_ip': port_ip
-        }
-
-        if self.image_settings.nic_config_pb_loc and self.keypair_settings:
-            return self.apply_ansible_playbook(
-                self.image_settings.nic_config_pb_loc, variables)
-        else:
-            logger.warning(
-                'VM %s cannot self configure NICs eth1++. No playbook or '
-                'keypairs found.', self.instance_settings.name)
-
     def apply_ansible_playbook(self, pb_file_loc, variables=None,
                                fip_name=None):
         """
@@ -722,6 +666,56 @@ class OpenStackVmInstance(OpenStackComputeObject):
                 return True
         return False
 
+    def cloud_init_complete(self, block=False, poll_interval=POLL_INTERVAL):
+        """
+        Returns true when the VM's cloud-init routine has completed.
+        Note: this is currently done via SSH, therefore, if this instance does
+              not have a Floating IP or a running SSH server, this routine
+              will always return False or raise an Exception
+        :param block: When true, thread will block until active or timeout
+                      value in seconds has been exceeded (False)
+        :param poll_interval: The polling interval
+        :return: T/F
+        """
+        # sleep and wait for VM status change
+        logger.info('Checking if cloud-init has completed')
+
+        timeout = CLOUD_INIT_TIMEOUT
+
+        if self.vm_active(block=True) and self.vm_ssh_active(block=True):
+            if block:
+                start = time.time()
+            else:
+                start = time.time() - timeout
+
+            while timeout > time.time() - start:
+                status = self.__cloud_init_complete()
+                if status:
+                    logger.info('cloud-init complete for VM instance')
+                    return True
+
+                logger.debug('Retry cloud-init query in ' + str(
+                    poll_interval) + ' seconds')
+                time.sleep(poll_interval)
+                logger.debug('cloud-init complete timeout in ' + str(
+                    timeout - (time.time() - start)))
+
+        logger.error('Timeout waiting for cloud-init to complete')
+        return False
+
+    def __cloud_init_complete(self):
+        """
+        Returns True when can create a SSH session else False
+        :return: T/F
+        """
+        if len(self.__floating_ip_dict) > 0:
+            ssh = self.ssh_client()
+            if ssh:
+                stdin1, stdout1, sterr1 = ssh.exec_command(
+                    'ls -l /var/lib/cloud/instance/boot-finished')
+                return stdout1.channel.recv_exit_status() == 0
+        return False
+
     def get_floating_ip(self, fip_name=None):
         """
         Returns the floating IP object byt name if found, else the first known,
index 486018d..bee06ea 100644 (file)
@@ -1601,224 +1601,6 @@ class CreateInstanceOnComputeHost(OSIntegrationTestCase):
             index += 1
 
 
-class CreateInstancePubPrivNetTests(OSIntegrationTestCase):
-    """
-    Test for the CreateInstance class with two NIC/Ports, eth0 with floating IP
-    and eth1 w/o.
-    These tests require a Centos image
-    """
-
-    def setUp(self):
-        """
-        Instantiates the CreateImage object that is responsible for downloading
-        and creating an OS image file within OpenStack
-        """
-        super(self.__class__, self).__start__()
-
-        self.nova = nova_utils.nova_client(self.os_creds)
-
-        # Initialize for tearDown()
-        self.image_creator = None
-        self.network_creators = list()
-        self.router_creators = list()
-        self.flavor_creator = None
-        self.keypair_creator = None
-        self.sec_grp_creator = None
-        self.inst_creator = None
-
-        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
-        self.keypair_priv_filepath = 'tmp/' + self.guid
-        self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
-        self.keypair_name = self.guid + '-kp'
-        self.vm_inst_name = self.guid + '-inst'
-        self.port_1_name = self.guid + '-port-1'
-        self.port_2_name = self.guid + '-port-2'
-        self.floating_ip_name = self.guid + 'fip1'
-        self.priv_net_config = openstack_tests.get_priv_net_config(
-            net_name=self.guid + '-priv-net',
-            subnet_name=self.guid + '-priv-subnet',
-            router_name=self.guid + '-priv-router',
-            external_net=self.ext_net_name)
-        self.pub_net_config = openstack_tests.get_pub_net_config(
-            net_name=self.guid + '-pub-net',
-            subnet_name=self.guid + '-pub-subnet',
-            router_name=self.guid + '-pub-router',
-            external_net=self.ext_net_name)
-
-        image_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
-        os_image_settings = openstack_tests.centos_image_settings(
-            name=image_name, image_metadata=self.image_metadata)
-
-        try:
-            # Create Image
-            self.image_creator = OpenStackImage(self.os_creds,
-                                                os_image_settings)
-            self.image_creator.create()
-
-            # First network is public
-            self.network_creators.append(OpenStackNetwork(
-                self.os_creds, self.pub_net_config.network_settings))
-            # Second network is private
-            self.network_creators.append(OpenStackNetwork(
-                self.os_creds, self.priv_net_config.network_settings))
-            for network_creator in self.network_creators:
-                network_creator.create()
-
-            self.router_creators.append(OpenStackRouter(
-                self.os_creds, self.pub_net_config.router_settings))
-            self.router_creators.append(OpenStackRouter(
-                self.os_creds, self.priv_net_config.router_settings))
-
-            # Create Routers
-            for router_creator in self.router_creators:
-                router_creator.create()
-
-            # Create Flavor
-            self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=self.guid + '-flavor-name', ram=512,
-                             disk=10, vcpus=2,
-                             metadata=self.flavor_metadata))
-            self.flavor_creator.create()
-
-            # Create Keypair
-            self.keypair_creator = OpenStackKeypair(
-                self.os_creds, KeypairConfig(
-                    name=self.keypair_name,
-                    public_filepath=self.keypair_pub_filepath,
-                    private_filepath=self.keypair_priv_filepath))
-            self.keypair_creator.create()
-
-            sec_grp_name = self.guid + '-sec-grp'
-            rule1 = SecurityGroupRuleConfig(
-                sec_grp_name=sec_grp_name, direction=Direction.ingress,
-                protocol=Protocol.icmp)
-            rule2 = SecurityGroupRuleConfig(
-                sec_grp_name=sec_grp_name, direction=Direction.ingress,
-                protocol=Protocol.tcp, port_range_min=22, port_range_max=22)
-            self.sec_grp_creator = OpenStackSecurityGroup(
-                self.os_creds,
-                SecurityGroupConfig(
-                    name=sec_grp_name, rule_settings=[rule1, rule2]))
-            self.sec_grp_creator.create()
-        except:
-            self.tearDown()
-            raise
-
-    def tearDown(self):
-        """
-        Cleans the created objects
-        """
-        if self.inst_creator:
-            try:
-                self.inst_creator.clean()
-            except Exception as e:
-                logger.error(
-                    'Unexpected exception cleaning VM instance with message '
-                    '- %s', e)
-
-        if self.keypair_creator:
-            try:
-                self.keypair_creator.clean()
-            except Exception as e:
-                logger.error(
-                    'Unexpected exception cleaning keypair with message - %s',
-                    e)
-
-        if self.flavor_creator:
-            try:
-                self.flavor_creator.clean()
-            except Exception as e:
-                logger.error(
-                    'Unexpected exception cleaning flavor with message - %s',
-                    e)
-
-        for router_creator in self.router_creators:
-            try:
-                router_creator.clean()
-            except Exception as e:
-                logger.error(
-                    'Unexpected exception cleaning router with message - %s',
-                    e)
-
-        for network_creator in self.network_creators:
-            try:
-                network_creator.clean()
-            except Exception as e:
-                logger.error(
-                    'Unexpected exception cleaning network with message - %s',
-                    e)
-
-        if self.sec_grp_creator:
-            try:
-                self.sec_grp_creator.clean()
-            except Exception as e:
-                logger.error(
-                    'Unexpected exception cleaning security group with message'
-                    ' - %s', e)
-
-        if self.image_creator and not self.image_creator.image_settings.exists:
-            try:
-                self.image_creator.clean()
-            except Exception as e:
-                logger.error(
-                    'Unexpected exception cleaning image with message - %s', e)
-
-        super(self.__class__, self).__clean__()
-
-    def test_dual_ports_dhcp(self):
-        """
-        Tests the creation of an OpenStack instance with a dual ports/NICs with
-        a DHCP assigned IP.
-        NOTE: This test and any others that call ansible will most likely fail
-        unless you do one of two things:
-        1. Have a ~/.ansible.cfg (or alternate means) to
-           set host_key_checking = False
-        2. Set the following environment variable in your executing shell:
-           ANSIBLE_HOST_KEY_CHECKING=False
-        Should this not be performed, the creation of the host ssh key will
-        cause your ansible calls to fail.
-        """
-        # Create ports/NICs for instance
-        ports_settings = []
-        ctr = 1
-        for network_creator in self.network_creators:
-            ports_settings.append(PortConfig(
-                name=self.guid + '-port-' + str(ctr),
-                network_name=network_creator.network_settings.name))
-            ctr += 1
-
-        # Create instance
-        instance_settings = VmInstanceConfig(
-            name=self.vm_inst_name,
-            flavor=self.flavor_creator.flavor_settings.name,
-            port_settings=ports_settings,
-            security_group_names=[self.sec_grp_creator.sec_grp_settings.name],
-            floating_ip_settings=[FloatingIpConfig(
-                name=self.floating_ip_name, port_name=self.port_1_name,
-                router_name=self.pub_net_config.router_settings.name)])
-
-        self.inst_creator = OpenStackVmInstance(
-            self.os_creds, instance_settings,
-            self.image_creator.image_settings,
-            keypair_settings=self.keypair_creator.keypair_settings)
-
-        vm_inst = self.inst_creator.create(block=True)
-
-        self.assertEqual(vm_inst.id, self.inst_creator.get_vm_inst().id)
-
-        # Effectively blocks until VM has been properly activated
-        self.assertTrue(self.inst_creator.vm_active(block=True))
-
-        ip = self.inst_creator.get_port_ip(ports_settings[0].name)
-        self.assertTrue(check_dhcp_lease(self.inst_creator, ip))
-
-        # Effectively blocks until VM's ssh port has been opened
-        self.assertTrue(self.inst_creator.vm_ssh_active(block=True))
-
-        self.assertEqual(0, self.inst_creator.config_nics())
-
-
 class InstanceSecurityGroupTests(OSIntegrationTestCase):
     """
     Tests that include, add, and remove security groups from VM instances
index 4b00922..7e08fca 100644 (file)
@@ -271,15 +271,12 @@ def centos_image_settings(name, url=None, image_metadata=None,
     else:
         metadata = image_metadata
 
-    pb_path = pkg_resources.resource_filename(
-        'snaps.provisioning.ansible_pb.centos-network-setup.playbooks',
-        'configure_host.yml')
     return create_image_settings(
         image_name=name, image_user=CENTOS_USER,
         image_format=DEFAULT_IMAGE_FORMAT, metadata=metadata, disk_url=url,
         default_url=CENTOS_DEFAULT_IMAGE_URL,
         kernel_settings=kernel_settings, ramdisk_settings=ramdisk_settings,
-        public=public, nic_config_pb_loc=pb_path)
+        public=public)
 
 
 def ubuntu_image_settings(name, url=None, image_metadata=None,
@@ -304,15 +301,12 @@ def ubuntu_image_settings(name, url=None, image_metadata=None,
     else:
         metadata = image_metadata
 
-    pb_path = pkg_resources.resource_filename(
-        'snaps.provisioning.ansible_pb.ubuntu-network-setup.playbooks',
-        'configure_host.yml')
     return create_image_settings(
         image_name=name, image_user=UBUNTU_USER,
         image_format=DEFAULT_IMAGE_FORMAT, metadata=metadata, disk_url=url,
         default_url=UBUNTU_DEFAULT_IMAGE_URL,
         kernel_settings=kernel_settings, ramdisk_settings=ramdisk_settings,
-        public=public, nic_config_pb_loc=pb_path)
+        public=public)
 
 
 def get_priv_net_config(net_name, subnet_name, router_name=None,
diff --git a/snaps/openstack/utils/launch_utils.py b/snaps/openstack/utils/launch_utils.py
new file mode 100644 (file)
index 0000000..abf04b5
--- /dev/null
@@ -0,0 +1,804 @@
+#
+# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
+#                    and others.  All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This utility makes it easy to create OpenStack objects
+import logging
+import re
+import socket
+import struct
+
+import os
+from keystoneauth1.exceptions import Unauthorized
+
+from snaps.config.flavor import FlavorConfig
+from snaps.config.image import ImageConfig
+from snaps.config.keypair import KeypairConfig
+from snaps.config.network import PortConfig, NetworkConfig
+from snaps.config.project import ProjectConfig
+from snaps.config.qos import QoSConfig
+from snaps.config.router import RouterConfig
+from snaps.config.security_group import SecurityGroupConfig
+from snaps.config.user import UserConfig
+from snaps.config.vm_inst import VmInstanceConfig
+from snaps.config.volume import VolumeConfig
+from snaps.config.volume_type import VolumeTypeConfig
+from snaps.openstack.create_flavor import OpenStackFlavor
+from snaps.openstack.create_image import OpenStackImage
+from snaps.openstack.create_keypairs import OpenStackKeypair
+from snaps.openstack.create_network import OpenStackNetwork
+from snaps.openstack.create_project import OpenStackProject
+from snaps.openstack.create_qos import OpenStackQoS
+from snaps.openstack.create_router import OpenStackRouter
+from snaps.openstack.create_security_group import OpenStackSecurityGroup
+from snaps.openstack.create_user import OpenStackUser
+from snaps.openstack.create_volume import OpenStackVolume
+from snaps.openstack.create_volume_type import OpenStackVolumeType
+from snaps.openstack.os_credentials import OSCreds, ProxySettings
+from snaps.openstack.utils import deploy_utils, neutron_utils
+from snaps.provisioning import ansible_utils
+
+logger = logging.getLogger('lanuch_utils')
+DEFAULT_CREDS_KEY = 'admin'
+
+
+def launch_config(config, tmplt_file, deploy, clean, clean_image):
+    """
+    Launches all objects and applies any configured ansible playbooks
+    :param config: the environment configuration dict object
+    :param tmplt_file: the path to the SNAPS-OO template file
+    :param deploy: when True deploy
+    :param clean: when True clean
+    :param clean_image: when True clean the image when clean is True
+    """
+    os_config = config.get('openstack')
+
+    creators = list()
+    vm_dict = dict()
+    images_dict = dict()
+    flavors_dict = dict()
+    networks_dict = dict()
+    routers_dict = dict()
+    os_creds_dict = dict()
+
+    if os_config:
+        os_creds_dict = __get_creds_dict(os_config)
+
+        # Create projects
+        projects_dict = __create_instances(
+            os_creds_dict, OpenStackProject, ProjectConfig,
+            os_config.get('projects'), 'project', clean)
+        creators.append(projects_dict)
+
+        # Create users
+        users_dict = __create_instances(
+            os_creds_dict, OpenStackUser, UserConfig,
+            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
+        flavors_dict = __create_instances(
+            os_creds_dict, OpenStackFlavor, FlavorConfig,
+            os_config.get('flavors'), 'flavor', clean, users_dict)
+        creators.append(flavors_dict)
+
+        # Create QoS specs
+        qos_dict = __create_instances(
+            os_creds_dict, OpenStackQoS, QoSConfig,
+            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, VolumeTypeConfig,
+            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, VolumeConfig,
+            os_config.get('volumes'), 'volume', clean, users_dict)
+        creators.append(vol_dict)
+
+        # Create images
+        images_dict = __create_instances(
+            os_creds_dict, OpenStackImage, ImageConfig,
+            os_config.get('images'), 'image', clean, users_dict)
+        creators.append(images_dict)
+
+        # Create networks
+        networks_dict = __create_instances(
+            os_creds_dict, OpenStackNetwork, NetworkConfig,
+            os_config.get('networks'), 'network', clean, users_dict)
+        creators.append(networks_dict)
+
+        # Create routers
+        routers_dict = __create_instances(
+            os_creds_dict, OpenStackRouter, RouterConfig,
+            os_config.get('routers'), 'router', clean, users_dict)
+        creators.append(routers_dict)
+
+        # Create keypairs
+        keypairs_dict = __create_instances(
+            os_creds_dict, OpenStackKeypair, KeypairConfig,
+            os_config.get('keypairs'), 'keypair', clean, users_dict)
+        creators.append(keypairs_dict)
+
+        # Create security groups
+        creators.append(__create_instances(
+            os_creds_dict, OpenStackSecurityGroup,
+            SecurityGroupConfig,
+            os_config.get('security_groups'), 'security_group', clean,
+            users_dict))
+
+        # Create instance
+        vm_dict = __create_vm_instances(
+            os_creds_dict, users_dict, os_config.get('instances'),
+            images_dict, keypairs_dict, clean)
+        creators.append(vm_dict)
+        logger.info(
+            'Completed creating/retrieving all configured instances')
+
+    # Must enter either block
+    if clean:
+        # Cleanup Environment
+        __cleanup(creators, clean_image)
+    elif deploy:
+        # Provision VMs
+        ansible_config = config.get('ansible')
+        if ansible_config and vm_dict:
+            if not __apply_ansible_playbooks(
+                    ansible_config, os_creds_dict, vm_dict, images_dict,
+                    flavors_dict, networks_dict, routers_dict, tmplt_file):
+                logger.error("Problem applying ansible playbooks")
+
+
+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
+    :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 = config.get('http_proxy')
+    if http_proxy:
+        tokens = re.split(':', http_proxy)
+        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(**config)
+
+
+def __parse_ports_config(config):
+    """
+    Parses the "ports" configuration
+    :param config: The dictionary to parse
+    :return: a list of PortConfig objects
+    """
+    out = list()
+    for port_config in config:
+        out.append(PortConfig(**port_config.get('port')))
+    return out
+
+
+def __create_instances(os_creds_dict, creator_class, config_class, config,
+                       config_key, cleanup=False, os_users_dict=None):
+    """
+    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
+    """
+    out = {}
+
+    if config:
+        for config_dict in config:
+            inst_config = config_dict.get(config_key)
+            if inst_config:
+                creds = __get_creds(os_creds_dict, os_users_dict, inst_config)
+                if creds:
+                    creator = creator_class(
+                        creds,
+                        config_class(**inst_config))
+
+                    if creator:
+                        if cleanup:
+                            try:
+                                creator.initialize()
+                            except Unauthorized as e:
+                                logger.warn(
+                                    'Unable to initialize creator [%s] - %s',
+                                    creator, e)
+                        else:
+                            creator.create()
+
+                        out[inst_config['name']] = creator
+
+        logger.info('Initialized configured %ss', config_key)
+
+    return out
+
+
+def __create_vm_instances(os_creds_dict, os_users_dict, instances_config,
+                          image_dict, keypairs_dict, cleanup=False):
+    """
+    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
+    :return: dictionary
+    """
+    vm_dict = {}
+
+    if instances_config:
+        for instance_config in instances_config:
+            conf = instance_config.get('instance')
+            if conf:
+                if image_dict:
+                    image_creator = image_dict.get(conf.get('imageName'))
+                    if image_creator:
+                        instance_settings = VmInstanceConfig(
+                            **instance_config['instance'])
+                        kp_creator = keypairs_dict.get(
+                            conf.get('keypair_name'))
+
+                        try:
+                            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)
+                        except Unauthorized as e:
+                            if not cleanup:
+                                logger.warn('Unable to initialize VM - %s', e)
+                                raise
+                    else:
+                        raise Exception('Image creator instance not found.'
+                                        ' Cannot instantiate')
+                else:
+                    if not cleanup:
+                        raise Exception('Image dictionary is None. Cannot '
+                                        'instantiate')
+            else:
+                raise Exception('Instance configuration is None. Cannot '
+                                'instantiate')
+        logger.info('Created configured instances')
+
+    return vm_dict
+
+
+def __apply_ansible_playbooks(ansible_configs, os_creds_dict, vm_dict,
+                              image_dict, flavor_dict, networks_dict,
+                              routers_dict, tmplt_file):
+    """
+    Applies ansible playbooks to running VMs with floating IPs
+    :param ansible_configs: a list of Ansible configurations
+    :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 networks_dict: the dictionary of newly instantiated networks where
+                          the name is the key
+    :param routers_dict: the dictionary of newly instantiated routers where
+                          the name is the key
+    :param tmplt_file: the path of the SNAPS-OO template file 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:
+        # Set CWD so the deployment file's playbook location can leverage
+        # relative paths
+        orig_cwd = os.getcwd()
+        env_dir = os.path.dirname(tmplt_file)
+        os.chdir(env_dir)
+
+        # Apply playbooks
+        for ansible_config in ansible_configs:
+            # Ensure all hosts are accepting SSH session requests
+            for vm_name in ansible_config['hosts']:
+                vm_inst = vm_dict.get(vm_name)
+                if vm_inst:
+                    if not vm_inst.vm_ssh_active(block=True):
+                        logger.warning(
+                            'Timeout waiting for instance to respond to '
+                            'SSH requests')
+                        return False
+
+            os_creds = os_creds_dict.get('admin-creds')
+            __apply_ansible_playbook(
+                ansible_config, os_creds, vm_dict, image_dict, flavor_dict,
+                networks_dict, routers_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, networks_dict, routers_dict):
+    """
+    Applies an Ansible configuration setting
+    :param ansible_config: the configuration settings
+    :param os_creds: the OpenStack admin 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 networks_dict: the dictionary of newly instantiated networks where
+                          the name is the key
+    :param routers_dict: the dictionary of newly instantiated routers 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)
+        if floating_ips:
+            for key, vm_creator in vm_dict.items():
+                fip = vm_creator.get_floating_ip()
+                if fip and fip.ip in floating_ips:
+                    if not vm_creator.cloud_init_complete(block=True):
+                        raise Exception(
+                            'Cannot apply playbooks as cloud-init has not '
+                            'completed')
+
+            variables = __get_variables(
+                ansible_config.get('variables'), os_creds, vm_dict, image_dict,
+                flavor_dict, networks_dict, routers_dict)
+
+            retval = ansible_utils.apply_playbook(
+                ansible_config['playbook_location'], floating_ips, remote_user,
+                private_key_filepath,
+                variables=variables,
+                proxy_setting=proxy_settings)
+            if retval != 0:
+                # Not a fatal type of event
+                logger.warning(
+                    'Unable to apply playbook found at location - %s',
+                    ansible_config.get('playbook_location'))
+            return retval
+
+
+def __get_connection_info(ansible_config, vm_dict):
+    """
+    Returns a tuple of data required for connecting to the running VMs
+    (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)
+    """
+    if ansible_config.get('hosts'):
+        hosts = ansible_config['hosts']
+        if len(hosts) > 0:
+            floating_ips = list()
+            remote_user = None
+            pk_file = None
+            proxy_settings = None
+            for host in hosts:
+                vm = vm_dict.get(host)
+                if vm:
+                    fip = vm.get_floating_ip()
+                    if fip:
+                        remote_user = vm.get_image_user()
+
+                        if fip:
+                            floating_ips.append(fip.ip)
+                        else:
+                            raise Exception(
+                                'Could not find floating IP for VM - ' +
+                                vm.name)
+
+                        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, pk_file, proxy_settings
+    return None
+
+
+def __get_variables(var_config, os_creds, vm_dict, image_dict, flavor_dict,
+                    networks_dict, routers_dict):
+    """
+    Returns a dictionary of substitution variables to be used for Ansible
+    templates
+    :param var_config: the variable configuration settings
+    :param os_creds: the OpenStack admin 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 networks_dict: the dictionary of newly instantiated networks where
+                          the name is the key
+    :param routers_dict: the dictionary of newly instantiated routers 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.items():
+            value = __get_variable_value(
+                value, os_creds, vm_dict, image_dict, flavor_dict,
+                networks_dict, routers_dict)
+            if key and value:
+                variables[key] = value
+                logger.info(
+                    "Set Jinga2 variable with key [%s] the value [%s]",
+                    key, value)
+            else:
+                raise Exception(
+                    'Key - [' + str(key) + '] or Value [' + str(value)
+                    + '] must not be None')
+        return variables
+    return None
+
+
+def __get_variable_value(var_config_values, os_creds, vm_dict, image_dict,
+                         flavor_dict, networks_dict, routers_dict):
+    """
+    Returns the associated variable value for use by Ansible for substitution
+    purposes
+    :param var_config_values: the configuration dictionary
+    :param os_creds: the OpenStack admin 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 networks_dict: the dictionary of newly instantiated networks where
+                          the name is the key
+    :param routers_dict: the dictionary of newly instantiated routers where
+                          the name is the key
+    :return:
+    """
+    if var_config_values['type'] == 'string':
+        return __get_string_variable_value(var_config_values)
+    if var_config_values['type'] == 'vm-attr':
+        return __get_vm_attr_variable_value(var_config_values, vm_dict)
+    if var_config_values['type'] == 'os_creds':
+        return __get_os_creds_variable_value(var_config_values, os_creds)
+    if var_config_values['type'] == 'network':
+        return __get_network_variable_value(var_config_values, networks_dict)
+    if var_config_values['type'] == 'router':
+        return __get_router_variable_value(var_config_values, routers_dict,
+                                           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':
+        return __get_flavor_variable_value(var_config_values, flavor_dict)
+    return None
+
+
+def __get_string_variable_value(var_config_values):
+    """
+    Returns the associated string value
+    :param var_config_values: the configuration dictionary
+    :return: the value contained in the dictionary with the key 'value'
+    """
+    return var_config_values['value']
+
+
+def __get_vm_attr_variable_value(var_config_values, vm_dict):
+    """
+    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
+    :return: the value
+    """
+    vm = vm_dict.get(var_config_values['vm_name'])
+    if vm:
+        if var_config_values['value'] == 'floating_ip':
+            return vm.get_floating_ip().ip
+        if var_config_values['value'] == 'image_user':
+            return vm.get_image_user()
+
+
+def __get_os_creds_variable_value(var_config_values, os_creds):
+    """
+    Returns the associated OS credentials value
+    :param var_config_values: the configuration dictionary
+    :param os_creds: the admin OpenStack OSCreds object
+    :return: the value
+    """
+    if os_creds:
+        if var_config_values['value'] == 'username':
+            logger.info("Returning OS username")
+            return os_creds.username
+        elif var_config_values['value'] == 'password':
+            logger.info("Returning OS password")
+            return os_creds.password
+        elif var_config_values['value'] == 'auth_url':
+            logger.info("Returning OS auth_url")
+            return os_creds.auth_url
+        elif var_config_values['value'] == 'project_name':
+            logger.info("Returning OS project_name")
+            return os_creds.project_name
+
+
+def __get_network_variable_value(var_config_values, networks_dict):
+    """
+    Returns the associated network value
+    :param var_config_values: the configuration dictionary
+    :param networks_dict: the dictionary containing all networks where the key
+                          is the network name
+    :return: the value
+    """
+    net_name = var_config_values.get('network_name')
+
+    if net_name and networks_dict.get(net_name):
+        network_creator = networks_dict[net_name]
+
+        if 'subnet_name' in var_config_values:
+            subnet_name = var_config_values.get('subnet_name')
+            if subnet_name:
+                for subnet in network_creator.get_network().subnets:
+                    if subnet_name == subnet.name:
+                        if 'value' in var_config_values:
+                            if 'gateway_ip' == var_config_values['value']:
+                                return subnet.gateway_ip
+                            if 'ip_range' == var_config_values['value']:
+                                return subnet.start + ' ' + subnet.end
+                            if 'cidr_ip' == var_config_values['value']:
+                                cidr_split = subnet.cidr.split('/')
+                                return cidr_split[0]
+                            if 'netmask' == var_config_values['value']:
+                                cidr_split = subnet.cidr.split('/')
+                                cidr_bits = 32 - int(cidr_split[1])
+                                netmask = socket.inet_ntoa(
+                                    struct.pack(
+                                        '!I', (1 << 32) - (1 << cidr_bits)))
+                                return netmask
+                            if 'broadcast_ip' == var_config_values['value']:
+                                end_split = subnet.end.split('.')
+                                broadcast_ip = (
+                                    end_split[0] + '.' + end_split[1] + '.'
+                                    + end_split[2] + '.255')
+                                return broadcast_ip
+
+
+def __get_router_variable_value(var_config_values, routers_dict, os_creds):
+    """
+    Returns the associated network value
+    :param var_config_values: the configuration dictionary
+    :param routers_dict: the dictionary containing all networks where the key
+                          is the network name
+    :param os_creds: the admin OpenStack credentials
+    :return: the value
+    """
+    router_name = var_config_values.get('router_name')
+    router_creator = routers_dict[router_name]
+
+    if router_creator:
+        if 'external_fixed_ip' == var_config_values.get('attr'):
+            neutron = neutron_utils.neutron_client(os_creds)
+            ext_nets = neutron_utils.get_external_networks(neutron)
+
+            subnet_name = var_config_values.get('subnet_name')
+
+            for ext_net in ext_nets:
+                for subnet in ext_net.subnets:
+                    if subnet_name == subnet.name:
+                        router = router_creator.get_router()
+                        for fixed_ips in router.external_fixed_ips:
+                            if subnet.id == fixed_ips['subnet_id']:
+                                return fixed_ips['ip_address']
+
+
+def __get_vm_port_variable_value(var_config_values, vm_dict):
+    """
+    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
+    :return: the value
+    """
+    port_name = var_config_values.get('port_name')
+    vm_name = var_config_values.get('vm_name')
+
+    if port_name and vm_name:
+        vm = vm_dict.get(vm_name)
+        if vm:
+            for vm_port in vm.get_vm_inst().ports:
+                if vm_port.name == port_name:
+                    port_value_id = var_config_values.get('port_value')
+                    if port_value_id:
+                        if port_value_id == 'mac_address':
+                            return vm_port.mac_address
+                        if port_value_id == 'ip_address':
+                            return vm_port.ips[0]['ip_address']
+
+
+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
+    :return: the value
+    """
+    if image_dict:
+        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'):
+                    return image_creator.get_image().id
+                if (var_config_values.get('value')
+                        and var_config_values['value'] == 'user'):
+                    return image_creator.image_settings.image_user
+
+
+def __get_flavor_variable_value(var_config_values, flavor_dict):
+    """
+    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
+    :return: the value or None
+    """
+    if flavor_dict:
+        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'):
+                    return flavor_creator.get_flavor().id
+
+
+def __cleanup(creators, clean_image=False):
+    """
+    Cleans up environment
+    :param creators: the list of creators by type
+    :param clean_image: when true
+    :return:
+    """
+    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)):
+                creator.clean()
diff --git a/snaps/provisioning/ansible_pb/__init__.py b/snaps/provisioning/ansible_pb/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/snaps/provisioning/ansible_pb/centos-network-setup/__init__.py b/snaps/provisioning/ansible_pb/centos-network-setup/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/snaps/provisioning/ansible_pb/centos-network-setup/playbooks/__init__.py b/snaps/provisioning/ansible_pb/centos-network-setup/playbooks/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/snaps/provisioning/ansible_pb/centos-network-setup/playbooks/configure_host.yml b/snaps/provisioning/ansible_pb/centos-network-setup/playbooks/configure_host.yml
deleted file mode 100644 (file)
index 8df03cb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
-#                    and others.  All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
----
-- name: Configure NIC
-  hosts: all
-  become: yes
-  become_method: sudo
-  become_user: root
-
-  tasks:
-   - name: Setup /etc/sysconfig/network-scripts/ifcfg-eth1 file
-     action: template owner=root group=root mode=644 src=../templates/ifcfg-interface dest=/etc/sysconfig/network-scripts/ifcfg-{{nic_name}}
-   - name : Restart Network
-     command: systemctl restart network
\ No newline at end of file
diff --git a/snaps/provisioning/ansible_pb/centos-network-setup/templates/ifcfg-interface b/snaps/provisioning/ansible_pb/centos-network-setup/templates/ifcfg-interface
deleted file mode 100644 (file)
index 47aa3fa..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-DEVICE={{ nic_name }}
-NAME={{ nic_name }}
-IPADDR={{ nic_ip }}
-
-DEFROUTE=no
-NETMASK=255.255.255.0
-NM_CONTROLLED=no
-IPV6INIT=yes
-IPV6_AUTOCONF=yes
-IPV6_DEFROUTE=yes
-IPV6_PEERDNS=yes
-IPV6_PEERROUTES=yes
-IPV6_FAILURE_FATAL=no
-ONBOOT=yes
\ No newline at end of file
diff --git a/snaps/provisioning/ansible_pb/ubuntu-network-setup/__init__.py b/snaps/provisioning/ansible_pb/ubuntu-network-setup/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/snaps/provisioning/ansible_pb/ubuntu-network-setup/playbooks/__init__.py b/snaps/provisioning/ansible_pb/ubuntu-network-setup/playbooks/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/snaps/provisioning/ansible_pb/ubuntu-network-setup/playbooks/configure_host.yml b/snaps/provisioning/ansible_pb/ubuntu-network-setup/playbooks/configure_host.yml
deleted file mode 100644 (file)
index 5d43f96..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
-#                    and others.  All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
----
-- name: Configure NIC
-  hosts: all
-  become: yes
-  become_method: sudo
-  become_user: root
-
-  tasks:
-   - name: Setup /etc/network/interfaces.d/{{nic_name}}.cfg file
-     action: template owner=root group=root mode=644 src=../templates/ethN.cfg dest=/etc/network/interfaces.d/{{nic_name}}.cfg
-   - name : Restart Network
-     command: service networking restart
\ No newline at end of file
diff --git a/snaps/provisioning/ansible_pb/ubuntu-network-setup/templates/ethN.cfg b/snaps/provisioning/ansible_pb/ubuntu-network-setup/templates/ethN.cfg
deleted file mode 100644 (file)
index 3fa7708..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-auto {{ nic_name }}
-iface {{ nic_name }} inet dhcp
index 4f1f65e..7600002 100644 (file)
@@ -241,6 +241,9 @@ class AnsibleProvisioningTests(OSIntegrationTestCase):
         # Block until VM's ssh port has been opened
         self.assertTrue(self.inst_creator.vm_ssh_active(block=True))
 
+        # Block until cloud-init has completed
+        self.assertTrue(self.inst_creator.cloud_init_complete(block=True))
+
         ssh_client = self.inst_creator.ssh_client()
         self.assertIsNotNone(ssh_client)
 
@@ -310,6 +313,9 @@ class AnsibleProvisioningTests(OSIntegrationTestCase):
         # Block until VM's ssh port has been opened
         self.assertTrue(self.inst_creator.vm_ssh_active(block=True))
 
+        # Block until cloud-init has completed
+        self.assertTrue(self.inst_creator.cloud_init_complete(block=True))
+
         # Apply Security Group
         self.inst_creator.add_security_group(
             self.sec_grp_creator.get_security_group())
index ec8196d..1990cd6 100644 (file)
@@ -65,13 +65,13 @@ from snaps.openstack.tests.create_image_tests import (
     CreateImageSuccessTests, CreateImageNegativeTests,
     CreateMultiPartImageTests)
 from snaps.openstack.tests.create_instance_tests import (
-    CreateInstanceSingleNetworkTests, CreateInstancePubPrivNetTests,
-    CreateInstanceOnComputeHost, CreateInstanceSimpleTests,
-    FloatingIpSettingsUnitTests, InstanceSecurityGroupTests,
-    VmInstanceSettingsUnitTests, CreateInstancePortManipulationTests,
-    SimpleHealthCheck, CreateInstanceFromThreePartImage,
-    CreateInstanceMockOfflineTests, CreateInstanceTwoNetTests,
-    CreateInstanceVolumeTests, CreateInstanceIPv6NetworkTests)
+    CreateInstanceSingleNetworkTests,  CreateInstanceOnComputeHost,
+    CreateInstanceSimpleTests, FloatingIpSettingsUnitTests,
+    InstanceSecurityGroupTests, VmInstanceSettingsUnitTests,
+    CreateInstancePortManipulationTests, SimpleHealthCheck,
+    CreateInstanceFromThreePartImage, CreateInstanceMockOfflineTests,
+    CreateInstanceTwoNetTests, CreateInstanceVolumeTests,
+    CreateInstanceIPv6NetworkTests)
 from snaps.openstack.tests.create_keypairs_tests import (
     CreateKeypairsTests, KeypairSettingsUnitTests, CreateKeypairsCleanupTests)
 from snaps.openstack.tests.create_network_tests import (
@@ -637,11 +637,6 @@ def add_openstack_integration_tests(suite, os_creds, ext_net_name,
             ext_net_name=ext_net_name, use_keystone=use_keystone,
             flavor_metadata=flavor_metadata, image_metadata=image_metadata,
             log_level=log_level))
-        suite.addTest(OSIntegrationTestCase.parameterize(
-            CreateInstancePubPrivNetTests, os_creds=os_creds,
-            ext_net_name=ext_net_name, use_keystone=use_keystone,
-            flavor_metadata=flavor_metadata, image_metadata=image_metadata,
-            log_level=log_level))
         suite.addTest(OSIntegrationTestCase.parameterize(
             AnsibleProvisioningTests, os_creds=os_creds,
             ext_net_name=ext_net_name, use_keystone=use_keystone,