diff options
Diffstat (limited to 'snaps/openstack/utils/nova_utils.py')
-rw-r--r-- | snaps/openstack/utils/nova_utils.py | 167 |
1 files changed, 103 insertions, 64 deletions
diff --git a/snaps/openstack/utils/nova_utils.py b/snaps/openstack/utils/nova_utils.py index e15484c..005b56f 100644 --- a/snaps/openstack/utils/nova_utils.py +++ b/snaps/openstack/utils/nova_utils.py @@ -35,33 +35,41 @@ __author__ = 'spisarski' logger = logging.getLogger('nova_utils') +POLL_INTERVAL = 3 + """ Utilities for basic OpenStack Nova API calls """ -def nova_client(os_creds): +def nova_client(os_creds, session=None): """ Instantiates and returns a client for communications with OpenStack's Nova server :param os_creds: The connection credentials to the OpenStack API + :param session: the keystone session object (optional) :return: the client object """ logger.debug('Retrieving Nova Client') + if not session: + session = keystone_utils.keystone_session(os_creds) + return Client(os_creds.compute_api_version, - session=keystone_utils.keystone_session(os_creds), + session=session, region_name=os_creds.region_name) -def create_server(nova, neutron, glance, instance_config, image_config, - keypair_config=None): +def create_server(nova, keystone, neutron, glance, instance_config, + image_config, project_name, keypair_config=None): """ Creates a VM instance :param nova: the nova client (required) + :param keystone: the keystone client for retrieving projects (required) :param neutron: the neutron client for retrieving ports (required) :param glance: the glance client (required) :param instance_config: the VMInstConfig object (required) :param image_config: the VM's ImageConfig object (required) + :param project_name: the associated project name (required) :param keypair_config: the VM's KeypairConfig object (optional) :return: a snaps.domain.VmInst object """ @@ -69,8 +77,13 @@ def create_server(nova, neutron, glance, instance_config, image_config, ports = list() for port_setting in instance_config.port_settings: - ports.append(neutron_utils.get_port( - neutron, port_settings=port_setting)) + port = neutron_utils.get_port( + neutron, keystone, port_settings=port_setting, + project_name=project_name) + if port: + ports.append(port) + else: + raise Exception('Cannot find port named - ' + port_setting.name) nics = [] for port in ports: kv = dict() @@ -115,22 +128,26 @@ def create_server(nova, neutron, glance, instance_config, image_config, server = nova.servers.create(**args) - return __map_os_server_obj_to_vm_inst(neutron, server) + return __map_os_server_obj_to_vm_inst( + neutron, keystone, server, project_name) else: raise NovaException( 'Cannot create instance, image cannot be located with name %s', image_config.name) -def get_server(nova, neutron, vm_inst_settings=None, server_name=None): +def get_server(nova, neutron, keystone, vm_inst_settings=None, + server_name=None, project_id=None): """ Returns a VmInst object for the first server instance found. :param nova: the Nova client :param neutron: the Neutron client + :param keystone: the Keystone client :param vm_inst_settings: the VmInstanceConfig object from which to build the query if not None :param server_name: the server with this name to return if vm_inst_settings is not None + :param project_id: the assocaited project ID :return: a snaps.domain.VmInst object or None if not found """ search_opts = dict() @@ -141,7 +158,8 @@ def get_server(nova, neutron, vm_inst_settings=None, server_name=None): servers = nova.servers.list(search_opts=search_opts) for server in servers: - return __map_os_server_obj_to_vm_inst(neutron, server) + return __map_os_server_obj_to_vm_inst( + neutron, keystone, server, project_id) def get_server_connection(nova, vm_inst_settings=None, server_name=None): @@ -165,11 +183,14 @@ def get_server_connection(nova, vm_inst_settings=None, server_name=None): return server.links[0] -def __map_os_server_obj_to_vm_inst(neutron, os_server): +def __map_os_server_obj_to_vm_inst(neutron, keystone, os_server, + project_name=None): """ Returns a VmInst object for an OpenStack Server object - :param neutron: the Neutron client (when None, ports will be empty) + :param neutron: the Neutron client + :param keystone: the Keystone client :param os_server: the OpenStack server object + :param project_name: the associated project name :return: an equivalent SNAPS-OO VmInst domain object """ sec_grp_names = list() @@ -182,10 +203,17 @@ def __map_os_server_obj_to_vm_inst(neutron, os_server): out_ports = list() if len(os_server.networks) > 0: for net_name, ips in os_server.networks.items(): - network = neutron_utils.get_network(neutron, network_name=net_name) - ports = neutron_utils.get_ports(neutron, network, ips) - for port in ports: - out_ports.append(port) + network = neutron_utils.get_network( + neutron, keystone, network_name=net_name, + project_name=project_name) + if network: + ports = neutron_utils.get_ports(neutron, network, ips) + for port in ports: + out_ports.append(port) + else: + raise NovaException( + 'Unable to locate network in project {} with ' + 'name {}'.format(project_name, net_name)) volumes = None if hasattr(os_server, 'os-extended-volumes:volumes_attached'): @@ -195,7 +223,9 @@ def __map_os_server_obj_to_vm_inst(neutron, os_server): name=os_server.name, inst_id=os_server.id, image_id=os_server.image['id'], flavor_id=os_server.flavor['id'], ports=out_ports, keypair_name=os_server.key_name, - sec_grp_names=sec_grp_names, volume_ids=volumes) + sec_grp_names=sec_grp_names, volume_ids=volumes, + compute_host=os_server._info.get('OS-EXT-SRV-ATTR:host'), + availability_zone=os_server._info.get('OS-EXT-AZ:availability_zone')) def __get_latest_server_os_object(nova, server): @@ -244,28 +274,35 @@ def get_server_console_output(nova, server): return None -def get_latest_server_object(nova, neutron, server): +def get_latest_server_object(nova, neutron, keystone, server, project_name): """ Returns a server with a given id :param nova: the Nova client :param neutron: the Neutron client + :param keystone: the Keystone client :param server: the old server object + :param project_name: the associated project name :return: the list of servers or None if not found """ server = __get_latest_server_os_object(nova, server) - return __map_os_server_obj_to_vm_inst(neutron, server) + return __map_os_server_obj_to_vm_inst( + neutron, keystone, server, project_name) -def get_server_object_by_id(nova, neutron, server_id): +def get_server_object_by_id(nova, neutron, keystone, server_id, + project_name=None): """ Returns a server with a given id :param nova: the Nova client :param neutron: the Neutron client + :param keystone: the Keystone client :param server_id: the server's id + :param project_name: the associated project name :return: an SNAPS-OO VmInst object or None if not found """ server = __get_latest_server_os_object_by_id(nova, server_id) - return __map_os_server_obj_to_vm_inst(neutron, server) + return __map_os_server_obj_to_vm_inst( + neutron, keystone, server, project_name) def get_server_security_group_names(nova, server): @@ -277,8 +314,9 @@ def get_server_security_group_names(nova, server): """ out = list() os_vm_inst = __get_latest_server_os_object(nova, server) - for sec_grp_dict in os_vm_inst.security_groups: - out.append(sec_grp_dict['name']) + if hasattr(os_vm_inst, 'security_groups'): + for sec_grp_dict in os_vm_inst.security_groups: + out.append(sec_grp_dict['name']) return out @@ -673,18 +711,6 @@ def remove_security_group(nova, vm, security_group): nova.servers.remove_security_group(str(vm.id), security_group.name) -def add_floating_ip_to_server(nova, vm, floating_ip, ip_addr): - """ - Adds a floating IP to a server instance - :param nova: the nova client - :param vm: VmInst domain object - :param floating_ip: FloatingIp domain object - :param ip_addr: the IP to which to bind the floating IP to - """ - vm = __get_latest_server_os_object(nova, vm) - vm.add_floating_ip(floating_ip.ip, ip_addr) - - def get_compute_quotas(nova, project_id): """ Returns a list of all available keypairs @@ -720,60 +746,73 @@ def update_quotas(nova, project_id, compute_quotas): return nova.quotas.update(project_id, **update_values) -def attach_volume(nova, neutron, server, volume, timeout=None): +def attach_volume(nova, neutron, keystone, server, volume, project_name, + timeout=120): """ - Attaches a volume to a server + Attaches a volume to a server. When the timeout parameter is used, a VmInst + object with the proper volume updates is returned unless it has not been + updated in the allotted amount of time then an Exception will be raised. :param nova: the nova client :param neutron: the neutron client + :param keystone: the neutron client :param server: the VMInst domain object :param volume: the Volume domain object + :param project_name: the associated project name :param timeout: denotes the amount of time to block to determine if the - has been properly attached. When None, do not wait. - :return: the value from the nova call + has been properly attached. + :return: updated VmInst object """ nova.volumes.create_server_volume(server.id, volume.id) - if timeout: - start_time = time.time() - while time.time() < start_time + timeout: - vm = get_server_object_by_id(nova, neutron, server.id) - for vol_dict in vm.volume_ids: - if volume.id == vol_dict['id']: - return vm + start_time = time.time() + while time.time() < start_time + timeout: + vm = get_server_object_by_id( + nova, neutron, keystone, server.id, project_name) + for vol_dict in vm.volume_ids: + if volume.id == vol_dict['id']: + return vm + time.sleep(POLL_INTERVAL) - return None - else: - return get_server_object_by_id(nova, neutron, server.id) + raise NovaException( + 'Attach failed on volume - {} and server - {}'.format( + volume.id, server.id)) -def detach_volume(nova, neutron, server, volume, timeout=None): +def detach_volume(nova, neutron, keystone, server, volume, project_name, + timeout=120): """ - Attaches a volume to a server + Detaches a volume to a server. When the timeout parameter is used, a VmInst + object with the proper volume updates is returned unless it has not been + updated in the allotted amount of time then an Exception will be raised. :param nova: the nova client :param neutron: the neutron client + :param keystone: the keystone client :param server: the VMInst domain object :param volume: the Volume domain object + :param project_name: the associated project name :param timeout: denotes the amount of time to block to determine if the - has been properly detached. When None, do not wait. - :return: the value from the nova call + has been properly detached. + :return: updated VmInst object """ nova.volumes.delete_server_volume(server.id, volume.id) - if timeout: - start_time = time.time() - while time.time() < start_time + timeout: - vm = get_server_object_by_id(nova, neutron, server.id) - found = False + start_time = time.time() + while time.time() < start_time + timeout: + vm = get_server_object_by_id( + nova, neutron, keystone, server.id, project_name) + if len(vm.volume_ids) == 0: + return vm + else: + ids = list() for vol_dict in vm.volume_ids: - if volume.id == vol_dict['id']: - found = True - - if not found: + ids.append(vol_dict['id']) + if volume.id not in ids: return vm + time.sleep(POLL_INTERVAL) - return None - else: - return get_server_object_by_id(nova, neutron, server.id) + raise NovaException( + 'Detach failed on volume - {} server - {}'.format( + volume.id, server.id)) class RebootType(enum.Enum): |