summaryrefslogtreecommitdiffstats
path: root/snaps/openstack/utils/nova_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'snaps/openstack/utils/nova_utils.py')
-rw-r--r--snaps/openstack/utils/nova_utils.py167
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):