Merge lp:~bgh/nova/qmanager-ipam-fixes into lp:nova/essex

Proposed by Brad Hall
Status: Needs review
Proposed branch: lp:~bgh/nova/qmanager-ipam-fixes
Merge into: lp:nova/essex
Diff against target: 284 lines (+85/-72)
6 files modified
nova/network/quantum/client.py (+0/-2)
nova/network/quantum/manager.py (+42/-22)
nova/network/quantum/melange_ipam_lib.py (+25/-26)
nova/network/quantum/nova_ipam_lib.py (+3/-2)
nova/network/quantum/quantum_connection.py (+10/-14)
nova/tests/test_quantum.py (+5/-6)
To merge this branch: bzr merge lp:~bgh/nova/qmanager-ipam-fixes
Reviewer Review Type Date Requested Status
Nova Core security contacts Pending
Review via email: mp+77438@code.launchpad.net

Description of the change

A couple fixes to the currently experimental QuantumManager (network manager)

To post a comment you must log in.

Unmerged revisions

1647. By Brad Hall

Make sure the network info structure we're returning has a label

1646. By Brad Hall

Fix quantum/melange ipam interaction

We now query for the subnets by net_id/vif_id instead of searching through all
the blocks to find the right one. Both of the allocate and deallocate for
instance calls are now using the vif_id -> network_id mapping instead of
searching the quantum networks. get_port_by_attachment was also changed to
take a net_id so that we don't have to search through all of the quantum
networks to find the corresponding port.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/network/quantum/client.py'
2--- nova/network/quantum/client.py 2011-09-02 20:05:24 +0000
3+++ nova/network/quantum/client.py 2011-09-29 19:57:23 +0000
4@@ -224,8 +224,6 @@
5 type(data)))
6
7 def deserialize(self, data, status_code):
8- if status_code == 202:
9- return data
10 return JSONSerializer().deserialize(data, self.content_type())
11
12 def content_type(self, format=None):
13
14=== modified file 'nova/network/quantum/manager.py'
15--- nova/network/quantum/manager.py 2011-09-02 20:05:24 +0000
16+++ nova/network/quantum/manager.py 2011-09-29 19:57:23 +0000
17@@ -201,15 +201,9 @@
18 vifs = db.virtual_interface_get_by_instance(admin_context,
19 instance_id)
20 for vif in vifs:
21- q_tenant_id = project_id
22- ipam_tenant_id = project_id
23- net_id, port_id = self.q_conn.get_port_by_attachment(q_tenant_id,
24- vif['uuid'])
25- if not net_id:
26- q_tenant_id = FLAGS.quantum_default_tenant_id
27- ipam_tenant_id = None
28- net_id, port_id = self.q_conn.get_port_by_attachment(
29- q_tenant_id, vif['uuid'])
30+ net = db.network_get(admin_context, vif['network_id'])
31+ net_id = net['uuid']
32+
33 if not net_id:
34 # TODO(bgh): We need to figure out a way to tell if we
35 # should actually be raising this exception or not.
36@@ -219,8 +213,19 @@
37 # probably just log, continue, and move on.
38 raise Exception(_("No network for for virtual interface %s") %
39 vif['uuid'])
40+
41+ ipam_tenant_id = project_id
42 (v4_subnet, v6_subnet) = self.ipam.get_subnets_by_net_id(context,
43- ipam_tenant_id, net_id)
44+ ipam_tenant_id, net_id, vif['uuid'])
45+ # There isn't a good way of figuring out what the ipam
46+ # tenant id should be before hand so we have to try both
47+ # (project_id and None).
48+ if not v4_subnet and not v6_subnet:
49+ ipam_tenant_id = None
50+ (v4_subnet, v6_subnet) = \
51+ self.ipam.get_subnets_by_net_id(context,
52+ ipam_tenant_id,
53+ net_id, vif['uuid'])
54 v4_ips = self.ipam.get_v4_ips_by_interface(context,
55 net_id, vif['uuid'],
56 project_id=ipam_tenant_id)
57@@ -242,6 +247,7 @@
58 'multi_host': False}
59
60 info = {
61+ 'label': net['label'],
62 'gateway': v4_subnet['gateway'],
63 'dhcp_server': v4_subnet['gateway'],
64 'broadcast': v4_subnet['broadcast'],
65@@ -283,20 +289,30 @@
66 for vif_ref in vifs:
67 interface_id = vif_ref['uuid']
68 q_tenant_id = project_id
69- ipam_tenant_id = project_id
70- (net_id, port_id) = self.q_conn.get_port_by_attachment(q_tenant_id,
71- interface_id)
72- if not net_id:
73+
74+ net = db.network_get(admin_context, vif_ref['network_id'])
75+ net_id = net['uuid']
76+
77+ port_id = self.q_conn.get_port_by_attachment(q_tenant_id,
78+ net_id, interface_id)
79+ if not port_id:
80 q_tenant_id = FLAGS.quantum_default_tenant_id
81- ipam_tenant_id = None
82- (net_id, port_id) = self.q_conn.get_port_by_attachment(
83- q_tenant_id, interface_id)
84- if not net_id:
85+ port_id = self.q_conn.get_port_by_attachment(
86+ q_tenant_id, net_id, interface_id)
87+
88+ if not port_id:
89 LOG.error("Unable to find port with attachment: %s" %
90 (interface_id))
91- continue
92- self.q_conn.detach_and_delete_port(q_tenant_id,
93- net_id, port_id)
94+ else:
95+ self.q_conn.detach_and_delete_port(q_tenant_id,
96+ net_id, port_id)
97+
98+ # Figure out which ipam tenant id we need here, either the project
99+ # id or None (which corresponds to the provider address space).
100+ if self.ipam.verify_subnet_exists(context, project_id, net_id):
101+ ipam_tenant_id = project_id
102+ else:
103+ ipam_tenant_id = None
104
105 self.ipam.deallocate_ips_by_vif(context, ipam_tenant_id,
106 net_id, vif_ref)
107@@ -319,6 +335,10 @@
108
109 project_id = context.project_id
110 for (net_id, _i) in networks:
111- self.ipam.verify_subnet_exists(context, project_id, net_id)
112+ # TODO(bgh): At some point we should figure out whether or
113+ # not we want the verify_subnet_exists call to be optional.
114+ if not self.ipam.verify_subnet_exists(context, project_id,
115+ net_id):
116+ raise exception.NetworkNotFound(network_id=net_id)
117 if not self.q_conn.network_exists(project_id, net_id):
118 raise exception.NetworkNotFound(network_id=net_id)
119
120=== modified file 'nova/network/quantum/melange_ipam_lib.py'
121--- nova/network/quantum/melange_ipam_lib.py 2011-09-02 20:05:24 +0000
122+++ nova/network/quantum/melange_ipam_lib.py 2011-09-29 19:57:23 +0000
123@@ -134,34 +134,27 @@
124 return [(network_id, tenant_id)
125 for priority, network_id, tenant_id in priority_nets]
126
127- def get_subnets_by_net_id(self, context, project_id, net_id):
128+ def get_subnets_by_net_id(self, context, project_id, net_id, vif_id):
129 """Returns information about the IPv4 and IPv6 subnets
130 associated with a Quantum Network UUID.
131 """
132-
133- # FIXME(danwent): Melange actually returns the subnet info
134- # when we query for a particular interface. We may want to
135- # rework the ipam_manager python API to let us take advantage of
136- # this, as right now we have to get all blocks and cycle through
137- # them.
138 subnet_v4 = None
139 subnet_v6 = None
140 tenant_id = project_id or FLAGS.quantum_default_tenant_id
141- all_blocks = self.m_conn.get_blocks(tenant_id)
142- for b in all_blocks['ip_blocks']:
143- if b['network_id'] == net_id:
144- subnet = {'network_id': b['network_id'],
145- 'cidr': b['cidr'],
146- 'gateway': b['gateway'],
147- 'broadcast': b['broadcast'],
148- 'netmask': b['netmask'],
149- 'dns1': b['dns1'],
150- 'dns2': b['dns2']}
151-
152- if IPNetwork(b['cidr']).version == 6:
153- subnet_v6 = subnet
154- else:
155- subnet_v4 = subnet
156+ ips = self.m_conn.get_allocated_ips(net_id, vif_id, tenant_id)
157+ for ip_address in ips:
158+ block = ip_address['ip_block']
159+ subnet = {'network_id': block['network_id'],
160+ 'cidr': block['cidr'],
161+ 'gateway': block['gateway'],
162+ 'broadcast': block['broadcast'],
163+ 'netmask': block['netmask'],
164+ 'dns1': block['dns1'],
165+ 'dns2': block['dns2']}
166+ if ip_address['version'] == 4:
167+ subnet_v4 = subnet
168+ else:
169+ subnet_v6 = subnet
170 return (subnet_v4, subnet_v6)
171
172 def get_v4_ips_by_interface(self, context, net_id, vif_id, project_id):
173@@ -179,7 +172,7 @@
174 project_id, 6)
175
176 def _get_ips_by_interface(self, context, net_id, vif_id, project_id,
177- ip_version):
178+ ip_version):
179 """Helper method to fetch v4 or v6 addresses for a particular
180 virtual interface.
181 """
182@@ -192,10 +185,16 @@
183 """Confirms that a subnet exists that is associated with the
184 specified Quantum Network UUID.
185 """
186+ # TODO(bgh): Would be nice if we could just do something like:
187+ # GET /ipam/tenants/{tenant_id}/networks/{network_id}/ instead
188+ # of searching through all the blocks. Checking for a 404
189+ # will then determine whether it exists.
190 tenant_id = project_id or FLAGS.quantum_default_tenant_id
191- v4_subnet, v6_subnet = self.get_subnets_by_net_id(context, tenant_id,
192- quantum_net_id)
193- return v4_subnet is not None
194+ all_blocks = self.m_conn.get_blocks(tenant_id)
195+ for b in all_blocks['ip_blocks']:
196+ if b['network_id'] == quantum_net_id:
197+ return True
198+ return False
199
200 def deallocate_ips_by_vif(self, context, project_id, net_id, vif_ref):
201 """Deallocate all fixed IPs associated with the specified
202
203=== modified file 'nova/network/quantum/nova_ipam_lib.py'
204--- nova/network/quantum/nova_ipam_lib.py 2011-09-02 20:05:24 +0000
205+++ nova/network/quantum/nova_ipam_lib.py 2011-09-29 19:57:23 +0000
206@@ -124,7 +124,7 @@
207 'virtual_interface_id': vif_rec['id']}
208 db.fixed_ip_update(admin_context, address, values)
209
210- def get_subnets_by_net_id(self, context, tenant_id, net_id):
211+ def get_subnets_by_net_id(self, context, tenant_id, net_id, _vif_id=None):
212 """Returns information about the IPv4 and IPv6 subnets
213 associated with a Quantum Network UUID.
214 """
215@@ -176,7 +176,8 @@
216 such subnet exists.
217 """
218 admin_context = context.elevated()
219- db.network_get_by_uuid(admin_context, quantum_net_id)
220+ net = db.network_get_by_uuid(admin_context, quantum_net_id)
221+ return net is not None
222
223 def deallocate_ips_by_vif(self, context, tenant_id, net_id, vif_ref):
224 """Deallocate all fixed IPs associated with the specified
225
226=== modified file 'nova/network/quantum/quantum_connection.py'
227--- nova/network/quantum/quantum_connection.py 2011-09-02 20:05:24 +0000
228+++ nova/network/quantum/quantum_connection.py 2011-09-29 19:57:23 +0000
229@@ -98,21 +98,17 @@
230 self.client.detach_resource(net_id, port_id, tenant=tenant_id)
231 self.client.delete_port(net_id, port_id, tenant=tenant_id)
232
233- def get_port_by_attachment(self, tenant_id, attachment_id):
234- """Given a tenant, search for the Quantum network and port
235- UUID that has the specified interface-id attachment.
236+ def get_port_by_attachment(self, tenant_id, net_id, attachment_id):
237+ """Given a tenant and network, search for the port UUID that
238+ has the specified interface-id attachment.
239 """
240 # FIXME(danwent): this will be inefficient until the Quantum
241 # API implements querying a port by the interface-id
242- net_list_resdict = self.client.list_networks(tenant=tenant_id)
243- for n in net_list_resdict["networks"]:
244- net_id = n['id']
245- port_list_resdict = self.client.list_ports(net_id,
246- tenant=tenant_id)
247- for p in port_list_resdict["ports"]:
248- port_id = p["id"]
249- port_get_resdict = self.client.show_port_attachment(net_id,
250+ port_list_resdict = self.client.list_ports(net_id, tenant=tenant_id)
251+ for p in port_list_resdict["ports"]:
252+ port_id = p["id"]
253+ port_get_resdict = self.client.show_port_attachment(net_id,
254 port_id, tenant=tenant_id)
255- if attachment_id == port_get_resdict["attachment"]["id"]:
256- return (net_id, port_id)
257- return (None, None)
258+ if attachment_id == port_get_resdict["attachment"]["id"]:
259+ return port_id
260+ return None
261
262=== modified file 'nova/tests/test_quantum.py'
263--- nova/tests/test_quantum.py 2011-09-02 19:11:28 +0000
264+++ nova/tests/test_quantum.py 2011-09-29 19:57:23 +0000
265@@ -87,14 +87,13 @@
266 "for tenant %(tenant_id)s" % locals()))
267 del self.nets[net_id]['ports'][port_id]
268
269- def get_port_by_attachment(self, tenant_id, attachment_id):
270- for net_id, n in self.nets.items():
271- if n['tenant-id'] == tenant_id:
272+ def get_port_by_attachment(self, tenant_id, net_id, attachment_id):
273+ for nid, n in self.nets.items():
274+ if nid == net_id and n['tenant-id'] == tenant_id:
275 for port_id, p in n['ports'].items():
276 if p['attachment-id'] == attachment_id:
277- return (net_id, port_id)
278-
279- return (None, None)
280+ return port_id
281+ return None
282
283 networks = [{'label': 'project1-net1',
284 'injected': False,

Subscribers

People subscribed via source and target branches