Merge lp:~bgh/nova/qmanager-rbp-trunk into lp:~hudson-openstack/nova/trunk

Proposed by Brad Hall
Status: Needs review
Proposed branch: lp:~bgh/nova/qmanager-rbp-trunk
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 289 lines (+85/-73)
7 files modified
bin/nova-manage (+1/-1)
nova/network/quantum/client.py (+0/-2)
nova/network/quantum/manager.py (+41/-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-rbp-trunk
Reviewer Review Type Date Requested Status
Vish Ishaya (community) Approve
Review via email: mp+75598@code.launchpad.net

Description of the change

Various fixes for the quantum network manager related to melange/ipam

To post a comment you must log in.
Revision history for this message
Vish Ishaya (vishvananda) wrote :

This looks like a painless set of fixes for quantum related code.

review: Approve

Unmerged revisions

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