diff options
Diffstat (limited to 'snaps/openstack/create_instance.py')
-rw-r--r-- | snaps/openstack/create_instance.py | 612 |
1 files changed, 291 insertions, 321 deletions
diff --git a/snaps/openstack/create_instance.py b/snaps/openstack/create_instance.py index 3d55f42..b158a25 100644 --- a/snaps/openstack/create_instance.py +++ b/snaps/openstack/create_instance.py @@ -15,14 +15,15 @@ import logging import time -from neutronclient.common.exceptions import PortNotFoundClient from novaclient.exceptions import NotFound -from snaps.openstack.create_network import PortSettings +from snaps.config.vm_inst import VmInstanceConfig, FloatingIpConfig from snaps.openstack.openstack_creator import OpenStackComputeObject -from snaps.openstack.utils import glance_utils +from snaps.openstack.utils import ( + glance_utils, cinder_utils, settings_utils, keystone_utils) from snaps.openstack.utils import neutron_utils from snaps.openstack.utils import nova_utils +from snaps.openstack.utils.nova_utils import RebootType from snaps.provisioning import ansible_utils __author__ = 'spisarski' @@ -72,7 +73,14 @@ class OpenStackVmInstance(OpenStackComputeObject): """ super(self.__class__, self).initialize() - self.__neutron = neutron_utils.neutron_client(self._os_creds) + self.__neutron = neutron_utils.neutron_client( + self._os_creds, self._os_session) + self.__keystone = keystone_utils.keystone_client( + self._os_creds, self._os_session) + self.__cinder = cinder_utils.cinder_client( + self._os_creds, self._os_session) + self.__glance = glance_utils.glance_client( + self._os_creds, self._os_session) self.__ports = self.__query_ports(self.instance_settings.port_settings) self.__lookup_existing_vm_by_name() @@ -88,8 +96,9 @@ class OpenStackVmInstance(OpenStackComputeObject): """ self.initialize() - if len(self.__ports) == 0: - self.__ports = self.__create_ports(self.instance_settings.port_settings) + if len(self.__ports) != len(self.instance_settings.port_settings): + self.__ports = self.__create_ports( + self.instance_settings.port_settings) if not self.__vm: self.__create_vm(block) @@ -102,7 +111,8 @@ class OpenStackVmInstance(OpenStackComputeObject): within the project """ server = nova_utils.get_server( - self._nova, vm_inst_settings=self.instance_settings) + self._nova, self.__neutron, self.__keystone, + vm_inst_settings=self.instance_settings) if server: if server.name == self.instance_settings.name: self.__vm = server @@ -110,8 +120,8 @@ class OpenStackVmInstance(OpenStackComputeObject): 'Found existing machine with name - %s', self.instance_settings.name) - fips = neutron_utils.get_floating_ips(self.__neutron, - self.__ports) + fips = neutron_utils.get_port_floating_ips( + self.__neutron, self.__ports) for port_id, fip in fips: settings = self.instance_settings.floating_ip_settings for fip_setting in settings: @@ -130,10 +140,10 @@ class OpenStackVmInstance(OpenStackComputeObject): active, error, or timeout waiting. Floating IPs will be assigned after active when block=True """ - glance = glance_utils.glance_client(self._os_creds) self.__vm = nova_utils.create_server( - self._nova, self.__neutron, glance, self.instance_settings, - self.image_settings, self.keypair_settings) + self._nova, self.__keystone, self.__neutron, self.__glance, + self.instance_settings, self.image_settings, + self._os_creds.project_name, self.keypair_settings) logger.info('Created instance with name - %s', self.instance_settings.name) @@ -155,6 +165,26 @@ class OpenStackVmInstance(OpenStackComputeObject): ' to VM that did not activate with name - ' + self.instance_settings.name) + if self.instance_settings.volume_names: + for volume_name in self.instance_settings.volume_names: + volume = cinder_utils.get_volume( + self.__cinder, self.__keystone, volume_name=volume_name, + project_name=self._os_creds.project_name) + + if volume and self.vm_active(block=True): + vm = nova_utils.attach_volume( + self._nova, self.__neutron, self.__keystone, self.__vm, + volume, self._os_creds.project_name) + + if vm: + self.__vm = vm + else: + logger.warn( + 'Volume [%s] attachment timeout ', volume.name) + else: + logger.warn('Unable to attach volume named [%s]', + volume_name) + self.__apply_floating_ips() def __apply_floating_ips(self): @@ -167,33 +197,44 @@ class OpenStackVmInstance(OpenStackComputeObject): # Apply floating IPs for floating_ip_setting in self.instance_settings.floating_ip_settings: - port = port_dict.get(floating_ip_setting.port_name) + self.add_floating_ip(floating_ip_setting) - if not port: - raise VmInstanceCreationError( - 'Cannot find port object with name - ' + - floating_ip_setting.port_name) + def add_floating_ip(self, floating_ip_setting): + """ + Adds a floating IP to a running instance + :param floating_ip_setting - the floating IP configuration + :return: the floating ip object + """ + port_dict = dict() + for key, port in self.__ports: + port_dict[key] = port + + # Apply floating IP + port = port_dict.get(floating_ip_setting.port_name) - # Setup Floating IP only if there is a router with an external - # gateway - ext_gateway = self.__ext_gateway_by_router( + if not port: + raise VmInstanceCreationError( + 'Cannot find port object with name - ' + + floating_ip_setting.port_name) + + # Setup Floating IP only if there is a router with an external + # gateway + ext_gateway = self.__ext_gateway_by_router( + floating_ip_setting.router_name) + if ext_gateway and self.vm_active(block=True): + floating_ip = neutron_utils.create_floating_ip( + self.__neutron, self.__keystone, ext_gateway, port.id) + self.__floating_ip_dict[floating_ip_setting.name] = floating_ip + + logger.info( + 'Created floating IP %s via router - %s', floating_ip.ip, floating_ip_setting.router_name) - if ext_gateway: - subnet = neutron_utils.get_subnet( - self.__neutron, - subnet_name=floating_ip_setting.subnet_name) - floating_ip = neutron_utils.create_floating_ip( - self.__neutron, ext_gateway) - self.__floating_ip_dict[floating_ip_setting.name] = floating_ip - logger.info( - 'Created floating IP %s via router - %s', floating_ip.ip, - floating_ip_setting.router_name) - self.__add_floating_ip(floating_ip, port, subnet) - else: - raise VmInstanceCreationError( - 'Unable to add floating IP to port, cannot locate router ' - 'with an external gateway ') + return floating_ip + else: + raise VmInstanceCreationError( + 'Unable to add floating IP to port, cannot locate router ' + 'with an external gateway ') def __ext_gateway_by_router(self, router_name): """ @@ -203,11 +244,11 @@ class OpenStackVmInstance(OpenStackComputeObject): :return: the external network name or None """ router = neutron_utils.get_router( - self.__neutron, router_name=router_name) - if router and router.external_gateway_info: + self.__neutron, self.__keystone, router_name=router_name, + project_name=self._os_creds.project_name) + if router and router.external_network_id: network = neutron_utils.get_network_by_id( - self.__neutron, - router.external_gateway_info['network_id']) + self.__neutron, router.external_network_id) if network: return network.name return None @@ -219,50 +260,60 @@ 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() # 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 + logger.info('Deleting Port with ID - %s ', port.id) + neutron_utils.delete_port(self.__neutron, port) + self.__ports = list() - # Cleanup VM if self.__vm: + # Detach Volume + for volume_rec in self.__vm.volume_ids: + volume = cinder_utils.get_volume_by_id( + self.__cinder, volume_rec['id']) + if volume: + vm = nova_utils.detach_volume( + self._nova, self.__neutron, self.__keystone, self.__vm, + volume, self._os_creds.project_name) + if vm: + self.__vm = vm + else: + logger.warn( + 'Timeout waiting to detach volume %s', volume.name) + else: + logger.warn('Unable to detach volume with ID - [%s]', + volume_rec['id']) + + # Cleanup VM + logger.info( + 'Deleting VM instance - ' + self.instance_settings.name) + 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) + + super(self.__class__, self).clean() def __query_ports(self, port_settings): """ @@ -276,7 +327,8 @@ class OpenStackVmInstance(OpenStackComputeObject): for port_setting in port_settings: port = neutron_utils.get_port( - self.__neutron, port_settings=port_setting) + self.__neutron, self.__keystone, port_settings=port_setting, + project_name=self._os_creds.project_name) if port: ports.append((port_setting.name, port)) @@ -294,59 +346,16 @@ class OpenStackVmInstance(OpenStackComputeObject): for port_setting in port_settings: port = neutron_utils.get_port( - self.__neutron, port_settings=port_setting) + self.__neutron, self.__keystone, port_settings=port_setting, + project_name=self._os_creds.project_name) if not port: - port = neutron_utils.create_port(self.__neutron, self._os_creds, port_setting) - if port: - ports.append((port_setting.name, port)) + port = neutron_utils.create_port( + self.__neutron, self._os_creds, port_setting) + if port: + ports.append((port_setting.name, port)) return ports - def __add_floating_ip(self, floating_ip, port, subnet, timeout=30, - poll_interval=POLL_INTERVAL): - """ - Returns True when active else False - TODO - Make timeout and poll_interval configurable... - """ - ip = None - - if subnet: - # Take IP of subnet if there is one configured on which to place - # the floating IP - for fixed_ip in port.ips: - if fixed_ip['subnet_id'] == subnet.id: - ip = fixed_ip['ip_address'] - break - else: - # Simply take the first - ip = port.ips[0]['ip_address'] - - if ip: - count = timeout / poll_interval - while count > 0: - logger.debug('Attempting to add floating IP to instance') - try: - nova_utils.add_floating_ip_to_server( - 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) - return - except Exception as e: - logger.debug( - 'Retry adding floating IP to instance. Last attempt ' - 'failed with - %s', e) - time.sleep(poll_interval) - count -= 1 - pass - else: - raise VmInstanceCreationError( - 'Unable find IP address on which to place the floating IP') - - logger.error('Timeout attempting to add the floating IP to instance.') - raise VmInstanceCreationError( - 'Timeout while attempting add floating IP to instance') - def get_os_creds(self): """ Returns the OpenStack credentials used to create these objects @@ -359,7 +368,9 @@ class OpenStackVmInstance(OpenStackComputeObject): 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.__neutron, self.__keystone, self.__vm.id, + self._os_creds.project_name) def get_console_output(self): """ @@ -380,8 +391,10 @@ class OpenStackVmInstance(OpenStackComputeObject): port = self.get_port_by_name(port_name) if port: if subnet_name: + network = neutron_utils.get_network_by_id( + self.__neutron, port.network_id) subnet = neutron_utils.get_subnet( - self.__neutron, subnet_name=subnet_name) + self.__neutron, network, subnet_name=subnet_name) if not subnet: logger.warning('Cannot retrieve port IP as subnet could ' 'not be located with name - %s', @@ -426,26 +439,11 @@ class OpenStackVmInstance(OpenStackComputeObject): Returns a dictionary of a VMs info as returned by OpenStack :return: a dict() """ - return nova_utils.get_server_info(self._nova, self.__vm) + from warnings import warn + warn('Do not use the returned dict() structure', + DeprecationWarning) - 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 + return nova_utils.get_server_info(self._nova, self.__vm) def __get_first_provisioning_floating_ip(self): """ @@ -462,30 +460,10 @@ 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) + # When cannot be found above + if len(self.__floating_ip_dict) > 0: + for key, fip in self.__floating_ip_dict.items(): + return fip def apply_ansible_playbook(self, pb_file_loc, variables=None, fip_name=None): @@ -496,12 +474,16 @@ class OpenStackVmInstance(OpenStackComputeObject): playbook :param fip_name: the name of the floating IP to use for applying the playbook (default - will take the first) - :return: the return value from ansible """ - return ansible_utils.apply_playbook( + from warnings import warn + warn('This method will be removed in a subsequent release', + DeprecationWarning) + + 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) + self.get_image_user(), + ssh_priv_key_file_path=self.keypair_settings.private_filepath, + variables=variables, proxy_setting=self._os_creds.proxy_settings) def get_image_user(self): """ @@ -541,9 +523,14 @@ class OpenStackVmInstance(OpenStackComputeObject): :param poll_interval: The polling interval in seconds :return: T/F """ - return self.__vm_status_check(STATUS_ACTIVE, block, - self.instance_settings.vm_boot_timeout, - poll_interval) + if self.__vm_status_check( + STATUS_ACTIVE, block, self.instance_settings.vm_boot_timeout, + poll_interval): + self.__vm = nova_utils.get_server_object_by_id( + self._nova, self.__neutron, self.__keystone, self.__vm.id, + self._os_creds.project_name) + return True + return False def __vm_status_check(self, expected_status_code, block, timeout, poll_interval): @@ -606,18 +593,27 @@ class OpenStackVmInstance(OpenStackComputeObject): status) return status == expected_status_code - def vm_ssh_active(self, block=False, poll_interval=POLL_INTERVAL): + def vm_ssh_active(self, user_override=None, password=None, block=False, + timeout=None, poll_interval=POLL_INTERVAL): """ Returns true when the VM can be accessed via SSH + :param user_override: overrides the user with which to create the + connection + :param password: overrides the use of a password instead of a private + key with which to create the connection :param block: When true, thread will block until active or timeout value in seconds has been exceeded (False) + :param timeout: the number of seconds to retry obtaining the connection + and overrides the ssh_connect_timeout member of the + self.instance_settings object :param poll_interval: The polling interval :return: T/F """ # sleep and wait for VM status change logger.info('Checking if VM is active') - timeout = self.instance_settings.ssh_connect_timeout + if not timeout: + timeout = self.instance_settings.ssh_connect_timeout if self.vm_active(block=True): if block: @@ -626,7 +622,8 @@ class OpenStackVmInstance(OpenStackComputeObject): start = time.time() - timeout while timeout > time.time() - start: - status = self.__ssh_active() + status = self.__ssh_active( + user_override=user_override, password=password) if status: logger.info('SSH is active for VM instance') return True @@ -640,18 +637,69 @@ class OpenStackVmInstance(OpenStackComputeObject): logger.error('Timeout attempting to connect with VM via SSH') return False - def __ssh_active(self): + def __ssh_active(self, user_override=None, password=None): """ Returns True when can create a SSH session else False :return: T/F """ if len(self.__floating_ip_dict) > 0: - ssh = self.ssh_client() + ssh = self.ssh_client( + user_override=user_override, password=password) if ssh: ssh.close() 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 = self.instance_settings.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, @@ -659,28 +707,40 @@ class OpenStackVmInstance(OpenStackComputeObject): :param fip_name: the name of the floating IP to return :return: the SSH client or None """ - fip = None if fip_name and self.__floating_ip_dict.get(fip_name): return self.__floating_ip_dict.get(fip_name) - if not fip: + else: return self.__get_first_provisioning_floating_ip() - def ssh_client(self, fip_name=None): + def ssh_client(self, fip_name=None, user_override=None, password=None): """ Returns an SSH client using the name or the first known floating IP if exists, else None :param fip_name: the name of the floating IP to return + :param user_override: the username to use instead of the default + :param password: the password to use instead of the private key :return: the SSH client or None """ fip = self.get_floating_ip(fip_name) + + ansible_user = self.get_image_user() + if user_override: + ansible_user = user_override + + if password: + private_key = None + else: + private_key = self.keypair_settings.private_filepath + if fip: return ansible_utils.ssh_client( self.__get_first_provisioning_floating_ip().ip, - self.get_image_user(), - self.keypair_settings.private_filepath, + ansible_user, + private_key_filepath=private_key, + password=password, proxy_settings=self._os_creds.proxy_settings) else: - logger.warning( + FloatingIPAllocationError( 'Cannot return an SSH client. No Floating IP configured') def add_security_group(self, security_group): @@ -723,165 +783,75 @@ class OpenStackVmInstance(OpenStackComputeObject): logger.warning('Security group not removed - ' + str(e)) return False - -class VmInstanceSettings: - """ - Class responsible for holding configuration setting for a VM Instance - """ - - def __init__(self, **kwargs): + def reboot(self, reboot_type=RebootType.soft): """ - Constructor - :param name: the name of the VM - :param flavor: the VM's flavor name - :param port_settings: the port configuration settings (required) - :param security_group_names: a set of names of the security groups to - add to the VM - :param floating_ip_settings: the floating IP configuration settings - :param sudo_user: the sudo user of the VM that will override the - instance_settings.image_user when trying to - connect to the VM - :param vm_boot_timeout: the amount of time a thread will sleep waiting - for an instance to boot - :param vm_delete_timeout: the amount of time a thread will sleep - waiting for an instance to be deleted - :param ssh_connect_timeout: the amount of time a thread will sleep - waiting obtaining an SSH connection to a VM - :param availability_zone: the name of the compute server on which to - deploy the VM (optional) - :param userdata: the string contents of any optional cloud-init script - to execute after the VM has been activated. - This value may also contain a dict who's key value - must contain the key 'cloud-init_file' which denotes - the location of some file containing the cloud-init - script - """ - self.name = kwargs.get('name') - self.flavor = kwargs.get('flavor') - self.sudo_user = kwargs.get('sudo_user') - self.userdata = kwargs.get('userdata') - - self.port_settings = list() - port_settings = kwargs.get('ports') - if not port_settings: - port_settings = kwargs.get('port_settings') - if port_settings: - for port_setting in port_settings: - if isinstance(port_setting, dict): - self.port_settings.append(PortSettings(**port_setting)) - elif isinstance(port_setting, PortSettings): - self.port_settings.append(port_setting) - - if kwargs.get('security_group_names'): - if isinstance(kwargs['security_group_names'], list): - self.security_group_names = kwargs['security_group_names'] - elif isinstance(kwargs['security_group_names'], set): - self.security_group_names = kwargs['security_group_names'] - elif isinstance(kwargs['security_group_names'], str): - self.security_group_names = [kwargs['security_group_names']] - else: - raise VmInstanceSettingsError( - 'Invalid data type for security_group_names attribute') - else: - self.security_group_names = set() - - self.floating_ip_settings = list() - floating_ip_settings = kwargs.get('floating_ips') - if not floating_ip_settings: - floating_ip_settings = kwargs.get('floating_ip_settings') - if floating_ip_settings: - for floating_ip_config in floating_ip_settings: - if isinstance(floating_ip_config, FloatingIpSettings): - self.floating_ip_settings.append(floating_ip_config) - else: - self.floating_ip_settings.append(FloatingIpSettings( - **floating_ip_config['floating_ip'])) - - if kwargs.get('vm_boot_timeout'): - self.vm_boot_timeout = kwargs['vm_boot_timeout'] - else: - self.vm_boot_timeout = 900 - - if kwargs.get('vm_delete_timeout'): - self.vm_delete_timeout = kwargs['vm_delete_timeout'] - else: - self.vm_delete_timeout = 300 + Issues a reboot call + :param reboot_type: instance of + snaps.openstack.utils.nova_utils.RebootType + enumeration + :return: + """ + nova_utils.reboot_server( + self._nova, self.__vm, reboot_type=reboot_type) - if kwargs.get('ssh_connect_timeout'): - self.ssh_connect_timeout = kwargs['ssh_connect_timeout'] - else: - self.ssh_connect_timeout = 180 - if kwargs.get('availability_zone'): - self.availability_zone = kwargs['availability_zone'] - else: - self.availability_zone = None +def generate_creator(os_creds, vm_inst, image_config, project_name, + keypair_config=None): + """ + Initializes an OpenStackVmInstance object + :param os_creds: the OpenStack credentials + :param vm_inst: the SNAPS-OO VmInst domain object + :param image_config: the associated ImageConfig object + :param project_name: the associated project ID + :param keypair_config: the associated KeypairConfig object (optional) + :return: an initialized OpenStackVmInstance object + """ + session = keystone_utils.keystone_session(os_creds) + nova = nova_utils.nova_client(os_creds, session) + keystone = keystone_utils.keystone_client(os_creds, session) + neutron = neutron_utils.neutron_client(os_creds, session) - if not self.name or not self.flavor: - raise VmInstanceSettingsError( - 'Instance configuration requires the attributes: name, flavor') + try: + derived_inst_config = settings_utils.create_vm_inst_config( + nova, keystone, neutron, vm_inst, project_name) - if len(self.port_settings) == 0: - raise VmInstanceSettingsError( - 'Instance configuration requires port settings (aka. NICS)') + derived_inst_creator = OpenStackVmInstance( + os_creds, derived_inst_config, image_config, keypair_config) + derived_inst_creator.initialize() + return derived_inst_creator + finally: + keystone_utils.close_session(session) -class FloatingIpSettings: +class VmInstanceSettings(VmInstanceConfig): """ - Class responsible for holding configuration settings for a floating IP + Deprecated, use snaps.config.vm_inst.VmInstanceConfig instead """ - def __init__(self, **kwargs): - """ - Constructor - :param name: the name of the floating IP - :param port_name: the name of the router to the external network - :param router_name: the name of the router to the external network - :param subnet_name: the name of the subnet on which to attach the - floating IP - :param provisioning: when true, this floating IP can be used for - provisioning - - TODO - provisioning flag is a hack as I have only observed a single - Floating IPs that actually works on an instance. Multiple floating IPs - placed on different subnets from the same port are especially - troublesome as you cannot predict which one will actually connect. - For now, it is recommended not to setup multiple floating IPs on an - instance unless absolutely necessary. - """ - self.name = kwargs.get('name') - self.port_name = kwargs.get('port_name') - self.port_id = kwargs.get('port_id') - self.router_name = kwargs.get('router_name') - self.subnet_name = kwargs.get('subnet_name') - if kwargs.get('provisioning') is not None: - self.provisioning = kwargs['provisioning'] - else: - self.provisioning = True + from warnings import warn + warn('Use snaps.config.vm_inst.VmInstanceConfig instead', + DeprecationWarning) + super(self.__class__, self).__init__(**kwargs) - # if not self.name or not self.port_name or not self.router_name: - if not self.name or not self.router_name: - raise FloatingIpSettingsError( - 'The attributes name, port_name and router_name are required') - if not self.port_name and not self.port_id: - raise FloatingIpSettingsError( - 'The attributes port_name or port_id are required') - - -class VmInstanceSettingsError(Exception): +class FloatingIpSettings(FloatingIpConfig): """ - Exception to be thrown when an VM instance settings are incorrect + Deprecated, use snaps.config.vm_inst.FloatingIpConfig instead """ + def __init__(self, **kwargs): + from warnings import warn + warn('Use snaps.config.vm_inst.FloatingIpConfig instead', + DeprecationWarning) + super(self.__class__, self).__init__(**kwargs) -class FloatingIpSettingsError(Exception): +class VmInstanceCreationError(Exception): """ - Exception to be thrown when an VM instance settings are incorrect + Exception to be thrown when an VM instance cannot be created """ -class VmInstanceCreationError(Exception): +class FloatingIPAllocationError(Exception): """ - Exception to be thrown when an VM instance cannot be created + Exception to be thrown when an VM instance cannot allocate a floating IP """ |