diff options
-rw-r--r-- | examples/launch.py | 13 | ||||
-rw-r--r-- | snaps/domain/creator.py | 44 | ||||
-rw-r--r-- | snaps/openstack/create_flavor.py | 40 | ||||
-rw-r--r-- | snaps/openstack/create_image.py | 53 | ||||
-rw-r--r-- | snaps/openstack/create_instance.py | 111 | ||||
-rw-r--r-- | snaps/openstack/create_keypairs.py | 42 | ||||
-rw-r--r-- | snaps/openstack/create_network.py | 81 | ||||
-rw-r--r-- | snaps/openstack/create_project.py | 65 | ||||
-rw-r--r-- | snaps/openstack/create_router.py | 114 | ||||
-rw-r--r-- | snaps/openstack/create_security_group.py | 85 | ||||
-rw-r--r-- | snaps/openstack/create_stack.py | 56 | ||||
-rw-r--r-- | snaps/openstack/create_user.py | 53 | ||||
-rw-r--r-- | snaps/openstack/openstack_creator.py | 110 | ||||
-rw-r--r-- | snaps/openstack/utils/deploy_utils.py | 70 | ||||
-rw-r--r-- | snaps/openstack/utils/tests/heat_utils_tests.py | 2 |
15 files changed, 603 insertions, 336 deletions
diff --git a/examples/launch.py b/examples/launch.py index f5d3bea..76353a2 100644 --- a/examples/launch.py +++ b/examples/launch.py @@ -164,7 +164,11 @@ def __create_instances(os_creds_dict, creator_class, config_class, config, creator = creator_class( __get_creds(os_creds_dict, os_users_dict, inst_config), config_class(**inst_config)) - creator.create(cleanup=cleanup) + + if cleanup: + creator.initialize() + else: + creator.create() out[inst_config['name']] = creator logger.info('Created configured %s', config_key) except Exception as e: @@ -211,7 +215,7 @@ def __create_vm_instances(os_creds_dict, os_users_dict, instances_config, instance_settings, image_creator.image_settings, keypair_creator=keypairs_dict[kp_name], - cleanup=cleanup) + init_only=cleanup) else: raise Exception('Image creator instance not found.' ' Cannot instantiate') @@ -669,7 +673,6 @@ def main(arguments): logger.error( 'Unexpected error deploying environment. Rolling back due' ' to - ' + str(e)) - # __cleanup(creators) raise # Must enter either block @@ -701,8 +704,8 @@ def main(arguments): 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): + if ((isinstance(creator, OpenStackImage) and clean_image) + or not isinstance(creator, OpenStackImage)): try: creator.clean() except Exception as e: diff --git a/snaps/domain/creator.py b/snaps/domain/creator.py new file mode 100644 index 0000000..cbfd030 --- /dev/null +++ b/snaps/domain/creator.py @@ -0,0 +1,44 @@ +# Copyright (c) 2017 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. + +__author__ = 'spisarski' + + +class CloudObject(object): + """ + Base class for all cloud objects to create or manage + """ + + def initialize(self): + """ + Method used to initialize object via queries + :return: + """ + raise NotImplementedError('Please implement this abstract method') + + def create(self): + """ + Method to be called to create this cloud object. First line should + generally be a call to initialize() + :return: + """ + raise NotImplementedError('Please implement this abstract method') + + def clean(self): + """ + Method used to delete objects on the cloud + :return: + """ + raise NotImplementedError('Please implement this abstract method') diff --git a/snaps/openstack/create_flavor.py b/snaps/openstack/create_flavor.py index ec4c765..1479bb0 100644 --- a/snaps/openstack/create_flavor.py +++ b/snaps/openstack/create_flavor.py @@ -16,6 +16,7 @@ import logging from novaclient.exceptions import NotFound +from snaps.openstack.openstack_creator import OpenStackComputeObject from snaps.openstack.utils import nova_utils __author__ = 'spisarski' @@ -26,7 +27,7 @@ MEM_PAGE_SIZE_ANY = {'hw:mem_page_size': 'any'} MEM_PAGE_SIZE_LARGE = {'hw:mem_page_size': 'large'} -class OpenStackFlavor: +class OpenStackFlavor(OpenStackComputeObject): """ Class responsible for creating a user in OpenStack """ @@ -38,29 +39,36 @@ class OpenStackFlavor: :param flavor_settings: The flavor settings :return: """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.flavor_settings = flavor_settings self.__flavor = None - self.__nova = None - def create(self, cleanup=False): + def initialize(self): """ - Creates the image in OpenStack if it does not already exist - :param cleanup: Denotes whether or not this is being called for cleanup - or not - :return: The OpenStack flavor object + Loads the existing OpenStack flavor + :return: The Flavor domain object or None """ - self.__nova = nova_utils.nova_client(self.__os_creds) + super(self.__class__, self).initialize() + self.__flavor = nova_utils.get_flavor_by_name( - self.__nova, self.flavor_settings.name) + self._nova, self.flavor_settings.name) if self.__flavor: - logger.info( - 'Found flavor with name - ' + self.flavor_settings.name) - elif not cleanup: + logger.info('Found flavor with name - %s', + self.flavor_settings.name) + return self.__flavor + + def create(self): + """ + Creates the image in OpenStack if it does not already exist + :return: The OpenStack flavor object + """ + self.initialize() + if not self.__flavor: self.__flavor = nova_utils.create_flavor( - self.__nova, self.flavor_settings) + self._nova, self.flavor_settings) if self.flavor_settings.metadata: - nova_utils.set_flavor_keys(self.__nova, self.__flavor, + nova_utils.set_flavor_keys(self._nova, self.__flavor, self.flavor_settings.metadata) else: logger.info('Did not create flavor due to cleanup mode') @@ -74,7 +82,7 @@ class OpenStackFlavor: """ if self.__flavor: try: - nova_utils.delete_flavor(self.__nova, self.__flavor) + nova_utils.delete_flavor(self._nova, self.__flavor) except NotFound: pass diff --git a/snaps/openstack/create_image.py b/snaps/openstack/create_image.py index 537824d..3024717 100644 --- a/snaps/openstack/create_image.py +++ b/snaps/openstack/create_image.py @@ -17,6 +17,7 @@ from glanceclient.exc import HTTPNotFound import logging import time +from snaps.openstack.openstack_creator import OpenStackCloudObject from snaps.openstack.utils import glance_utils __author__ = 'spisarski' @@ -28,9 +29,9 @@ POLL_INTERVAL = 3 STATUS_ACTIVE = 'active' -class OpenStackImage: +class OpenStackImage(OpenStackCloudObject): """ - Class responsible for creating an image in OpenStack + Class responsible for managing an image in OpenStack """ def __init__(self, os_creds, image_settings): @@ -40,22 +41,20 @@ class OpenStackImage: :param image_settings: The image settings :return: """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.image_settings = image_settings self.__image = None self.__kernel_image = None self.__ramdisk_image = None self.__glance = None - def create(self, cleanup=False): + def initialize(self): """ - Creates the image in OpenStack if it does not already exist and returns - the domain Image object - :param cleanup: Denotes whether or not this is being called for cleanup - or not - :return: The OpenStack Image object + Loads the existing Image + :return: The Image domain object or None """ - self.__glance = glance_utils.glance_client(self.__os_creds) + 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: @@ -66,15 +65,31 @@ class OpenStackImage: raise ImageCreationError( 'Image with does not exist with name - ' + self.image_settings.name) - elif not cleanup: + + if self.image_settings.kernel_image_settings: + 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, + image_settings=self.image_settings.ramdisk_image_settings) + + return self.__image + + def create(self): + """ + Creates the image in OpenStack if it does not already exist and returns + the domain Image object + :return: The Image domain object or None + """ + self.initialize() + + if not self.__image: extra_properties = self.image_settings.extra_properties or dict() if self.image_settings.kernel_image_settings: - self.__kernel_image = glance_utils.get_image( - self.__glance, - image_settings=self.image_settings.kernel_image_settings) - - if not self.__kernel_image and not cleanup: + if not self.__kernel_image: logger.info( 'Creating associated kernel image with name - %s', self.image_settings.kernel_image_settings.name) @@ -83,11 +98,7 @@ class OpenStackImage: self.image_settings.kernel_image_settings) extra_properties['kernel_id'] = self.__kernel_image.id if self.image_settings.ramdisk_image_settings: - self.__ramdisk_image = glance_utils.get_image( - self.__glance, - image_settings=self.image_settings.ramdisk_image_settings) - - if not self.__ramdisk_image and not cleanup: + if not self.__ramdisk_image: logger.info( 'Creating associated ramdisk image with name - %s', self.image_settings.ramdisk_image_settings.name) diff --git a/snaps/openstack/create_instance.py b/snaps/openstack/create_instance.py index 2fbeb79..3d55f42 100644 --- a/snaps/openstack/create_instance.py +++ b/snaps/openstack/create_instance.py @@ -19,6 +19,7 @@ from neutronclient.common.exceptions import PortNotFoundClient from novaclient.exceptions import NotFound from snaps.openstack.create_network import PortSettings +from snaps.openstack.openstack_creator import OpenStackComputeObject from snaps.openstack.utils import glance_utils from snaps.openstack.utils import neutron_utils from snaps.openstack.utils import nova_utils @@ -33,9 +34,9 @@ STATUS_ACTIVE = 'ACTIVE' STATUS_DELETED = 'DELETED' -class OpenStackVmInstance: +class OpenStackVmInstance(OpenStackComputeObject): """ - Class responsible for creating a VM instance in OpenStack + Class responsible for managing a VM instance in OpenStack """ def __init__(self, os_creds, instance_settings, image_settings, @@ -48,9 +49,8 @@ class OpenStackVmInstance: :param keypair_settings: The keypair metadata (Optional) :raises Exception """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) - self.__nova = None self.__neutron = None self.instance_settings = instance_settings @@ -65,28 +65,34 @@ class OpenStackVmInstance: # Note: this object does not change after the VM becomes active self.__vm = None - def create(self, cleanup=False, block=False): + def initialize(self): """ - Creates a VM instance - :param cleanup: When true, this object is initialized only via queries, - else objects will be created when the queries return - None. The name of this parameter should be changed to - something like 'readonly' as the same goes with all of - the other creator classes. + Loads the existing VMInst, Port, FloatingIps + :return: VMInst domain object + """ + super(self.__class__, self).initialize() + + self.__neutron = neutron_utils.neutron_client(self._os_creds) + + self.__ports = self.__query_ports(self.instance_settings.port_settings) + self.__lookup_existing_vm_by_name() + + def create(self, block=False): + """ + Creates a VM instance and associated objects unless they already exist :param block: Thread will block until instance has either become active, error, or timeout waiting. Additionally, when True, floating IPs will not be applied until VM is active. - :return: The VM reference object + :return: VMInst domain object """ - self.__nova = nova_utils.nova_client(self.__os_creds) - self.__neutron = neutron_utils.neutron_client(self.__os_creds) + self.initialize() - self.__ports = self.__setup_ports(self.instance_settings.port_settings, - cleanup) - self.__lookup_existing_vm_by_name() - if not self.__vm and not cleanup: + if len(self.__ports) == 0: + self.__ports = self.__create_ports(self.instance_settings.port_settings) + if not self.__vm: self.__create_vm(block) + return self.__vm def __lookup_existing_vm_by_name(self): @@ -96,7 +102,7 @@ class OpenStackVmInstance: within the project """ server = nova_utils.get_server( - self.__nova, vm_inst_settings=self.instance_settings) + self._nova, vm_inst_settings=self.instance_settings) if server: if server.name == self.instance_settings.name: self.__vm = server @@ -124,9 +130,9 @@ class OpenStackVmInstance: active, error, or timeout waiting. Floating IPs will be assigned after active when block=True """ - glance = glance_utils.glance_client(self.__os_creds) + glance = glance_utils.glance_client(self._os_creds) self.__vm = nova_utils.create_server( - self.__nova, self.__neutron, glance, self.instance_settings, + self._nova, self.__neutron, glance, self.instance_settings, self.image_settings, self.keypair_settings) logger.info('Created instance with name - %s', self.instance_settings.name) @@ -140,7 +146,7 @@ class OpenStackVmInstance: # Create server should do this but found it needed to occur here for sec_grp_name in self.instance_settings.security_group_names: if self.vm_active(block=True): - nova_utils.add_security_group(self.__nova, self.__vm, + nova_utils.add_security_group(self._nova, self.__vm, sec_grp_name) else: raise VmInstanceCreationError( @@ -235,7 +241,7 @@ class OpenStackVmInstance: try: logger.info( 'Deleting VM instance - ' + self.instance_settings.name) - nova_utils.delete_vm_instance(self.__nova, self.__vm) + nova_utils.delete_vm_instance(self._nova, self.__vm) except Exception as e: logger.error('Error deleting VM - %s', e) @@ -258,12 +264,11 @@ class OpenStackVmInstance: 'Unexpected error while checking VM instance status - %s', e) - def __setup_ports(self, port_settings, cleanup): + def __query_ports(self, port_settings): """ - Returns the previously configured ports or creates them if they do not + Returns the previously configured ports or an empty list if none exist :param port_settings: A list of PortSetting objects - :param cleanup: When true, only perform lookups for OpenStack objects. :return: a list of OpenStack port tuples where the first member is the port name and the second is the port object """ @@ -272,22 +277,28 @@ class OpenStackVmInstance: for port_setting in port_settings: port = neutron_utils.get_port( self.__neutron, port_settings=port_setting) - if not port: - network = neutron_utils.get_network( - self.__neutron, network_name=port_setting.network_name) - net_ports = neutron_utils.get_ports(self.__neutron, network) - for net_port in net_ports: - if port_setting.mac_address == net_port.mac_address: - port = net_port - break if port: ports.append((port_setting.name, port)) - elif not cleanup: - # Exception will be raised when port with same name already - # exists - ports.append( - (port_setting.name, neutron_utils.create_port( - self.__neutron, self.__os_creds, port_setting))) + + return ports + + def __create_ports(self, port_settings): + """ + Returns the previously configured ports or creates them if they do not + exist + :param port_settings: A list of PortSetting objects + :return: a list of OpenStack port tuples where the first member is the + port name and the second is the port object + """ + ports = list() + + for port_setting in port_settings: + port = neutron_utils.get_port( + self.__neutron, port_settings=port_setting) + if not port: + port = neutron_utils.create_port(self.__neutron, self._os_creds, port_setting) + if port: + ports.append((port_setting.name, port)) return ports @@ -316,7 +327,7 @@ class OpenStackVmInstance: logger.debug('Attempting to add floating IP to instance') try: nova_utils.add_floating_ip_to_server( - self.__nova, self.__vm, floating_ip, ip) + self._nova, self.__vm, floating_ip, ip) logger.info( 'Added floating IP %s to port IP %s on instance %s', floating_ip.ip, ip, self.instance_settings.name) @@ -341,21 +352,21 @@ class OpenStackVmInstance: Returns the OpenStack credentials used to create these objects :return: the credentials """ - return self.__os_creds + return self._os_creds def get_vm_inst(self): """ Returns the latest version of this server object from OpenStack :return: Server object """ - return nova_utils.get_server_object_by_id(self.__nova, self.__vm.id) + return nova_utils.get_server_object_by_id(self._nova, self.__vm.id) def get_console_output(self): """ Returns the vm console object for parsing logs :return: the console output object """ - return nova_utils.get_server_console_output(self.__nova, self.__vm) + return nova_utils.get_server_console_output(self._nova, self.__vm) def get_port_ip(self, port_name, subnet_name=None): """ @@ -415,7 +426,7 @@ class OpenStackVmInstance: Returns a dictionary of a VMs info as returned by OpenStack :return: a dict() """ - return nova_utils.get_server_info(self.__nova, self.__vm) + return nova_utils.get_server_info(self._nova, self.__vm) def config_nics(self): """ @@ -490,7 +501,7 @@ class OpenStackVmInstance: return ansible_utils.apply_playbook( pb_file_loc, [self.get_floating_ip(fip_name=fip_name).ip], self.get_image_user(), self.keypair_settings.private_filepath, - variables, self.__os_creds.proxy_settings) + variables, self._os_creds.proxy_settings) def get_image_user(self): """ @@ -582,7 +593,7 @@ class OpenStackVmInstance: else: return False - status = nova_utils.get_server_status(self.__nova, self.__vm) + status = nova_utils.get_server_status(self._nova, self.__vm) if not status: logger.warning('Cannot find instance with id - ' + self.__vm.id) return False @@ -667,7 +678,7 @@ class OpenStackVmInstance: self.__get_first_provisioning_floating_ip().ip, self.get_image_user(), self.keypair_settings.private_filepath, - proxy_settings=self.__os_creds.proxy_settings) + proxy_settings=self._os_creds.proxy_settings) else: logger.warning( 'Cannot return an SSH client. No Floating IP configured') @@ -685,7 +696,7 @@ class OpenStackVmInstance: return False try: - nova_utils.add_security_group(self.__nova, self.get_vm_inst(), + nova_utils.add_security_group(self._nova, self.get_vm_inst(), security_group.name) return True except NotFound as e: @@ -705,7 +716,7 @@ class OpenStackVmInstance: return False try: - nova_utils.remove_security_group(self.__nova, self.get_vm_inst(), + nova_utils.remove_security_group(self._nova, self.get_vm_inst(), security_group) return True except NotFound as e: diff --git a/snaps/openstack/create_keypairs.py b/snaps/openstack/create_keypairs.py index d0b69cd..3869afc 100644 --- a/snaps/openstack/create_keypairs.py +++ b/snaps/openstack/create_keypairs.py @@ -19,6 +19,7 @@ from neutronclient.common.utils import str2bool from novaclient.exceptions import NotFound from snaps import file_utils +from snaps.openstack.openstack_creator import OpenStackComputeObject from snaps.openstack.utils import nova_utils __author__ = 'spisarski' @@ -26,9 +27,9 @@ __author__ = 'spisarski' logger = logging.getLogger('OpenStackKeypair') -class OpenStackKeypair: +class OpenStackKeypair(OpenStackComputeObject): """ - Class responsible for creating a keypair in OpenStack + Class responsible for managing a keypair in OpenStack """ def __init__(self, os_creds, keypair_settings): @@ -37,38 +38,43 @@ class OpenStackKeypair: :param os_creds: The credentials to connect with OpenStack :param keypair_settings: The settings used to create a keypair """ - self.__nova = None - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.keypair_settings = keypair_settings - self.__nova = nova_utils.nova_client(os_creds) self.__delete_keys_on_clean = True # Attributes instantiated on create() self.__keypair = None - def create(self, cleanup=False): + def initialize(self): """ - Responsible for creating the keypair object. - :param cleanup: Denotes whether or not this is being called for cleanup - or not + Loads the existing OpenStack Keypair + :return: The Keypair domain object or None """ - self.__nova = nova_utils.nova_client(self.__os_creds) - - logger.info('Creating keypair %s...' % self.keypair_settings.name) + super(self.__class__, self).initialize() try: self.__keypair = nova_utils.get_keypair_by_name( - self.__nova, self.keypair_settings.name) + self._nova, self.keypair_settings.name) + return self.__keypair except Exception as e: logger.warn('Cannot load existing keypair - %s', e) - return - if not self.__keypair and not cleanup: + def create(self): + """ + Responsible for creating the keypair object. + :return: The Keypair domain object or None + """ + self.initialize() + + if not self.__keypair: + logger.info('Creating keypair %s...' % self.keypair_settings.name) + if self.keypair_settings.public_filepath and os.path.isfile( self.keypair_settings.public_filepath): logger.info("Uploading existing keypair") self.__keypair = nova_utils.upload_keypair_file( - self.__nova, self.keypair_settings.name, + self._nova, self.keypair_settings.name, self.keypair_settings.public_filepath) if self.keypair_settings.delete_on_clean is not None: @@ -80,7 +86,7 @@ class OpenStackKeypair: logger.info("Creating new keypair") keys = nova_utils.create_keys(self.keypair_settings.key_size) self.__keypair = nova_utils.upload_keypair( - self.__nova, self.keypair_settings.name, + self._nova, self.keypair_settings.name, nova_utils.public_key_openssh(keys)) file_utils.save_keys_to_files( keys, self.keypair_settings.public_filepath, @@ -104,7 +110,7 @@ class OpenStackKeypair: """ if self.__keypair: try: - nova_utils.delete_keypair(self.__nova, self.__keypair) + nova_utils.delete_keypair(self._nova, self.__keypair) except NotFound: pass self.__keypair = None diff --git a/snaps/openstack/create_network.py b/snaps/openstack/create_network.py index 166a682..437f294 100644 --- a/snaps/openstack/create_network.py +++ b/snaps/openstack/create_network.py @@ -15,6 +15,8 @@ import logging from neutronclient.common.exceptions import NotFound + +from snaps.openstack.openstack_creator import OpenStackNetworkObject from snaps.openstack.utils import keystone_utils, neutron_utils __author__ = 'spisarski' @@ -22,9 +24,9 @@ __author__ = 'spisarski' logger = logging.getLogger('OpenStackNetwork') -class OpenStackNetwork: +class OpenStackNetwork(OpenStackNetworkObject): """ - Class responsible for creating a network in OpenStack + Class responsible for managing a network in OpenStack """ def __init__(self, os_creds, network_settings): @@ -33,56 +35,61 @@ class OpenStackNetwork: :param os_creds: The credentials to connect with OpenStack :param network_settings: The settings used to create a network """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.network_settings = network_settings - self.__neutron = None # Attributes instantiated on create() self.__network = None self.__subnets = list() - def create(self, cleanup=False): + def initialize(self): + """ + Loads the existing OpenStack network/subnet + :return: The Network domain object or None + """ + super(self.__class__, self).initialize() + + self.__network = neutron_utils.get_network( + self._neutron, network_settings=self.network_settings, + project_id=self.network_settings.get_project_id(self._os_creds)) + + if self.__network: + for subnet_setting in self.network_settings.subnet_settings: + sub_inst = neutron_utils.get_subnet( + self._neutron, subnet_settings=subnet_setting) + if sub_inst: + self.__subnets.append(sub_inst) + logger.debug( + "Subnet '%s' created successfully" % sub_inst.id) + + return self.__network + + def create(self): """ Responsible for creating not only the network but then a private subnet, router, and an interface to the router. - :param cleanup: When true, only perform lookups for OpenStack objects. - :return: the created network object or None + :return: the Network domain object """ - self.__neutron = neutron_utils.neutron_client(self.__os_creds) - - logger.info( - 'Creating neutron network %s...' % self.network_settings.name) - net_inst = neutron_utils.get_network( - self.__neutron, network_settings=self.network_settings, - project_id=self.network_settings.get_project_id(self.__os_creds)) - if net_inst: - self.__network = net_inst - else: - if not cleanup: - self.__network = neutron_utils.create_network( - self.__neutron, self.__os_creds, self.network_settings) - else: - logger.info( - 'Network does not exist and will not create as in cleanup' - ' mode') - return - logger.debug( - "Network '%s' created successfully" % self.__network.id) + self.initialize() + + if not self.__network: + self.__network = neutron_utils.create_network( + self._neutron, self._os_creds, self.network_settings) + logger.debug( + "Network '%s' created successfully" % self.__network.id) - logger.debug('Creating Subnets....') for subnet_setting in self.network_settings.subnet_settings: sub_inst = neutron_utils.get_subnet( - self.__neutron, subnet_settings=subnet_setting) + self._neutron, subnet_settings=subnet_setting) + if not sub_inst: + sub_inst = neutron_utils.create_subnet( + self._neutron, subnet_setting, self._os_creds, + self.__network) if sub_inst: self.__subnets.append(sub_inst) logger.debug( "Subnet '%s' created successfully" % sub_inst.id) - else: - if not cleanup: - self.__subnets.append( - neutron_utils.create_subnet( - self.__neutron, subnet_setting, self.__os_creds, - self.__network)) return self.__network @@ -94,7 +101,7 @@ class OpenStackNetwork: try: logger.info( 'Deleting subnet with name ' + subnet.name) - neutron_utils.delete_subnet(self.__neutron, subnet) + neutron_utils.delete_subnet(self._neutron, subnet) except NotFound as e: logger.warning( 'Error deleting subnet with message - ' + str(e)) @@ -103,7 +110,7 @@ class OpenStackNetwork: if self.__network: try: - neutron_utils.delete_network(self.__neutron, self.__network) + neutron_utils.delete_network(self._neutron, self.__network) except NotFound: pass diff --git a/snaps/openstack/create_project.py b/snaps/openstack/create_project.py index 38505ad..0cf6d4a 100644 --- a/snaps/openstack/create_project.py +++ b/snaps/openstack/create_project.py @@ -16,6 +16,7 @@ import logging from keystoneclient.exceptions import NotFound, Conflict +from snaps.openstack.openstack_creator import OpenStackIdentityObject from snaps.openstack.utils import keystone_utils, neutron_utils, nova_utils __author__ = 'spisarski' @@ -23,9 +24,9 @@ __author__ = 'spisarski' logger = logging.getLogger('create_image') -class OpenStackProject: +class OpenStackProject(OpenStackIdentityObject): """ - Class responsible for creating a project/project in OpenStack + Class responsible for managing a project/project in OpenStack """ def __init__(self, os_creds, project_settings): @@ -35,38 +36,42 @@ class OpenStackProject: :param project_settings: The project's settings :return: """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.project_settings = project_settings self.__project = None self.__role = None - self.__keystone = None self.__role_name = self.project_settings.name + '-role' - def create(self, cleanup=False): + def initialize(self): """ - Creates the image in OpenStack if it does not already exist - :param cleanup: Denotes whether or not this is being called for cleanup - :return: The OpenStack Image object + Loads the existing Project object if it exists + :return: The Project domain object """ - self.__keystone = keystone_utils.keystone_client(self.__os_creds) + super(self.__class__, self).initialize() + self.__project = keystone_utils.get_project( - keystone=self.__keystone, project_settings=self.project_settings) - if self.__project: - logger.info( - 'Found project with name - ' + self.project_settings.name) - elif not cleanup: + keystone=self._keystone, project_settings=self.project_settings) + return self.__project + + def create(self): + """ + Creates a Project/Tenant in OpenStack if it does not already exist + :return: The Project domain object + """ + self.initialize() + + if not self.__project: self.__project = keystone_utils.create_project( - self.__keystone, self.project_settings) + self._keystone, self.project_settings) for username in self.project_settings.users: - user = keystone_utils.get_user(self.__keystone, username) + user = keystone_utils.get_user(self._keystone, username) if user: try: self.assoc_user(user) except Conflict as e: logger.warn('Unable to associate user %s due to %s', user.name, e) - else: - logger.info('Did not create image due to cleanup mode') return self.__project @@ -77,7 +82,7 @@ class OpenStackProject: """ if self.__project: # Delete security group 'default' if exists - neutron = neutron_utils.neutron_client(self.__os_creds) + neutron = neutron_utils.neutron_client(self._os_creds) default_sec_grp = neutron_utils.get_security_group( neutron, sec_grp_name='default', project_id=self.__project.id) @@ -90,23 +95,23 @@ class OpenStackProject: # Delete Project try: - keystone_utils.delete_project(self.__keystone, self.__project) + keystone_utils.delete_project(self._keystone, self.__project) except NotFound: pass self.__project = None if self.__role: try: - keystone_utils.delete_role(self.__keystone, self.__role) + keystone_utils.delete_role(self._keystone, self.__role) except NotFound: pass self.__project = None # Final role check in case init was done from an existing instance role = keystone_utils.get_role_by_name( - self.__keystone, self.__role_name) + self._keystone, self.__role_name) if role: - keystone_utils.delete_role(self.__keystone, role) + keystone_utils.delete_role(self._keystone, role) def get_project(self): """ @@ -123,12 +128,12 @@ class OpenStackProject: """ if not self.__role: self.__role = keystone_utils.get_role_by_name( - self.__keystone, self.__role_name) + self._keystone, self.__role_name) if not self.__role: self.__role = keystone_utils.create_role( - self.__keystone, self.__role_name) + self._keystone, self.__role_name) - keystone_utils.grant_user_role_to_project(self.__keystone, self.__role, + keystone_utils.grant_user_role_to_project(self._keystone, self.__role, user, self.__project) def get_compute_quotas(self): @@ -136,7 +141,7 @@ class OpenStackProject: Returns the compute quotas as an instance of the ComputeQuotas class :return: """ - nova = nova_utils.nova_client(self.__os_creds) + nova = nova_utils.nova_client(self._os_creds) return nova_utils.get_compute_quotas(nova, self.__project.id) def get_network_quotas(self): @@ -144,7 +149,7 @@ class OpenStackProject: Returns the network quotas as an instance of the NetworkQuotas class :return: """ - neutron = neutron_utils.neutron_client(self.__os_creds) + neutron = neutron_utils.neutron_client(self._os_creds) return neutron_utils.get_network_quotas(neutron, self.__project.id) def update_compute_quotas(self, compute_quotas): @@ -152,7 +157,7 @@ class OpenStackProject: Updates the compute quotas for this project :param compute_quotas: a ComputeQuotas object. """ - nova = nova_utils.nova_client(self.__os_creds) + nova = nova_utils.nova_client(self._os_creds) nova_utils.update_quotas(nova, self.__project.id, compute_quotas) def update_network_quotas(self, network_quotas): @@ -160,7 +165,7 @@ class OpenStackProject: Updates the network quotas for this project :param network_quotas: a NetworkQuotas object. """ - neutron = neutron_utils.neutron_client(self.__os_creds) + neutron = neutron_utils.neutron_client(self._os_creds) neutron_utils.update_quotas(neutron, self.__project.id, network_quotas) diff --git a/snaps/openstack/create_router.py b/snaps/openstack/create_router.py index ef27fab..98e3e14 100644 --- a/snaps/openstack/create_router.py +++ b/snaps/openstack/create_router.py @@ -16,6 +16,7 @@ import logging from neutronclient.common.exceptions import NotFound from snaps.openstack.create_network import PortSettings +from snaps.openstack.openstack_creator import OpenStackNetworkObject from snaps.openstack.utils import neutron_utils, keystone_utils __author__ = 'spisarski' @@ -23,9 +24,9 @@ __author__ = 'spisarski' logger = logging.getLogger('OpenStackNetwork') -class OpenStackRouter: +class OpenStackRouter(OpenStackNetworkObject): """ - Class responsible for creating a router in OpenStack + Class responsible for managing a router in OpenStack """ def __init__(self, os_creds, router_settings): @@ -36,13 +37,12 @@ class OpenStackRouter: (must be an instance of the RouterSettings class) """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) if not router_settings: raise RouterCreationError('router_settings is required') self.router_settings = router_settings - self.__neutron = None # Attributes instantiated on create() self.__router = None @@ -53,64 +53,84 @@ class OpenStackRouter: # interfaces are the value self.__ports = list() - def create(self, cleanup=False): + def initialize(self): """ - Responsible for creating the router. - :param cleanup: When true, only perform lookups for OpenStack objects. - :return: the router object + Loads the existing router. + :return: the Router domain object """ - self.__neutron = neutron_utils.neutron_client(self.__os_creds) - - logger.debug( - 'Creating Router with name - ' + self.router_settings.name) - existing = False - router_inst = neutron_utils.get_router( - self.__neutron, router_settings=self.router_settings) - if router_inst: - self.__router = router_inst - existing = True - else: - if not cleanup: - self.__router = neutron_utils.create_router( - self.__neutron, self.__os_creds, self.router_settings) + super(self.__class__, self).initialize() + + self.__router = neutron_utils.get_router( + self._neutron, router_settings=self.router_settings) for internal_subnet_name in self.router_settings.internal_subnets: internal_subnet = neutron_utils.get_subnet( - self.__neutron, subnet_name=internal_subnet_name) + self._neutron, subnet_name=internal_subnet_name) if internal_subnet: self.__internal_subnets.append(internal_subnet) - if internal_subnet and not cleanup and not existing: - logger.debug('Adding router to subnet...') - router_intf = neutron_utils.add_interface_router( - self.__neutron, self.__router, subnet=internal_subnet) - self.__internal_router_interface = router_intf else: raise RouterCreationError( 'Subnet not found with name ' + internal_subnet_name) for port_setting in self.router_settings.port_settings: port = neutron_utils.get_port( - self.__neutron, port_settings=port_setting) - logger.info( - 'Retrieved port %s for router - %s', port_setting.name, - self.router_settings.name) + self._neutron, port_settings=port_setting) if port: self.__ports.append(port) - if not port and not cleanup and not existing: - port = neutron_utils.create_port(self.__neutron, - self.__os_creds, port_setting) - if port: - logger.info( - 'Created port %s for router - %s', port_setting.name, - self.router_settings.name) - self.__ports.append(port) - neutron_utils.add_interface_router(self.__neutron, - self.__router, - port=port) + return self.__router + + def create(self): + """ + Responsible for creating the router. + :return: the Router domain object + """ + self.initialize() + + if not self.__router: + self.__router = neutron_utils.create_router( + self._neutron, self._os_creds, self.router_settings) + + for internal_subnet_name in self.router_settings.internal_subnets: + internal_subnet = neutron_utils.get_subnet( + self._neutron, subnet_name=internal_subnet_name) + if internal_subnet: + self.__internal_subnets.append(internal_subnet) + if internal_subnet: + logger.debug('Adding router to subnet...') + router_intf = neutron_utils.add_interface_router( + self._neutron, self.__router, + subnet=internal_subnet) + self.__internal_router_interface = router_intf else: raise RouterCreationError( - 'Error creating port with name - ' + port_setting.name) + 'Subnet not found with name ' + internal_subnet_name) + + for port_setting in self.router_settings.port_settings: + port = neutron_utils.get_port( + self._neutron, port_settings=port_setting) + logger.info( + 'Retrieved port %s for router - %s', port_setting.name, + self.router_settings.name) + if port: + self.__ports.append(port) + + if not port: + port = neutron_utils.create_port( + self._neutron, self._os_creds, port_setting) + if port: + logger.info( + 'Created port %s for router - %s', + port_setting.name, + self.router_settings.name) + self.__ports.append(port) + neutron_utils.add_interface_router(self._neutron, + self.__router, + port=port) + else: + raise RouterCreationError( + 'Error creating port with name - ' + + port_setting.name) return self.__router @@ -123,7 +143,7 @@ class OpenStackRouter: 'Removing router interface from router %s and port %s', self.router_settings.name, port.name) try: - neutron_utils.remove_interface_router(self.__neutron, + neutron_utils.remove_interface_router(self._neutron, self.__router, port=port) except NotFound: pass @@ -134,7 +154,7 @@ class OpenStackRouter: 'Removing router interface from router %s and subnet %s', self.router_settings.name, internal_subnet.name) try: - neutron_utils.remove_interface_router(self.__neutron, + neutron_utils.remove_interface_router(self._neutron, self.__router, subnet=internal_subnet) except NotFound: @@ -144,7 +164,7 @@ class OpenStackRouter: if self.__router: logger.info('Removing router ' + self.router_settings.name) try: - neutron_utils.delete_router(self.__neutron, self.__router) + neutron_utils.delete_router(self._neutron, self.__router) except NotFound: pass self.__router = None diff --git a/snaps/openstack/create_security_group.py b/snaps/openstack/create_security_group.py index 34d5952..8218c83 100644 --- a/snaps/openstack/create_security_group.py +++ b/snaps/openstack/create_security_group.py @@ -16,6 +16,8 @@ import logging import enum from neutronclient.common.exceptions import NotFound, Conflict + +from snaps.openstack.openstack_creator import OpenStackNetworkObject from snaps.openstack.utils import keystone_utils from snaps.openstack.utils import neutron_utils @@ -24,9 +26,9 @@ __author__ = 'spisarski' logger = logging.getLogger('OpenStackSecurityGroup') -class OpenStackSecurityGroup: +class OpenStackSecurityGroup(OpenStackNetworkObject): """ - Class responsible for creating Security Groups + Class responsible for managing a Security Group in OpenStack """ def __init__(self, os_creds, sec_grp_settings): @@ -35,10 +37,9 @@ class OpenStackSecurityGroup: :param os_creds: The credentials to connect with OpenStack :param sec_grp_settings: The settings used to create a security group """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.sec_grp_settings = sec_grp_settings - self.__neutron = None - self.__keystone = None # Attributes instantiated on create() self.__security_group = None @@ -46,29 +47,46 @@ class OpenStackSecurityGroup: # dict where the rule settings object is the key self.__rules = dict() - def create(self, cleanup=False): + def initialize(self): + """ + Loads existing security group. + :return: the security group domain object + """ + super(self.__class__, self).initialize() + + self.__security_group = neutron_utils.get_security_group( + self._neutron, sec_grp_settings=self.sec_grp_settings) + if self.__security_group: + # Populate rules + existing_rules = neutron_utils.get_rules_by_security_group( + self._neutron, self.__security_group) + + for existing_rule in existing_rules: + # For Custom Rules + rule_setting = self.__get_setting_from_rule(existing_rule) + self.__rules[rule_setting] = existing_rule + + return self.__security_group + + def create(self): """ Responsible for creating the security group. - :param cleanup: Denotes whether or not this is being called for cleanup - :return: the OpenStack security group object + :return: the security group domain object """ - self.__neutron = neutron_utils.neutron_client(self.__os_creds) - self.__keystone = keystone_utils.keystone_client(self.__os_creds) + self.initialize() - logger.info( - 'Creating security group %s...' % self.sec_grp_settings.name) + if not self.__security_group: + logger.info( + 'Creating security group %s...' % self.sec_grp_settings.name) - self.__security_group = neutron_utils.get_security_group( - self.__neutron, sec_grp_settings=self.sec_grp_settings) - if not self.__security_group and not cleanup: - # Create the security group + keystone = keystone_utils.keystone_client(self._os_creds) self.__security_group = neutron_utils.create_security_group( - self.__neutron, self.__keystone, + self._neutron, keystone, self.sec_grp_settings) # Get the rules added for free auto_rules = neutron_utils.get_rules_by_security_group( - self.__neutron, self.__security_group) + self._neutron, self.__security_group) ctr = 0 for auto_rule in auto_rules: @@ -80,7 +98,7 @@ class OpenStackSecurityGroup: for sec_grp_rule_setting in self.sec_grp_settings.rule_settings: try: custom_rule = neutron_utils.create_security_group_rule( - self.__neutron, sec_grp_rule_setting) + self._neutron, sec_grp_rule_setting) self.__rules[sec_grp_rule_setting] = custom_rule except Conflict as e: logger.warn('Unable to create rule due to conflict - %s', @@ -88,22 +106,7 @@ class OpenStackSecurityGroup: # Refresh security group object to reflect the new rules added self.__security_group = neutron_utils.get_security_group( - self.__neutron, sec_grp_settings=self.sec_grp_settings) - else: - # Populate rules - existing_rules = neutron_utils.get_rules_by_security_group( - self.__neutron, self.__security_group) - - for existing_rule in existing_rules: - # For Custom Rules - rule_setting = self.__get_setting_from_rule(existing_rule) - ctr = 0 - if not rule_setting: - # For Free Rules - rule_setting = self.__generate_rule_setting(existing_rule) - ctr += 1 - - self.__rules[rule_setting] = existing_rule + self._neutron, sec_grp_settings=self.sec_grp_settings) return self.__security_group @@ -115,7 +118,7 @@ class OpenStackSecurityGroup: :return: the newly instantiated SecurityGroupRuleSettings object """ sec_grp = neutron_utils.get_security_group_by_id( - self.__neutron, rule.security_group_id) + self._neutron, rule.security_group_id) setting = SecurityGroupRuleSettings( description=rule.description, @@ -135,7 +138,7 @@ class OpenStackSecurityGroup: """ for setting, rule in self.__rules.items(): try: - neutron_utils.delete_security_group_rule(self.__neutron, rule) + neutron_utils.delete_security_group_rule(self._neutron, rule) except NotFound as e: logger.warning('Rule not found, cannot delete - ' + str(e)) pass @@ -143,7 +146,7 @@ class OpenStackSecurityGroup: if self.__security_group: try: - neutron_utils.delete_security_group(self.__neutron, + neutron_utils.delete_security_group(self._neutron, self.__security_group) except NotFound as e: logger.warning( @@ -171,7 +174,7 @@ class OpenStackSecurityGroup: :param rule_setting: the rule configuration """ rule_setting.sec_grp_name = self.sec_grp_settings.name - new_rule = neutron_utils.create_security_group_rule(self.__neutron, + new_rule = neutron_utils.create_security_group_rule(self._neutron, rule_setting) self.__rules[rule_setting] = new_rule self.sec_grp_settings.rule_settings.append(rule_setting) @@ -187,12 +190,12 @@ class OpenStackSecurityGroup: if rule_id or rule_setting: if rule_id: rule_to_remove = neutron_utils.get_rule_by_id( - self.__neutron, self.__security_group, rule_id) + self._neutron, self.__security_group, rule_id) elif rule_setting: rule_to_remove = self.__rules.get(rule_setting) if rule_to_remove: - neutron_utils.delete_security_group_rule(self.__neutron, + neutron_utils.delete_security_group_rule(self._neutron, rule_to_remove) rule_setting = self.__get_setting_from_rule(rule_to_remove) if rule_setting: diff --git a/snaps/openstack/create_stack.py b/snaps/openstack/create_stack.py index ffe87a5..ce87e89 100644 --- a/snaps/openstack/create_stack.py +++ b/snaps/openstack/create_stack.py @@ -19,6 +19,7 @@ import time from heatclient.exc import HTTPNotFound from snaps.openstack.create_instance import OpenStackVmInstance +from snaps.openstack.openstack_creator import OpenStackCloudObject from snaps.openstack.utils import nova_utils, settings_utils, glance_utils from snaps.openstack.create_network import OpenStackNetwork @@ -36,9 +37,9 @@ STATUS_DELETE_COMPLETE = 'DELETE_COMPLETE' STATUS_DELETE_FAILED = 'DELETE_FAILED' -class OpenStackHeatStack: +class OpenStackHeatStack(OpenStackCloudObject, object): """ - Class responsible for creating an heat stack in OpenStack + Class responsible for managing a heat stack in OpenStack """ def __init__(self, os_creds, stack_settings, image_settings=None, @@ -55,7 +56,8 @@ class OpenStackHeatStack: used for spawning this stack :return: """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.stack_settings = stack_settings if image_settings: @@ -71,24 +73,30 @@ class OpenStackHeatStack: self.__stack = None self.__heat_cli = None - def create(self, cleanup=False): + def initialize(self): """ - Creates the heat stack in OpenStack if it does not already exist and - returns the domain Stack object - :param cleanup: When true, this object is initialized only via queries, - else objects will be created when the queries return - None. The name of this parameter should be changed to - something like 'readonly' as the same goes with all of - the other creator classes. - :return: The OpenStack Stack object + Loads the existing heat stack + :return: The Stack domain object or None """ - self.__heat_cli = heat_utils.heat_client(self.__os_creds) + self.__heat_cli = heat_utils.heat_client(self._os_creds) self.__stack = heat_utils.get_stack( self.__heat_cli, stack_settings=self.stack_settings) if self.__stack: logger.info('Found stack with name - ' + self.stack_settings.name) return self.__stack - elif not cleanup: + + def create(self): + """ + Creates the heat stack in OpenStack if it does not already exist and + returns the domain Stack object + :return: The Stack domain object or None + """ + self.initialize() + + if self.__stack: + logger.info('Found stack with name - ' + self.stack_settings.name) + return self.__stack + else: self.__stack = heat_utils.create_stack(self.__heat_cli, self.stack_settings) logger.info( @@ -102,10 +110,6 @@ class OpenStackHeatStack: raise StackCreationError( 'Stack was not created or activated in the alloted amount ' 'of time') - else: - logger.info('Did not create stack due to cleanup mode') - - return self.__stack def clean(self): """ @@ -211,7 +215,7 @@ class OpenStackHeatStack: :return: list() of OpenStackNetwork objects """ - neutron = neutron_utils.neutron_client(self.__os_creds) + neutron = neutron_utils.neutron_client(self._os_creds) out = list() stack_networks = heat_utils.get_stack_networks( @@ -220,9 +224,9 @@ class OpenStackHeatStack: for stack_network in stack_networks: net_settings = settings_utils.create_network_settings( neutron, stack_network) - net_creator = OpenStackNetwork(self.__os_creds, net_settings) + net_creator = OpenStackNetwork(self._os_creds, net_settings) out.append(net_creator) - net_creator.create(cleanup=True) + net_creator.initialize() return out @@ -234,13 +238,13 @@ class OpenStackHeatStack: """ out = list() - nova = nova_utils.nova_client(self.__os_creds) + nova = nova_utils.nova_client(self._os_creds) stack_servers = heat_utils.get_stack_servers( self.__heat_cli, nova, self.__stack) - neutron = neutron_utils.neutron_client(self.__os_creds) - glance = glance_utils.glance_client(self.__os_creds) + neutron = neutron_utils.neutron_client(self._os_creds) + glance = glance_utils.glance_client(self._os_creds) for stack_server in stack_servers: vm_inst_settings = settings_utils.create_vm_inst_settings( @@ -252,10 +256,10 @@ class OpenStackHeatStack: keypair_settings=self.keypair_settings, priv_key_key=heat_keypair_option) vm_inst_creator = OpenStackVmInstance( - self.__os_creds, vm_inst_settings, image_settings, + self._os_creds, vm_inst_settings, image_settings, keypair_settings) out.append(vm_inst_creator) - vm_inst_creator.create(cleanup=True) + vm_inst_creator.initialize() return out diff --git a/snaps/openstack/create_user.py b/snaps/openstack/create_user.py index 6db74fe..bcf4790 100644 --- a/snaps/openstack/create_user.py +++ b/snaps/openstack/create_user.py @@ -15,6 +15,8 @@ import logging from keystoneclient.exceptions import NotFound + +from snaps.openstack.openstack_creator import OpenStackIdentityObject from snaps.openstack.os_credentials import OSCreds from snaps.openstack.utils import keystone_utils @@ -23,9 +25,9 @@ __author__ = 'spisarski' logger = logging.getLogger('create_user') -class OpenStackUser: +class OpenStackUser(OpenStackIdentityObject): """ - Class responsible for creating a user in OpenStack + Class responsible for managing a user in OpenStack """ def __init__(self, os_creds, user_settings): @@ -35,24 +37,31 @@ class OpenStackUser: :param user_settings: The user settings :return: """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.user_settings = user_settings self.__user = None - self.__keystone = None - def create(self, cleanup=False): + def initialize(self): """ Creates the user in OpenStack if it does not already exist - :param cleanup: Denotes whether or not this is being called for cleanup - :return: The OpenStack user object + :return: The User domain object """ - self.__keystone = keystone_utils.keystone_client(self.__os_creds) - self.__user = keystone_utils.get_user(self.__keystone, + super(self.__class__, self).initialize() + + self.__user = keystone_utils.get_user(self._keystone, self.user_settings.name) - if not self.__user and not cleanup: - self.__user = keystone_utils.create_user(self.__keystone, - self.user_settings) + return self.__user + def create(self, cleanup=False): + """ + Creates a User if one does not already exist + :return: The User domain object + """ + self.initialize() + if not self.__user: + self.__user = keystone_utils.create_user(self._keystone, + self.user_settings) return self.__user def clean(self): @@ -62,7 +71,7 @@ class OpenStackUser: """ if self.__user: try: - keystone_utils.delete_user(self.__keystone, self.__user) + keystone_utils.delete_user(self._keystone, self.__user) except NotFound: pass self.__user = None @@ -84,16 +93,16 @@ class OpenStackUser: return OSCreds( username=self.user_settings.name, password=self.user_settings.password, - auth_url=self.__os_creds.auth_url, + auth_url=self._os_creds.auth_url, project_name=project_name, - identity_api_version=self.__os_creds.identity_api_version, - user_domain_name=self.__os_creds.user_domain_name, - user_domain_id=self.__os_creds.user_domain_id, - project_domain_name=self.__os_creds.project_domain_name, - project_domain_id=self.__os_creds.project_domain_id, - interface=self.__os_creds.interface, - proxy_settings=self.__os_creds.proxy_settings, - cacert=self.__os_creds.cacert) + identity_api_version=self._os_creds.identity_api_version, + user_domain_name=self._os_creds.user_domain_name, + user_domain_id=self._os_creds.user_domain_id, + project_domain_name=self._os_creds.project_domain_name, + project_domain_id=self._os_creds.project_domain_id, + interface=self._os_creds.interface, + proxy_settings=self._os_creds.proxy_settings, + cacert=self._os_creds.cacert) class UserSettings: diff --git a/snaps/openstack/openstack_creator.py b/snaps/openstack/openstack_creator.py new file mode 100644 index 0000000..de2ae91 --- /dev/null +++ b/snaps/openstack/openstack_creator.py @@ -0,0 +1,110 @@ +# Copyright (c) 2017 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. +from snaps.domain.creator import CloudObject +from snaps.openstack.utils import nova_utils, neutron_utils, keystone_utils + +__author__ = 'spisarski' + + +class OpenStackCloudObject(CloudObject): + """ + Abstract class for all OpenStack object creators + """ + + def __init__(self, os_creds): + """ + Constructor + :param os_creds: the OpenStack credentials object + """ + # super(self.__class__, self, os_creds) + self._os_creds = os_creds + + def initialize(self): + raise NotImplementedError('Do not override abstract method') + + def create(self): + raise NotImplementedError('Do not override abstract method') + + def clean(self): + raise NotImplementedError('Do not override abstract method') + + +class OpenStackComputeObject(OpenStackCloudObject): + """ + Abstract class for all OpenStack compute creators + """ + + def __init__(self, os_creds): + """ + Constructor + :param os_creds: the OpenStack credentials object + """ + super(OpenStackComputeObject, self).__init__(os_creds) + self._nova = None + + def initialize(self): + self._nova = nova_utils.nova_client(self._os_creds) + + def create(self): + raise NotImplementedError('Do not override abstract method') + + def clean(self): + raise NotImplementedError('Do not override abstract method') + + +class OpenStackNetworkObject(OpenStackCloudObject): + """ + Abstract class for all OpenStack compute creators + """ + + def __init__(self, os_creds): + """ + Constructor + :param os_creds: the OpenStack credentials object + """ + super(OpenStackNetworkObject, self).__init__(os_creds) + self._neutron = None + + def initialize(self): + self._neutron = neutron_utils.neutron_client(self._os_creds) + + def create(self): + raise NotImplementedError('Do not override abstract method') + + def clean(self): + raise NotImplementedError('Do not override abstract method') + + +class OpenStackIdentityObject(OpenStackCloudObject): + """ + Abstract class for all OpenStack compute creators + """ + + def __init__(self, os_creds): + """ + Constructor + :param os_creds: the OpenStack credentials object + """ + super(OpenStackIdentityObject, self).__init__(os_creds) + self._keystone = None + + def initialize(self): + self._keystone = keystone_utils.keystone_client(self._os_creds) + + def create(self): + raise NotImplementedError('Do not override abstract method') + + def clean(self): + raise NotImplementedError('Do not override abstract method') diff --git a/snaps/openstack/utils/deploy_utils.py b/snaps/openstack/utils/deploy_utils.py index ade8811..c936c1f 100644 --- a/snaps/openstack/utils/deploy_utils.py +++ b/snaps/openstack/utils/deploy_utils.py @@ -34,11 +34,16 @@ def create_image(os_creds, image_settings, cleanup=False): Creates an image in OpenStack if necessary :param os_creds: The OpenStack credentials object :param image_settings: The image settings object - :param cleanup: Denotes whether or not this is being called for cleanup or not - :return: A reference to the image creator object from which the image object can be accessed + :param cleanup: Denotes whether or not this is being called for cleanup + :return: A reference to the image creator object from which the image + object can be accessed """ image_creator = OpenStackImage(os_creds, image_settings) - image_creator.create(cleanup) + + if cleanup: + image_creator.initialize() + else: + image_creator.create() return image_creator @@ -47,18 +52,24 @@ def create_network(os_creds, network_settings, cleanup=False): Creates a network on which the CMTSs can attach :param os_creds: The OpenStack credentials object :param network_settings: The network settings object - :param cleanup: Denotes whether or not this is being called for cleanup or not - :return: A reference to the network creator objects for each network from which network elements such as the - subnet, router, interface router, and network objects can be accessed. + :param cleanup: Denotes whether or not this is being called for cleanup + :return: A reference to the network creator objects for each network from + which network elements such as the subnet, router, interface + router, and network objects can be accessed. """ # Check for OS for network existence # If exists return network instance data # Else, create network and return instance data - logger.info('Attempting to create network with name - ' + network_settings.name) + logger.info('Attempting to create network with name - %s', + network_settings.name) network_creator = OpenStackNetwork(os_creds, network_settings) - network_creator.create(cleanup) + + if cleanup: + network_creator.initialize() + else: + network_creator.create() logger.info('Created network ') return network_creator @@ -68,16 +79,22 @@ def create_router(os_creds, router_settings, cleanup=False): Creates a network on which the CMTSs can attach :param os_creds: The OpenStack credentials object :param router_settings: The RouterSettings instance - :param cleanup: Denotes whether or not this is being called for cleanup or not - :return: A reference to the network creator objects for each network from which network elements such as the - subnet, router, interface router, and network objects can be accessed. + :param cleanup: Denotes whether or not this is being called for cleanup + :return: A reference to the network creator objects for each network from + which network elements such as the subnet, router, interface + router, and network objects can be accessed. """ # Check for OS for network existence # If exists return network instance data # Else, create network and return instance data - logger.info('Attempting to create router with name - ' + router_settings.name) + logger.info('Attempting to create router with name - %s', + router_settings.name) router_creator = OpenStackRouter(os_creds, router_settings) - router_creator.create(cleanup) + + if cleanup: + router_creator.initialize() + else: + router_creator.create() logger.info('Created router ') return router_creator @@ -87,30 +104,40 @@ def create_keypair(os_creds, keypair_settings, cleanup=False): Creates a keypair that can be applied to an instance :param os_creds: The OpenStack credentials object :param keypair_settings: The KeypairSettings object - :param cleanup: Denotes whether or not this is being called for cleanup or not + :param cleanup: Denotes whether or not this is being called for cleanup :return: A reference to the keypair creator object """ keypair_creator = OpenStackKeypair(os_creds, keypair_settings) - keypair_creator.create(cleanup) + + if cleanup: + keypair_creator.initialize() + else: + keypair_creator.create() return keypair_creator -def create_vm_instance(os_creds, instance_settings, image_settings, keypair_creator=None, cleanup=False): +def create_vm_instance(os_creds, instance_settings, image_settings, + keypair_creator=None, init_only=False): """ Creates a VM instance :param os_creds: The OpenStack credentials :param instance_settings: Instance of VmInstanceSettings :param image_settings: The object containing image settings - :param keypair_creator: The object responsible for creating the keypair associated with this VM instance. (optional) - :param sg_names: The names of the security groups to apply to VM. (optional) - :param cleanup: Denotes whether or not this is being called for cleanup or not (default False) + :param keypair_creator: The object responsible for creating the keypair + associated with this VM instance. (optional) + :param init_only: Denotes whether or not this is being called for + initialization (T) or creation (F) (default False) :return: A reference to the VM instance object """ kp_settings = None if keypair_creator: kp_settings = keypair_creator.keypair_settings - vm_creator = OpenStackVmInstance(os_creds, instance_settings, image_settings, kp_settings) - vm_creator.create(cleanup=cleanup) + vm_creator = OpenStackVmInstance(os_creds, instance_settings, + image_settings, kp_settings) + if init_only: + vm_creator.initialize() + else: + vm_creator.create() return vm_creator @@ -148,4 +175,3 @@ def create_security_group(os_creds, sec_grp_settings): sg_creator = OpenStackSecurityGroup(os_creds, sec_grp_settings) sg_creator.create() return sg_creator - diff --git a/snaps/openstack/utils/tests/heat_utils_tests.py b/snaps/openstack/utils/tests/heat_utils_tests.py index e7d6265..44235ff 100644 --- a/snaps/openstack/utils/tests/heat_utils_tests.py +++ b/snaps/openstack/utils/tests/heat_utils_tests.py @@ -371,7 +371,7 @@ class HeatUtilsCreateComplexStackTests(OSComponentTestCase): self.image_creator2.image_settings]) vm_creator = OpenStackVmInstance( self.os_creds, vm_settings, img_settings) - vm_creator.create(cleanup=False) + vm_creator.initialize() vm_creator.clean() vm_creator.vm_deleted(block=True) |