diff options
Diffstat (limited to 'snaps/openstack/create_instance.py')
-rw-r--r-- | snaps/openstack/create_instance.py | 212 |
1 files changed, 109 insertions, 103 deletions
diff --git a/snaps/openstack/create_instance.py b/snaps/openstack/create_instance.py index d91e360..b158a25 100644 --- a/snaps/openstack/create_instance.py +++ b/snaps/openstack/create_instance.py @@ -15,11 +15,12 @@ import logging import time -from novaclient.exceptions import NotFound, BadRequest +from novaclient.exceptions import NotFound from snaps.config.vm_inst import VmInstanceConfig, FloatingIpConfig from snaps.openstack.openstack_creator import OpenStackComputeObject -from snaps.openstack.utils import glance_utils, cinder_utils, settings_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 @@ -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,7 +96,7 @@ class OpenStackVmInstance(OpenStackComputeObject): """ self.initialize() - if len(self.__ports) == 0: + if len(self.__ports) != len(self.instance_settings.port_settings): self.__ports = self.__create_ports( self.instance_settings.port_settings) if not self.__vm: @@ -103,7 +111,7 @@ class OpenStackVmInstance(OpenStackComputeObject): within the project """ server = nova_utils.get_server( - self._nova, self.__neutron, + self._nova, self.__neutron, self.__keystone, vm_inst_settings=self.instance_settings) if server: if server.name == self.instance_settings.name: @@ -112,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: @@ -132,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) @@ -159,20 +167,20 @@ class OpenStackVmInstance(OpenStackComputeObject): if self.instance_settings.volume_names: for volume_name in self.instance_settings.volume_names: - cinder = cinder_utils.cinder_client(self._os_creds) volume = cinder_utils.get_volume( - cinder, volume_name=volume_name) + self.__cinder, self.__keystone, volume_name=volume_name, + project_name=self._os_creds.project_name) if volume and self.vm_active(block=True): - timeout = 30 vm = nova_utils.attach_volume( - self._nova, self.__neutron, self.__vm, volume, timeout) + self._nova, self.__neutron, self.__keystone, self.__vm, + volume, self._os_creds.project_name) if vm: self.__vm = vm else: - logger.warn('Volume [%s] not attached within timeout ' - 'of [%s]', volume.name, timeout) + logger.warn( + 'Volume [%s] attachment timeout ', volume.name) else: logger.warn('Unable to attach volume named [%s]', volume_name) @@ -213,18 +221,15 @@ class OpenStackVmInstance(OpenStackComputeObject): # gateway ext_gateway = self.__ext_gateway_by_router( floating_ip_setting.router_name) - if ext_gateway: - subnet = neutron_utils.get_subnet( - self.__neutron, - subnet_name=floating_ip_setting.subnet_name) + if ext_gateway and self.vm_active(block=True): floating_ip = neutron_utils.create_floating_ip( - self.__neutron, ext_gateway) + 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) - self.__add_floating_ip(floating_ip, port, subnet) + return floating_ip else: raise VmInstanceCreationError( @@ -239,7 +244,8 @@ class OpenStackVmInstance(OpenStackComputeObject): :return: the external network name or None """ router = neutron_utils.get_router( - self.__neutron, router_name=router_name) + 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_network_id) @@ -269,12 +275,12 @@ class OpenStackVmInstance(OpenStackComputeObject): 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']) + self.__cinder, volume_rec['id']) if volume: vm = nova_utils.detach_volume( - self._nova, self.__neutron, self.__vm, volume, 30) + self._nova, self.__neutron, self.__keystone, self.__vm, + volume, self._os_creds.project_name) if vm: self.__vm = vm else: @@ -307,6 +313,8 @@ class OpenStackVmInstance(OpenStackComputeObject): '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): """ Returns the previously configured ports or an empty list if none @@ -319,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)) @@ -337,63 +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)) + 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 BadRequest as bre: - logger.error('Cannot add floating IP [%s]', bre) - raise - 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 @@ -407,7 +369,8 @@ class OpenStackVmInstance(OpenStackComputeObject): :return: Server object """ return nova_utils.get_server_object_by_id( - self._nova, self.__neutron, self.__vm.id) + self._nova, self.__neutron, self.__keystone, self.__vm.id, + self._os_creds.project_name) def get_console_output(self): """ @@ -428,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', @@ -474,6 +439,10 @@ class OpenStackVmInstance(OpenStackComputeObject): Returns a dictionary of a VMs info as returned by OpenStack :return: a dict() """ + from warnings import warn + warn('Do not use the returned dict() structure', + DeprecationWarning) + return nova_utils.get_server_info(self._nova, self.__vm) def __get_first_provisioning_floating_ip(self): @@ -505,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): """ @@ -554,7 +527,8 @@ class OpenStackVmInstance(OpenStackComputeObject): 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.__vm.id) + self._nova, self.__neutron, self.__keystone, self.__vm.id, + self._os_creds.project_name) return True return False @@ -619,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: @@ -639,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 @@ -653,13 +637,14 @@ 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 @@ -727,19 +712,32 @@ class OpenStackVmInstance(OpenStackComputeObject): 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: FloatingIPAllocationError( @@ -797,24 +795,32 @@ class OpenStackVmInstance(OpenStackComputeObject): self._nova, self.__vm, reboot_type=reboot_type) -def generate_creator(os_creds, vm_inst, image_config, keypair_config=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 """ - nova = nova_utils.nova_client(os_creds) - neutron = neutron_utils.neutron_client(os_creds) - derived_inst_config = settings_utils.create_vm_inst_config( - nova, neutron, vm_inst) - - derived_inst_creator = OpenStackVmInstance( - os_creds, derived_inst_config, image_config, keypair_config) - derived_inst_creator.initialize() - return derived_inst_creator + 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) + + try: + derived_inst_config = settings_utils.create_vm_inst_config( + nova, keystone, neutron, vm_inst, project_name) + + 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 VmInstanceSettings(VmInstanceConfig): |