Merge lp:~bgh/nova/qmanager-rbp-trunk into lp:~hudson-openstack/nova/trunk
- qmanager-rbp-trunk
- Merge into 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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Vish Ishaya (community) | Approve | ||
Review via email: mp+75598@code.launchpad.net |
Commit message
Description of the change
Various fixes for the quantum network manager related to melange/ipam
To post a comment you must log in.
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 | 685 | help='Multi host') | 685 | help='Multi host') |
6 | 686 | @args('--dns1', dest="dns1", metavar="<DNS Address>", help='First DNS') | 686 | @args('--dns1', dest="dns1", metavar="<DNS Address>", help='First DNS') |
7 | 687 | @args('--dns2', dest="dns2", metavar="<DNS Address>", help='Second DNS') | 687 | @args('--dns2', dest="dns2", metavar="<DNS Address>", help='Second DNS') |
9 | 688 | @args('--uuid', dest="net_uuid", metavar="<network uuid>", | 688 | @args('--uuid', dest="uuid", metavar="<network uuid>", |
10 | 689 | help='Network UUID') | 689 | help='Network UUID') |
11 | 690 | @args('--project_id', dest="project_id", metavar="<project id>", | 690 | @args('--project_id', dest="project_id", metavar="<project id>", |
12 | 691 | help='Project id') | 691 | help='Project id') |
13 | 692 | 692 | ||
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 | 224 | type(data))) | 224 | type(data))) |
19 | 225 | 225 | ||
20 | 226 | def deserialize(self, data, status_code): | 226 | def deserialize(self, data, status_code): |
21 | 227 | if status_code == 202: | ||
22 | 228 | return data | ||
23 | 229 | return JSONSerializer().deserialize(data, self.content_type()) | 227 | return JSONSerializer().deserialize(data, self.content_type()) |
24 | 230 | 228 | ||
25 | 231 | def content_type(self, format=None): | 229 | def content_type(self, format=None): |
26 | 232 | 230 | ||
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 | 201 | vifs = db.virtual_interface_get_by_instance(admin_context, | 201 | vifs = db.virtual_interface_get_by_instance(admin_context, |
32 | 202 | instance_id) | 202 | instance_id) |
33 | 203 | for vif in vifs: | 203 | for vif in vifs: |
43 | 204 | q_tenant_id = project_id | 204 | net = db.network_get(admin_context, vif['network_id']) |
44 | 205 | ipam_tenant_id = project_id | 205 | net_id = net['uuid'] |
45 | 206 | net_id, port_id = self.q_conn.get_port_by_attachment(q_tenant_id, | 206 | |
37 | 207 | vif['uuid']) | ||
38 | 208 | if not net_id: | ||
39 | 209 | q_tenant_id = FLAGS.quantum_default_tenant_id | ||
40 | 210 | ipam_tenant_id = None | ||
41 | 211 | net_id, port_id = self.q_conn.get_port_by_attachment( | ||
42 | 212 | q_tenant_id, vif['uuid']) | ||
46 | 213 | if not net_id: | 207 | if not net_id: |
47 | 214 | # TODO(bgh): We need to figure out a way to tell if we | 208 | # TODO(bgh): We need to figure out a way to tell if we |
48 | 215 | # should actually be raising this exception or not. | 209 | # should actually be raising this exception or not. |
49 | @@ -219,8 +213,19 @@ | |||
50 | 219 | # probably just log, continue, and move on. | 213 | # probably just log, continue, and move on. |
51 | 220 | raise Exception(_("No network for for virtual interface %s") % | 214 | raise Exception(_("No network for for virtual interface %s") % |
52 | 221 | vif['uuid']) | 215 | vif['uuid']) |
53 | 216 | |||
54 | 217 | ipam_tenant_id = project_id | ||
55 | 222 | (v4_subnet, v6_subnet) = self.ipam.get_subnets_by_net_id(context, | 218 | (v4_subnet, v6_subnet) = self.ipam.get_subnets_by_net_id(context, |
57 | 223 | ipam_tenant_id, net_id) | 219 | ipam_tenant_id, net_id, vif['uuid']) |
58 | 220 | # There isn't a good way of figuring out what the ipam | ||
59 | 221 | # tenant id should be before hand so we have to try both | ||
60 | 222 | # (project_id and None). | ||
61 | 223 | if not v4_subnet and not v6_subnet: | ||
62 | 224 | ipam_tenant_id = None | ||
63 | 225 | (v4_subnet, v6_subnet) = \ | ||
64 | 226 | self.ipam.get_subnets_by_net_id(context, | ||
65 | 227 | ipam_tenant_id, | ||
66 | 228 | net_id, vif['uuid']) | ||
67 | 224 | v4_ips = self.ipam.get_v4_ips_by_interface(context, | 229 | v4_ips = self.ipam.get_v4_ips_by_interface(context, |
68 | 225 | net_id, vif['uuid'], | 230 | net_id, vif['uuid'], |
69 | 226 | project_id=ipam_tenant_id) | 231 | project_id=ipam_tenant_id) |
70 | @@ -283,20 +288,30 @@ | |||
71 | 283 | for vif_ref in vifs: | 288 | for vif_ref in vifs: |
72 | 284 | interface_id = vif_ref['uuid'] | 289 | interface_id = vif_ref['uuid'] |
73 | 285 | q_tenant_id = project_id | 290 | q_tenant_id = project_id |
78 | 286 | ipam_tenant_id = project_id | 291 | |
79 | 287 | (net_id, port_id) = self.q_conn.get_port_by_attachment(q_tenant_id, | 292 | net = db.network_get(admin_context, vif_ref['network_id']) |
80 | 288 | interface_id) | 293 | net_id = net['uuid'] |
81 | 289 | if not net_id: | 294 | |
82 | 295 | port_id = self.q_conn.get_port_by_attachment(q_tenant_id, | ||
83 | 296 | net_id, interface_id) | ||
84 | 297 | if not port_id: | ||
85 | 290 | q_tenant_id = FLAGS.quantum_default_tenant_id | 298 | q_tenant_id = FLAGS.quantum_default_tenant_id |
90 | 291 | ipam_tenant_id = None | 299 | port_id = self.q_conn.get_port_by_attachment( |
91 | 292 | (net_id, port_id) = self.q_conn.get_port_by_attachment( | 300 | q_tenant_id, net_id, interface_id) |
92 | 293 | q_tenant_id, interface_id) | 301 | |
93 | 294 | if not net_id: | 302 | if not port_id: |
94 | 295 | LOG.error("Unable to find port with attachment: %s" % | 303 | LOG.error("Unable to find port with attachment: %s" % |
95 | 296 | (interface_id)) | 304 | (interface_id)) |
99 | 297 | continue | 305 | else: |
100 | 298 | self.q_conn.detach_and_delete_port(q_tenant_id, | 306 | self.q_conn.detach_and_delete_port(q_tenant_id, |
101 | 299 | net_id, port_id) | 307 | net_id, port_id) |
102 | 308 | |||
103 | 309 | # Figure out which ipam tenant id we need here, either the project | ||
104 | 310 | # id or None (which corresponds to the provider address space). | ||
105 | 311 | if self.ipam.verify_subnet_exists(context, project_id, net_id): | ||
106 | 312 | ipam_tenant_id = project_id | ||
107 | 313 | else: | ||
108 | 314 | ipam_tenant_id = None | ||
109 | 300 | 315 | ||
110 | 301 | self.ipam.deallocate_ips_by_vif(context, ipam_tenant_id, | 316 | self.ipam.deallocate_ips_by_vif(context, ipam_tenant_id, |
111 | 302 | net_id, vif_ref) | 317 | net_id, vif_ref) |
112 | @@ -319,6 +334,10 @@ | |||
113 | 319 | 334 | ||
114 | 320 | project_id = context.project_id | 335 | project_id = context.project_id |
115 | 321 | for (net_id, _i) in networks: | 336 | for (net_id, _i) in networks: |
117 | 322 | self.ipam.verify_subnet_exists(context, project_id, net_id) | 337 | # TODO(bgh): At some point we should figure out whether or |
118 | 338 | # not we want the verify_subnet_exists call to be optional. | ||
119 | 339 | if not self.ipam.verify_subnet_exists(context, project_id, | ||
120 | 340 | net_id): | ||
121 | 341 | raise exception.NetworkNotFound(network_id=net_id) | ||
122 | 323 | if not self.q_conn.network_exists(project_id, net_id): | 342 | if not self.q_conn.network_exists(project_id, net_id): |
123 | 324 | raise exception.NetworkNotFound(network_id=net_id) | 343 | raise exception.NetworkNotFound(network_id=net_id) |
124 | 325 | 344 | ||
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 | 134 | return [(network_id, tenant_id) | 134 | return [(network_id, tenant_id) |
130 | 135 | for priority, network_id, tenant_id in priority_nets] | 135 | for priority, network_id, tenant_id in priority_nets] |
131 | 136 | 136 | ||
133 | 137 | def get_subnets_by_net_id(self, context, project_id, net_id): | 137 | def get_subnets_by_net_id(self, context, project_id, net_id, vif_id): |
134 | 138 | """Returns information about the IPv4 and IPv6 subnets | 138 | """Returns information about the IPv4 and IPv6 subnets |
135 | 139 | associated with a Quantum Network UUID. | 139 | associated with a Quantum Network UUID. |
136 | 140 | """ | 140 | """ |
137 | 141 | |||
138 | 142 | # FIXME(danwent): Melange actually returns the subnet info | ||
139 | 143 | # when we query for a particular interface. We may want to | ||
140 | 144 | # rework the ipam_manager python API to let us take advantage of | ||
141 | 145 | # this, as right now we have to get all blocks and cycle through | ||
142 | 146 | # them. | ||
143 | 147 | subnet_v4 = None | 141 | subnet_v4 = None |
144 | 148 | subnet_v6 = None | 142 | subnet_v6 = None |
145 | 149 | tenant_id = project_id or FLAGS.quantum_default_tenant_id | 143 | tenant_id = project_id or FLAGS.quantum_default_tenant_id |
161 | 150 | all_blocks = self.m_conn.get_blocks(tenant_id) | 144 | ips = self.m_conn.get_allocated_ips(net_id, vif_id, tenant_id) |
162 | 151 | for b in all_blocks['ip_blocks']: | 145 | for ip_address in ips: |
163 | 152 | if b['network_id'] == net_id: | 146 | block = ip_address['ip_block'] |
164 | 153 | subnet = {'network_id': b['network_id'], | 147 | subnet = {'network_id': block['network_id'], |
165 | 154 | 'cidr': b['cidr'], | 148 | 'cidr': block['cidr'], |
166 | 155 | 'gateway': b['gateway'], | 149 | 'gateway': block['gateway'], |
167 | 156 | 'broadcast': b['broadcast'], | 150 | 'broadcast': block['broadcast'], |
168 | 157 | 'netmask': b['netmask'], | 151 | 'netmask': block['netmask'], |
169 | 158 | 'dns1': b['dns1'], | 152 | 'dns1': block['dns1'], |
170 | 159 | 'dns2': b['dns2']} | 153 | 'dns2': block['dns2']} |
171 | 160 | 154 | if ip_address['version'] == 4: | |
172 | 161 | if IPNetwork(b['cidr']).version == 6: | 155 | subnet_v4 = subnet |
173 | 162 | subnet_v6 = subnet | 156 | else: |
174 | 163 | else: | 157 | subnet_v6 = subnet |
160 | 164 | subnet_v4 = subnet | ||
175 | 165 | return (subnet_v4, subnet_v6) | 158 | return (subnet_v4, subnet_v6) |
176 | 166 | 159 | ||
177 | 167 | def get_v4_ips_by_interface(self, context, net_id, vif_id, project_id): | 160 | def get_v4_ips_by_interface(self, context, net_id, vif_id, project_id): |
178 | @@ -179,7 +172,7 @@ | |||
179 | 179 | project_id, 6) | 172 | project_id, 6) |
180 | 180 | 173 | ||
181 | 181 | def _get_ips_by_interface(self, context, net_id, vif_id, project_id, | 174 | def _get_ips_by_interface(self, context, net_id, vif_id, project_id, |
183 | 182 | ip_version): | 175 | ip_version): |
184 | 183 | """Helper method to fetch v4 or v6 addresses for a particular | 176 | """Helper method to fetch v4 or v6 addresses for a particular |
185 | 184 | virtual interface. | 177 | virtual interface. |
186 | 185 | """ | 178 | """ |
187 | @@ -192,10 +185,16 @@ | |||
188 | 192 | """Confirms that a subnet exists that is associated with the | 185 | """Confirms that a subnet exists that is associated with the |
189 | 193 | specified Quantum Network UUID. | 186 | specified Quantum Network UUID. |
190 | 194 | """ | 187 | """ |
191 | 188 | # TODO(bgh): Would be nice if we could just do something like: | ||
192 | 189 | # GET /ipam/tenants/{tenant_id}/networks/{network_id}/ instead | ||
193 | 190 | # of searching through all the blocks. Checking for a 404 | ||
194 | 191 | # will then determine whether it exists. | ||
195 | 195 | tenant_id = project_id or FLAGS.quantum_default_tenant_id | 192 | tenant_id = project_id or FLAGS.quantum_default_tenant_id |
199 | 196 | v4_subnet, v6_subnet = self.get_subnets_by_net_id(context, tenant_id, | 193 | all_blocks = self.m_conn.get_blocks(tenant_id) |
200 | 197 | quantum_net_id) | 194 | for b in all_blocks['ip_blocks']: |
201 | 198 | return v4_subnet is not None | 195 | if b['network_id'] == quantum_net_id: |
202 | 196 | return True | ||
203 | 197 | return False | ||
204 | 199 | 198 | ||
205 | 200 | def deallocate_ips_by_vif(self, context, project_id, net_id, vif_ref): | 199 | def deallocate_ips_by_vif(self, context, project_id, net_id, vif_ref): |
206 | 201 | """Deallocate all fixed IPs associated with the specified | 200 | """Deallocate all fixed IPs associated with the specified |
207 | 202 | 201 | ||
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 | 124 | 'virtual_interface_id': vif_rec['id']} | 124 | 'virtual_interface_id': vif_rec['id']} |
213 | 125 | db.fixed_ip_update(admin_context, address, values) | 125 | db.fixed_ip_update(admin_context, address, values) |
214 | 126 | 126 | ||
216 | 127 | def get_subnets_by_net_id(self, context, tenant_id, net_id): | 127 | def get_subnets_by_net_id(self, context, tenant_id, net_id, _vif_id=None): |
217 | 128 | """Returns information about the IPv4 and IPv6 subnets | 128 | """Returns information about the IPv4 and IPv6 subnets |
218 | 129 | associated with a Quantum Network UUID. | 129 | associated with a Quantum Network UUID. |
219 | 130 | """ | 130 | """ |
220 | @@ -176,7 +176,8 @@ | |||
221 | 176 | such subnet exists. | 176 | such subnet exists. |
222 | 177 | """ | 177 | """ |
223 | 178 | admin_context = context.elevated() | 178 | admin_context = context.elevated() |
225 | 179 | db.network_get_by_uuid(admin_context, quantum_net_id) | 179 | net = db.network_get_by_uuid(admin_context, quantum_net_id) |
226 | 180 | return net is not None | ||
227 | 180 | 181 | ||
228 | 181 | def deallocate_ips_by_vif(self, context, tenant_id, net_id, vif_ref): | 182 | def deallocate_ips_by_vif(self, context, tenant_id, net_id, vif_ref): |
229 | 182 | """Deallocate all fixed IPs associated with the specified | 183 | """Deallocate all fixed IPs associated with the specified |
230 | 183 | 184 | ||
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 | 98 | self.client.detach_resource(net_id, port_id, tenant=tenant_id) | 98 | self.client.detach_resource(net_id, port_id, tenant=tenant_id) |
236 | 99 | self.client.delete_port(net_id, port_id, tenant=tenant_id) | 99 | self.client.delete_port(net_id, port_id, tenant=tenant_id) |
237 | 100 | 100 | ||
241 | 101 | def get_port_by_attachment(self, tenant_id, attachment_id): | 101 | def get_port_by_attachment(self, tenant_id, net_id, attachment_id): |
242 | 102 | """Given a tenant, search for the Quantum network and port | 102 | """Given a tenant and network, search for the port UUID that |
243 | 103 | UUID that has the specified interface-id attachment. | 103 | has the specified interface-id attachment. |
244 | 104 | """ | 104 | """ |
245 | 105 | # FIXME(danwent): this will be inefficient until the Quantum | 105 | # FIXME(danwent): this will be inefficient until the Quantum |
246 | 106 | # API implements querying a port by the interface-id | 106 | # API implements querying a port by the interface-id |
255 | 107 | net_list_resdict = self.client.list_networks(tenant=tenant_id) | 107 | port_list_resdict = self.client.list_ports(net_id, tenant=tenant_id) |
256 | 108 | for n in net_list_resdict["networks"]: | 108 | for p in port_list_resdict["ports"]: |
257 | 109 | net_id = n['id'] | 109 | port_id = p["id"] |
258 | 110 | port_list_resdict = self.client.list_ports(net_id, | 110 | port_get_resdict = self.client.show_port_attachment(net_id, |
251 | 111 | tenant=tenant_id) | ||
252 | 112 | for p in port_list_resdict["ports"]: | ||
253 | 113 | port_id = p["id"] | ||
254 | 114 | port_get_resdict = self.client.show_port_attachment(net_id, | ||
259 | 115 | port_id, tenant=tenant_id) | 111 | port_id, tenant=tenant_id) |
263 | 116 | if attachment_id == port_get_resdict["attachment"]["id"]: | 112 | if attachment_id == port_get_resdict["attachment"]["id"]: |
264 | 117 | return (net_id, port_id) | 113 | return port_id |
265 | 118 | return (None, None) | 114 | return None |
266 | 119 | 115 | ||
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 | 87 | "for tenant %(tenant_id)s" % locals())) | 87 | "for tenant %(tenant_id)s" % locals())) |
272 | 88 | del self.nets[net_id]['ports'][port_id] | 88 | del self.nets[net_id]['ports'][port_id] |
273 | 89 | 89 | ||
277 | 90 | def get_port_by_attachment(self, tenant_id, attachment_id): | 90 | def get_port_by_attachment(self, tenant_id, net_id, attachment_id): |
278 | 91 | for net_id, n in self.nets.items(): | 91 | for nid, n in self.nets.items(): |
279 | 92 | if n['tenant-id'] == tenant_id: | 92 | if nid == net_id and n['tenant-id'] == tenant_id: |
280 | 93 | for port_id, p in n['ports'].items(): | 93 | for port_id, p in n['ports'].items(): |
281 | 94 | if p['attachment-id'] == attachment_id: | 94 | if p['attachment-id'] == attachment_id: |
285 | 95 | return (net_id, port_id) | 95 | return port_id |
286 | 96 | 96 | return None | |
284 | 97 | return (None, None) | ||
287 | 98 | 97 | ||
288 | 99 | networks = [{'label': 'project1-net1', | 98 | networks = [{'label': 'project1-net1', |
289 | 100 | 'injected': False, | 99 | 'injected': False, |
This looks like a painless set of fixes for quantum related code.