From 38682667c53199e5860c35101ad33c0cdc21e692 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Mon, 6 Feb 2012 01:32:12 -0800 Subject: bug 927507: fix quantum manager get_port_by_attachment - makes query efficient by using Quantum API filters (new in API v1.1) - fixes correctness issue where we did not handle case where network did not exist in quantum (note: this was masked by a quantum bug that will be fixed once this change is into nova). Also included a few other minor things in this patchset: 1) make get_instance_nw_info use network label from DB, which is already available, rather than calling out to quantum just to get the name. 2) quantum manager was not properly cleaning up VIFs in the nova db. This fixes that. 3) set 'bridge' in nw_info dictionary to the empty string, to clearly indicate that this value is ignored by Quantum Manager. Change-Id: Ia1cbb5232f8ce373b605979902f88d7528d3e456 --- nova/network/quantum/client.py | 28 +++++++++++++++++++++------- nova/network/quantum/manager.py | 13 +++---------- nova/network/quantum/quantum_connection.py | 27 +++++++++++++++------------ 3 files changed, 39 insertions(+), 29 deletions(-) (limited to 'nova') diff --git a/nova/network/quantum/client.py b/nova/network/quantum/client.py index 2e5d6f707..edd214326 100644 --- a/nova/network/quantum/client.py +++ b/nova/network/quantum/client.py @@ -44,12 +44,16 @@ class JSONSerializer(object): def deserialize(self, data, content_type): return json.loads(data) +# Quantum API v1.0 uses 420 + 430 for network + port not found +# Quantum API v1.1 uses 404 for network + port not found +NOT_FOUND_CODES = set((404, 420, 430)) + # The full client lib will expose more # granular exceptions, for now, just try to distinguish # between the cases we care about. class QuantumNotFoundException(Exception): - """Indicates that Quantum Server returned 404""" + """Indicates that Quantum Server returned a not-found error code""" pass @@ -90,7 +94,7 @@ class api_call(object): class Client(object): """A base client class - derived from Glance.BaseClient""" - action_prefix = '/v1.0/tenants/{tenant_id}' + action_prefix = '/v1.1/tenants/{tenant_id}' """Action query strings""" networks_path = "/networks" @@ -188,7 +192,7 @@ class Client(object): self.logger.debug("Quantum Client Reply (code = %s) :\n %s" \ % (str(status_code), data)) - if status_code == httplib.NOT_FOUND: + if status_code in NOT_FOUND_CODES: raise QuantumNotFoundException( _("Quantum entity not found: %s" % data)) @@ -233,10 +237,18 @@ class Client(object): format = self.format return "application/%s" % (format) + def append_filter_params(self, url, filter_ops): + if len(filter_ops) > 0: + url += "?" + for fkey, fval in filter_ops.values(): + url += "%s=%s&" % (fkey, fval) + @api_call - def list_networks(self): + def list_networks(self, filter_ops={}): """Fetches a list of all networks for a tenant""" - return self.do_request("GET", self.networks_path) + url = self.networks_path + self.append_filter_params(url, filter_ops) + return self.do_request("GET", url) @api_call def show_network_details(self, network): @@ -261,9 +273,11 @@ class Client(object): return self.do_request("DELETE", self.network_path % (network)) @api_call - def list_ports(self, network): + def list_ports(self, network, filter_ops={}): """Fetches a list of ports on a given network""" - return self.do_request("GET", self.ports_path % (network)) + url = self.ports_path % (network) + self.append_filter_params(url, filter_ops) + return self.do_request("GET", url) @api_call def show_port_details(self, network, port): diff --git a/nova/network/quantum/manager.py b/nova/network/quantum/manager.py index 5e2729cac..8f2aa0a4a 100644 --- a/nova/network/quantum/manager.py +++ b/nova/network/quantum/manager.py @@ -478,9 +478,8 @@ class QuantumManager(manager.FloatingIP, manager.FlatManager): net_tenant_id = FLAGS.quantum_default_tenant_id network = {'id': network['id'], 'uuid': network['uuid'], - 'bridge': 'ovs_flag', - 'label': self.q_conn.get_network_name(net_tenant_id, - network['uuid']), + 'bridge': '', # Quantum ignores this field + 'label': network['label'], 'project_id': net_tenant_id} networks[vif['uuid']] = network @@ -540,6 +539,7 @@ class QuantumManager(manager.FloatingIP, manager.FlatManager): self.ipam.deallocate_ips_by_vif(context, ipam_tenant_id, net_id, vif_ref) + db.virtual_interface_delete(admin_context, vif_ref['id']) # If DHCP is enabled on this network then we need to update the # leases and restart the server. @@ -553,13 +553,6 @@ class QuantumManager(manager.FloatingIP, manager.FlatManager): '|%(instance_id)s|, vif_uuid: |%(vif_uuid)s|') LOG.critical(msg % locals) - try: - db.virtual_interface_delete_by_instance(admin_context, - instance_id) - except exception.InstanceNotFound: - LOG.error(_("Attempted to deallocate non-existent instance: %s" % - (instance_id))) - # TODO(bgh): At some point we should consider merging enable_dhcp() and # update_dhcp() # TODO(tr3buchet): agree, i'm curious why they differ even now.. diff --git a/nova/network/quantum/quantum_connection.py b/nova/network/quantum/quantum_connection.py index d8a4e1a48..ba34d026c 100644 --- a/nova/network/quantum/quantum_connection.py +++ b/nova/network/quantum/quantum_connection.py @@ -117,18 +117,21 @@ class QuantumClientConnection(object): """Given a tenant and network, search for the port UUID that has the specified interface-id attachment. """ - # FIXME(danwent): this will be inefficient until the Quantum - # API implements querying a port by the interface-id - port_list_resdict = self.client.list_ports(net_id, tenant=tenant_id) - for p in port_list_resdict["ports"]: - port_id = p["id"] - port_get_resdict = self.client.show_port_attachment(net_id, - port_id, tenant=tenant_id) - # Skip ports without an attachment - if "id" not in port_get_resdict["attachment"]: - continue - if attachment_id == port_get_resdict["attachment"]["id"]: - return port_id + port_list = [] + try: + port_list_resdict = self.client.list_ports(net_id, + tenant=tenant_id, + filter_ops={'attachment': attachment_id}) + port_list = port_list_resdict["ports"] + except quantum_client.QuantumNotFoundException: + return None + + port_list_len = len(port_list) + if port_list_len != 1: + LOG.error("Expected single port with attachment " + "%(attachment_id)s, found %(port_list_len)s" % locals()) + if port_list_len >= 1: + return port_list[0]['id'] return None def get_attached_ports(self, tenant_id, network_id): -- cgit