Merge lp:~ilyaalekseyev/nova/libvirt-multinic-experemental into lp:~openstack-gd/nova/multi-nic-exp-fix
- libvirt-multinic-experemental
- Merge into multi-nic-exp-fix
Proposed by
Eldar Nugaev
Status: | Work in progress |
---|---|
Proposed branch: | lp:~ilyaalekseyev/nova/libvirt-multinic-experemental |
Merge into: | lp:~openstack-gd/nova/multi-nic-exp-fix |
Diff against target: |
1238 lines (+560/-178) 16 files modified
bin/nova-manage (+5/-0) nova/compute/api.py (+10/-2) nova/compute/manager.py (+23/-16) nova/db/api.py (+27/-8) nova/db/sqlalchemy/api.py (+137/-31) nova/db/sqlalchemy/migrate_repo/versions/011_add_multinic_tables.py (+93/-0) nova/db/sqlalchemy/models.py (+39/-4) nova/network/manager.py (+45/-7) nova/tests/test_cloud.py (+1/-1) nova/tests/test_compute.py (+1/-1) nova/tests/test_console.py (+1/-1) nova/tests/test_network.py (+57/-12) nova/tests/test_quota.py (+1/-1) nova/tests/test_virt.py (+7/-5) nova/virt/libvirt.xml.template (+10/-8) nova/virt/libvirt_conn.py (+103/-81) |
To merge this branch: | bzr merge lp:~ilyaalekseyev/nova/libvirt-multinic-experemental |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ilya Alekseyev (community) | Abstain | ||
Review via email: mp+53819@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Unmerged revisions
- 716. By Ilya Alekseyev
-
merge with reldan tests and fixes
- 715. By Ilya Alekseyev
-
bugfix
- 714. By Ilya Alekseyev
-
bugfix
- 713. By Ilya Alekseyev
-
fixed ip lease and release & floating ips getter
- 712. By Ilya Alekseyev
-
bug & test fix
- 711. By Ilya Alekseyev
-
bug & test fix
- 710. By Ilya Alekseyev
-
Merge with trunk and bugfix
- 709. By Ilya Alekseyev
-
model migration
- 708. By Ilya Alekseyev
-
Merge with trunk
- 707. By Ilya Alekseyev
-
fixing merge trouble
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-03-16 17:06:30 +0000 |
3 | +++ bin/nova-manage 2011-03-17 13:48:33 +0000 |
4 | @@ -555,6 +555,11 @@ |
5 | network.dhcp_start, |
6 | network.dns) |
7 | |
8 | + |
9 | + def associate(self, project_id, cidr): |
10 | + """Associate network with project""" |
11 | + db.network_associate(context.get_admin_context(), project_id, cidr) |
12 | + |
13 | def delete(self, fixed_range): |
14 | """Deletes a network""" |
15 | network = db.network_get_by_cidr(context.get_admin_context(), \ |
16 | |
17 | === modified file 'nova/compute/api.py' |
18 | --- nova/compute/api.py 2011-03-15 21:56:00 +0000 |
19 | +++ nova/compute/api.py 2011-03-17 13:48:33 +0000 |
20 | @@ -213,12 +213,20 @@ |
21 | instances = [] |
22 | LOG.debug(_("Going to run %s instances..."), num_instances) |
23 | for num in range(num_instances): |
24 | - instance = dict(mac_address=utils.generate_mac(), |
25 | + instance = dict(#mac_address=utils.generate_mac(), |
26 | launch_index=num, |
27 | **base_options) |
28 | instance = self.db.instance_create(context, instance) |
29 | instance_id = instance['id'] |
30 | |
31 | + networks = self.db.network_get_all_by_project(context, |
32 | + context.project_id) |
33 | + for net in networks: |
34 | + nic = dict(mac_address=utils.generate_mac(), |
35 | + instance_id=instance_id, |
36 | + network_id=net.id) |
37 | + self.db.nic_create(context, nic) |
38 | + |
39 | elevated = context.elevated() |
40 | if not security_groups: |
41 | security_groups = [] |
42 | @@ -611,4 +619,4 @@ |
43 | def associate_floating_ip(self, context, instance_id, address): |
44 | instance = self.get(context, instance_id) |
45 | self.network_api.associate_floating_ip(context, address, |
46 | - instance['fixed_ip']) |
47 | + instance['fixed_ip'][0]) |
48 | |
49 | === modified file 'nova/compute/manager.py' |
50 | --- nova/compute/manager.py 2011-03-15 21:56:00 +0000 |
51 | +++ nova/compute/manager.py 2011-03-17 13:48:33 +0000 |
52 | @@ -199,11 +199,17 @@ |
53 | # a call to ensure that network setup completes. We |
54 | # will eventually also need to save the address here. |
55 | if not FLAGS.stub_network: |
56 | - address = rpc.call(context, |
57 | - self.get_network_topic(context), |
58 | - {"method": "allocate_fixed_ip", |
59 | - "args": {"instance_id": instance_id, |
60 | - "vpn": is_vpn}}) |
61 | + #address = rpc.call(context, |
62 | + # self.get_network_topic(context), |
63 | + # {"method": "allocate_fixed_ip", |
64 | + # "args": {"instance_id": instance_id, |
65 | + # "vpn": is_vpn}}) |
66 | + |
67 | + addresses = rpc.call(context, |
68 | + self.get_network_topic(context), |
69 | + {"method": "allocate_fixed_ips", |
70 | + "args":{"instance_id": instance_id, |
71 | + "vpn": is_vpn}}) |
72 | |
73 | self.network_manager.setup_compute_network(context, |
74 | instance_id) |
75 | @@ -237,8 +243,8 @@ |
76 | instance_ref = self.db.instance_get(context, instance_id) |
77 | LOG.audit(_("Terminating instance %s"), instance_id, context=context) |
78 | |
79 | - fixed_ip = instance_ref.get('fixed_ip') |
80 | - if not FLAGS.stub_network and fixed_ip: |
81 | + fixed_ips = instance_ref.get('fixed_ips') |
82 | + if not FLAGS.stub_network and fixed_ips: |
83 | floating_ips = fixed_ip.get('floating_ips') or [] |
84 | for floating_ip in floating_ips: |
85 | address = floating_ip['address'] |
86 | @@ -255,15 +261,16 @@ |
87 | {"method": "disassociate_floating_ip", |
88 | "args": {"floating_address": address}}) |
89 | |
90 | - address = fixed_ip['address'] |
91 | - if address: |
92 | - LOG.debug(_("Deallocating address %s"), address, |
93 | - context=context) |
94 | - # NOTE(vish): Currently, nothing needs to be done on the |
95 | - # network node until release. If this changes, |
96 | - # we will need to cast here. |
97 | - self.network_manager.deallocate_fixed_ip(context.elevated(), |
98 | - address) |
99 | + for fixed_ip in fixed_ips: |
100 | + address = fixed_ip['address'] |
101 | + if address: |
102 | + LOG.debug(_("Deallocating address %s"), address, |
103 | + context=context) |
104 | + # NOTE(vish): Currently, nothing needs to be done on the |
105 | + # network node until release. If this changes, |
106 | + # we will need to cast here. |
107 | + self.network_manager.deallocate_fixed_ip(context.elevated(), |
108 | + address) |
109 | |
110 | volumes = instance_ref.get('volumes') or [] |
111 | for volume in volumes: |
112 | |
113 | === modified file 'nova/db/api.py' |
114 | --- nova/db/api.py 2011-03-15 07:45:35 +0000 |
115 | +++ nova/db/api.py 2011-03-17 13:48:33 +0000 |
116 | @@ -435,13 +435,13 @@ |
117 | return IMPL.instance_get_all_by_reservation(context, reservation_id) |
118 | |
119 | |
120 | -def instance_get_fixed_address(context, instance_id): |
121 | +def instance_get_fixed_address(context, instance_id, network_id): |
122 | """Get the fixed ip address of an instance.""" |
123 | - return IMPL.instance_get_fixed_address(context, instance_id) |
124 | - |
125 | - |
126 | -def instance_get_fixed_address_v6(context, instance_id): |
127 | - return IMPL.instance_get_fixed_address_v6(context, instance_id) |
128 | + return IMPL.instance_get_fixed_address(context, instance_id, network_id) |
129 | + |
130 | + |
131 | +def instance_get_fixed_address_v6(context, instance_id, network_id): |
132 | + return IMPL.instance_get_fixed_address_v6(context, instance_id, network_id) |
133 | |
134 | |
135 | def instance_get_floating_address(context, instance_id): |
136 | @@ -541,9 +541,9 @@ |
137 | #################### |
138 | |
139 | |
140 | -def network_associate(context, project_id): |
141 | +def network_associate(context, project_id, cidr=None): |
142 | """Associate a free network to a project.""" |
143 | - return IMPL.network_associate(context, project_id) |
144 | + return IMPL.network_associate(context, project_id, cidr) |
145 | |
146 | |
147 | def network_count(context): |
148 | @@ -633,6 +633,9 @@ |
149 | """Get all networks by instance id or raise if none exist.""" |
150 | return IMPL.network_get_all_by_instance(context, instance_id) |
151 | |
152 | +def network_get_all_by_project(context, project_id): |
153 | + return IMPL.network_get_all_by_project(context, project_id) |
154 | + |
155 | |
156 | def network_get_index(context, network_id): |
157 | """Get non-conflicting index for network.""" |
158 | @@ -1171,3 +1174,19 @@ |
159 | def zone_get_all(context): |
160 | """Get all child Zones.""" |
161 | return IMPL.zone_get_all(context) |
162 | + |
163 | + |
164 | +#################### |
165 | + |
166 | + |
167 | +def nic_create(context, nic): |
168 | + """Create new network interface card""" |
169 | + return IMPL.nic_create(context, nic) |
170 | + |
171 | +def nic_get_by_network_and_instance(context, instance_id, network_id): |
172 | + """Get network interface card by instance and network""" |
173 | + return IMPL.nic_get_by_network_and_instance(context, |
174 | + instance_id, |
175 | + network_id) |
176 | +def nic_get_all(context): |
177 | + return IMPL.nic_get_all(context) |
178 | \ No newline at end of file |
179 | |
180 | === modified file 'nova/db/sqlalchemy/api.py' |
181 | --- nova/db/sqlalchemy/api.py 2011-03-15 07:45:35 +0000 |
182 | +++ nova/db/sqlalchemy/api.py 2011-03-17 13:48:33 +0000 |
183 | @@ -29,10 +29,12 @@ |
184 | from nova.db.sqlalchemy import models |
185 | from nova.db.sqlalchemy.session import get_session |
186 | from sqlalchemy import or_ |
187 | +from sqlalchemy import not_ |
188 | from sqlalchemy.exc import IntegrityError |
189 | from sqlalchemy.orm import joinedload |
190 | from sqlalchemy.orm import joinedload_all |
191 | from sqlalchemy.sql import exists |
192 | +from sqlalchemy.sql import select |
193 | from sqlalchemy.sql import func |
194 | from sqlalchemy.sql.expression import literal_column |
195 | |
196 | @@ -730,6 +732,7 @@ |
197 | mac = utils.to_mac(address) |
198 | |
199 | result = session.query(models.Instance).\ |
200 | + join(models.Instance.mac_address).\ |
201 | filter_by(mac_address=mac).\ |
202 | first() |
203 | return result |
204 | @@ -751,9 +754,36 @@ |
205 | fixed_ip_ref.update(values) |
206 | fixed_ip_ref.save(session=session) |
207 | |
208 | - |
209 | -################### |
210 | - |
211 | +################### |
212 | + |
213 | +@require_context |
214 | +def nic_create(context, values): |
215 | + """Create a new NIC for instance""" |
216 | + |
217 | + nic_ref = models.NetworkInterfaceCard() |
218 | + nic_ref.update(values) |
219 | + |
220 | + session = get_session() |
221 | + with session.begin(): |
222 | + nic_ref.save(session=session) |
223 | + return nic_ref |
224 | + |
225 | +@require_context |
226 | +def nic_get_by_network_and_instance(context, instance_id, network_id): |
227 | + session = get_session() |
228 | + nic = session.query(models.NetworkInterfaceCard).\ |
229 | + filter_by(instance_id=instance_id).\ |
230 | + filter_by(network_id=network_id).\ |
231 | + filter_by(deleted=False).\ |
232 | + first() |
233 | + return nic |
234 | + |
235 | +@require_context |
236 | +def nic_get_all(context): |
237 | + session = get_session() |
238 | + return session.query(models.NetworkInterfaceCard) |
239 | + |
240 | +################### |
241 | |
242 | @require_context |
243 | def instance_create(context, values): |
244 | @@ -763,11 +793,36 @@ |
245 | values - dict containing column values. |
246 | """ |
247 | instance_ref = models.Instance() |
248 | + mac_addresses = None |
249 | + networks=[None] |
250 | + if values.get('mac_address'): |
251 | + if type(values['mac_address']).__name__ == 'str': |
252 | + mac_addresses = [values['mac_address']] |
253 | + elif type(values['mac_address']).__name__ == 'list': |
254 | + mac_addresses = values['mac_address'] |
255 | + del values['mac_address'] |
256 | + networks = networks * len(mac_addresses) |
257 | + |
258 | + if values.get('networks'): |
259 | + if type(values['networks']).__name__ == 'list': |
260 | + networks = values['networks'] |
261 | + else: |
262 | + networks = [values['networks']] |
263 | + del values['networks'] |
264 | instance_ref.update(values) |
265 | |
266 | session = get_session() |
267 | with session.begin(): |
268 | instance_ref.save(session=session) |
269 | + if mac_addresses: |
270 | + for i in range(0, len(mac_addresses)): |
271 | + mac_address = mac_addresses[i] |
272 | + network_id = networks[i] |
273 | + nic = models.NetworkInterfaceCard() |
274 | + nic.update({'instance_id': instance_ref['id'], |
275 | + 'mac_address': mac_address, |
276 | + 'network_id': network_id}) |
277 | + nic.save(session=session) |
278 | return instance_ref |
279 | |
280 | |
281 | @@ -797,6 +852,11 @@ |
282 | update({'deleted': 1, |
283 | 'deleted_at': datetime.datetime.utcnow(), |
284 | 'updated_at': literal_column('updated_at')}) |
285 | + session.query(models.NetworkInterfaceCard).\ |
286 | + filter_by(instance_id=instance_id).\ |
287 | + update({'deleted': 1, |
288 | + 'deleted_at': datetime.datetime.utcnow(), |
289 | + 'updated_at': literal_column('updated_at')}) |
290 | |
291 | |
292 | @require_context |
293 | @@ -918,23 +978,29 @@ |
294 | |
295 | |
296 | @require_context |
297 | -def instance_get_fixed_address(context, instance_id): |
298 | +def instance_get_fixed_address(context, instance_id, network_id): |
299 | session = get_session() |
300 | - with session.begin(): |
301 | - instance_ref = instance_get(context, instance_id, session=session) |
302 | - if not instance_ref.fixed_ip: |
303 | - return None |
304 | - return instance_ref.fixed_ip['address'] |
305 | + fixed_ip_ref = session.query(models.FixedIp).\ |
306 | + filter_by(id=instance_id).\ |
307 | + filter_by(network_id=network_id).\ |
308 | + first() |
309 | + if fixed_ip_ref is None: |
310 | + return None |
311 | + |
312 | + return fixed_ip_ref['address'] |
313 | |
314 | |
315 | @require_context |
316 | -def instance_get_fixed_address_v6(context, instance_id): |
317 | +def instance_get_fixed_address_v6(context, instance_id, network_id): |
318 | session = get_session() |
319 | with session.begin(): |
320 | instance_ref = instance_get(context, instance_id, session=session) |
321 | - network_ref = network_get_by_instance(context, instance_id) |
322 | + #network_ref = network_get_by_instance(context, instance_id) |
323 | + network_ref = network_get(context, network_id, session) |
324 | prefix = network_ref.cidr_v6 |
325 | - mac = instance_ref.mac_address |
326 | + nic = nic_get_by_network_and_instance(context, network_id=network_id, |
327 | + instance_id=instance_id) |
328 | + mac = nic.mac_address |
329 | return utils.to_global_ipv6(prefix, mac) |
330 | |
331 | |
332 | @@ -945,10 +1011,15 @@ |
333 | instance_ref = instance_get(context, instance_id, session=session) |
334 | if not instance_ref.fixed_ip: |
335 | return None |
336 | - if not instance_ref.fixed_ip.floating_ips: |
337 | + floating_ips = [] |
338 | + for ip in instance_ref.fixed_ip: |
339 | + if ip.floating_ips: |
340 | + floating_ips.extend(ip.floating_ips) |
341 | + |
342 | + if len(floating_ips) == 0: |
343 | return None |
344 | # NOTE(vish): this just returns the first floating ip |
345 | - return instance_ref.fixed_ip.floating_ips[0]['address'] |
346 | + return floating_ips[0]['address'] |
347 | |
348 | |
349 | @require_admin_context |
350 | @@ -1115,21 +1186,42 @@ |
351 | ################### |
352 | |
353 | |
354 | -@require_admin_context |
355 | -def network_associate(context, project_id): |
356 | +@require_context |
357 | +def network_associate(context, project_id, cidr=None): |
358 | session = get_session() |
359 | with session.begin(): |
360 | - network_ref = session.query(models.Network).\ |
361 | - filter_by(deleted=False).\ |
362 | - filter_by(project_id=None).\ |
363 | - with_lockmode('update').\ |
364 | - first() |
365 | - # NOTE(vish): if with_lockmode isn't supported, as in sqlite, |
366 | - # then this has concurrency issues |
367 | - if not network_ref: |
368 | - raise db.NoMoreNetworks() |
369 | - network_ref['project_id'] = project_id |
370 | + if cidr is None: |
371 | + network_ref = session.query(models.Network).\ |
372 | + filter_by(deleted=False).\ |
373 | + filter_by(project_id=None).\ |
374 | + filter(not_(models. |
375 | + Network.id.in_(select([models. |
376 | + NetworkProjectAssociation.network_id])))).\ |
377 | + with_lockmode('update').\ |
378 | + first() |
379 | + # NOTE(vish): if with_lockmode isn't supported, as in sqlite, |
380 | + # then this has concurrency issues |
381 | + if not network_ref: |
382 | + raise db.NoMoreNetworks() |
383 | + else: |
384 | + network_ref = session.query(models.Network).\ |
385 | + filter_by(deleted=False).\ |
386 | + filter_by(project_id=None).\ |
387 | + filter_by(cidr=cidr).\ |
388 | + with_lockmode('update').\ |
389 | + first() |
390 | + |
391 | + if not network_ref: |
392 | + raise db.NoMoreNetworks() |
393 | + |
394 | + if cidr is None and not network_ref['project_id']: |
395 | + network_ref['project_id'] = project_id |
396 | + |
397 | + association = models.NetworkProjectAssociation() |
398 | + association.project_id=project_id |
399 | + association.network_id=network_ref['id'] |
400 | session.add(network_ref) |
401 | + session.add(association) |
402 | return network_ref |
403 | |
404 | |
405 | @@ -1232,7 +1324,7 @@ |
406 | @require_admin_context |
407 | def network_get_all(context): |
408 | session = get_session() |
409 | - result = session.query(models.Network) |
410 | + result = session.query(models.Network).all() |
411 | if not result: |
412 | raise exception.NotFound(_('No networks defined')) |
413 | return result |
414 | @@ -1284,7 +1376,7 @@ |
415 | session = get_session() |
416 | rv = session.query(models.Network).\ |
417 | filter_by(deleted=False).\ |
418 | - join(models.Network.fixed_ips).\ |
419 | + join(models.Network.fixed_ip).\ |
420 | filter_by(instance_id=instance_id).\ |
421 | filter_by(deleted=False).\ |
422 | first() |
423 | @@ -1292,19 +1384,33 @@ |
424 | raise exception.NotFound(_('No network for instance %s') % instance_id) |
425 | return rv |
426 | |
427 | - |
428 | @require_admin_context |
429 | def network_get_all_by_instance(_context, instance_id): |
430 | session = get_session() |
431 | rv = session.query(models.Network).\ |
432 | filter_by(deleted=False).\ |
433 | - join(models.Network.fixed_ips).\ |
434 | + join(models.Network.fixed_ip).\ |
435 | filter_by(instance_id=instance_id).\ |
436 | filter_by(deleted=False) |
437 | if not rv: |
438 | raise exception.NotFound(_('No network for instance %s') % instance_id) |
439 | return rv |
440 | |
441 | +@require_context |
442 | +def network_get_all_by_project(context, project_id): |
443 | + session = get_session() |
444 | + nets = session.query(models.Network).\ |
445 | + filter_by(deleted=False).\ |
446 | + filter_by(project_id=None).\ |
447 | + join(models.Network.projects).\ |
448 | + filter_by(id=project_id).\ |
449 | + filter_by(deleted=False).\ |
450 | + all() |
451 | + if len(nets) == 0: |
452 | + nets=[project_get_network(context, project_id)] |
453 | + |
454 | + return nets |
455 | + |
456 | |
457 | @require_admin_context |
458 | def network_set_host(context, network_id, host_id): |
459 | @@ -2313,7 +2419,7 @@ |
460 | return result |
461 | |
462 | |
463 | - ################## |
464 | +#################### |
465 | |
466 | |
467 | @require_admin_context |
468 | |
469 | === added file 'nova/db/sqlalchemy/migrate_repo/versions/011_add_multinic_tables.py' |
470 | --- nova/db/sqlalchemy/migrate_repo/versions/011_add_multinic_tables.py 1970-01-01 00:00:00 +0000 |
471 | +++ nova/db/sqlalchemy/migrate_repo/versions/011_add_multinic_tables.py 2011-03-17 13:48:33 +0000 |
472 | @@ -0,0 +1,93 @@ |
473 | +# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
474 | + |
475 | +# Copyright 2011 Ilya Alekseyev. |
476 | +# All Rights Reserved. |
477 | +# |
478 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
479 | +# not use this file except in compliance with the License. You may obtain |
480 | +# a copy of the License at |
481 | +# |
482 | +# http://www.apache.org/licenses/LICENSE-2.0 |
483 | +# |
484 | +# Unless required by applicable law or agreed to in writing, software |
485 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
486 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
487 | +# License for the specific language governing permissions and limitations |
488 | +# under the License.from sqlalchemy import * |
489 | + |
490 | +from sqlalchemy import * |
491 | +from migrate import * |
492 | + |
493 | +from nova import log as logging |
494 | + |
495 | +meta = MetaData() |
496 | + |
497 | +# Just for the ForeignKey and column creation to succeed. |
498 | +instances = Table('instances', meta, |
499 | + Column('id', Integer(), primary_key=True, nullable=False), |
500 | + Column('mac_address', String(255)) |
501 | + ) |
502 | + |
503 | +networks = Table('networks', meta, |
504 | + Column('id', Integer(), primary_key=True, nullable=False) |
505 | + ) |
506 | + |
507 | +projects = Table('projects', meta, |
508 | + Column('id', |
509 | + String(length=255, convert_unicode=False, assert_unicode=None, |
510 | + unicode_error=None, _warn_on_bytestring=False), |
511 | + primary_key=True, |
512 | + nullable=False) |
513 | + ) |
514 | + |
515 | +# Tables for creation |
516 | + |
517 | +network_interface_cards = Table('network_interface_cards', meta, |
518 | + Column('created_at', DateTime(timezone=False)), |
519 | + Column('updated_at', DateTime(timezone=False)), |
520 | + Column('deleted_at', DateTime(timezone=False)), |
521 | + Column('deleted', Boolean(create_constraint=True, name=None)), |
522 | + Column('id', Integer(), primary_key=True), |
523 | + Column('instance_id', Integer(), ForeignKey('instances.id')), |
524 | + Column('network_id', Integer(), ForeignKey('networks.id')), |
525 | + Column('mac_address', String(255)) |
526 | +) |
527 | + |
528 | +network_project_association = Table('project_network_association', meta, |
529 | + Column('created_at', DateTime(timezone=False)), |
530 | + Column('updated_at', DateTime(timezone=False)), |
531 | + Column('deleted_at', DateTime(timezone=False)), |
532 | + Column('deleted', Boolean(create_constraint=True, name=None)), |
533 | + Column('project_id', String(255), ForeignKey('projects.id'), |
534 | + primary_key=True, nullable=True), |
535 | + Column('network_id', Integer(), ForeignKey('networks.id'), |
536 | + primary_key=True, nullable=True), |
537 | +) |
538 | + |
539 | + |
540 | +def upgrade(migrate_engine): |
541 | + # Upgrade operations go here. Don't create your own engine; bind migrate_engine |
542 | + # to your metadata |
543 | + meta.bind = migrate_engine |
544 | + for table in [network_interface_cards, network_project_association]: |
545 | + try: |
546 | + table.create() |
547 | + except Exception: |
548 | + logging.info(repr(table)) |
549 | + logging.exception('Exception while creating table') |
550 | + meta.drop_all(tables=tables) |
551 | + raise |
552 | + |
553 | + |
554 | +def downgrade(migrate_engine): |
555 | + # Operations to reverse the above upgrade go here. |
556 | + meta.bind = migrate_engine |
557 | + for table in [network_interface_cards, network_project_association]: |
558 | + try: |
559 | + table.drop() |
560 | + except Exception: |
561 | + logging.info(repr(table)) |
562 | + logging.exception('Exception while creating table') |
563 | + meta.drop_all(tables=tables) |
564 | + raise |
565 | + |
566 | |
567 | === modified file 'nova/db/sqlalchemy/models.py' |
568 | --- nova/db/sqlalchemy/models.py 2011-03-15 21:56:00 +0000 |
569 | +++ nova/db/sqlalchemy/models.py 2011-03-17 13:48:33 +0000 |
570 | @@ -22,7 +22,7 @@ |
571 | import datetime |
572 | |
573 | from sqlalchemy.orm import relationship, backref, object_mapper |
574 | -from sqlalchemy import Column, Integer, String, schema |
575 | +from sqlalchemy import Column, Integer, Float, String, schema |
576 | from sqlalchemy import ForeignKey, DateTime, Boolean, Text |
577 | from sqlalchemy.exc import IntegrityError |
578 | from sqlalchemy.ext.declarative import declarative_base |
579 | @@ -214,7 +214,7 @@ |
580 | user_data = Column(Text) |
581 | |
582 | reservation_id = Column(String(255)) |
583 | - mac_address = Column(String(255)) |
584 | + #mac_address = Column(String(255)) |
585 | |
586 | scheduled_at = Column(DateTime) |
587 | launched_at = Column(DateTime) |
588 | @@ -245,6 +245,21 @@ |
589 | # 'shutdown', 'shutoff', 'crashed']) |
590 | |
591 | |
592 | +class InstanceDiagnostics(BASE, NovaBase): |
593 | + """Represents a guest VM's diagnostics""" |
594 | + __tablename__ = "instance_diagnostics" |
595 | + id = Column(Integer, primary_key=True) |
596 | + instance_id = Column(Integer, ForeignKey('instances.id')) |
597 | + |
598 | + memory_available = Column(Float) |
599 | + memory_free = Column(Float) |
600 | + cpu_load = Column(Float) |
601 | + disk_read = Column(Float) |
602 | + disk_write = Column(Float) |
603 | + net_tx = Column(Float) |
604 | + net_rx = Column(Float) |
605 | + |
606 | + |
607 | class InstanceActions(BASE, NovaBase): |
608 | """Represents a guest VM's actions and results""" |
609 | __tablename__ = "instance_actions" |
610 | @@ -497,10 +512,10 @@ |
611 | id = Column(Integer, primary_key=True) |
612 | address = Column(String(255)) |
613 | network_id = Column(Integer, ForeignKey('networks.id'), nullable=True) |
614 | - network = relationship(Network, backref=backref('fixed_ips')) |
615 | + network = relationship(Network, backref=backref('fixed_ip')) |
616 | instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True) |
617 | instance = relationship(Instance, |
618 | - backref=backref('fixed_ip', uselist=False), |
619 | + backref=backref('fixed_ip'), |
620 | foreign_keys=instance_id, |
621 | primaryjoin='and_(' |
622 | 'FixedIp.instance_id == Instance.id,' |
623 | @@ -537,6 +552,9 @@ |
624 | members = relationship(User, |
625 | secondary='user_project_association', |
626 | backref='projects') |
627 | + networks = relationship(Network, |
628 | + secondary='project_network_association', |
629 | + backref='projects') |
630 | |
631 | |
632 | class UserProjectRoleAssociation(BASE, NovaBase): |
633 | @@ -560,6 +578,23 @@ |
634 | 'user_project_association.project_id']) |
635 | |
636 | |
637 | +class NetworkInterfaceCard(BASE, NovaBase): |
638 | + """Represents a guest VM's NIC's""" |
639 | + __tablename__ = "network_interface_cards" |
640 | + id = Column(Integer, primary_key=True) |
641 | + instance_id = Column(Integer, ForeignKey('instances.id')) |
642 | + instance = relationship(Instance, backref=backref('mac_address')) |
643 | + mac_address = Column(String(255)) |
644 | + network_id = Column(Integer, ForeignKey('networks.id')) |
645 | + |
646 | + |
647 | +class NetworkProjectAssociation(BASE, NovaBase): |
648 | + """Represents network to project association""" |
649 | + __tablename__ = "project_network_association" |
650 | + project_id = Column(String(255), ForeignKey(Project.id), primary_key=True) |
651 | + network_id = Column(Integer, ForeignKey(Network.id),primary_key=True) |
652 | + |
653 | + |
654 | class UserRoleAssociation(BASE, NovaBase): |
655 | __tablename__ = 'user_role_association' |
656 | user_id = Column(String(255), ForeignKey('users.id'), primary_key=True) |
657 | |
658 | === modified file 'nova/network/manager.py' |
659 | --- nova/network/manager.py 2011-03-09 18:16:26 +0000 |
660 | +++ nova/network/manager.py 2011-03-17 13:48:33 +0000 |
661 | @@ -223,11 +223,17 @@ |
662 | LOG.debug(_("Leasing IP %s"), address, context=context) |
663 | fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address) |
664 | instance_ref = fixed_ip_ref['instance'] |
665 | + network_ref = fixed_ip_ref['network'] |
666 | if not instance_ref: |
667 | raise exception.Error(_("IP %s leased that isn't associated") % |
668 | address) |
669 | - if instance_ref['mac_address'] != mac: |
670 | - inst_addr = instance_ref['mac_address'] |
671 | + if not network_ref: |
672 | + raise exception.Error(_("IP %s leased that isn't in network") % |
673 | + address) |
674 | + macs = [x.mac_address for x in instance_ref['mac_address'] |
675 | + if x.network_id == network_ref['id']] |
676 | + if len(macs) != 0 and macs[0] != mac: |
677 | + inst_addr = macs[0] |
678 | raise exception.Error(_("IP %(address)s leased to bad" |
679 | " mac %(inst_addr)s vs %(mac)s") % locals()) |
680 | now = datetime.datetime.utcnow() |
681 | @@ -244,11 +250,17 @@ |
682 | LOG.debug(_("Releasing IP %s"), address, context=context) |
683 | fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address) |
684 | instance_ref = fixed_ip_ref['instance'] |
685 | + network_ref = fixed_ip_ref['network'] |
686 | if not instance_ref: |
687 | raise exception.Error(_("IP %s released that isn't associated") % |
688 | address) |
689 | - if instance_ref['mac_address'] != mac: |
690 | - inst_addr = instance_ref['mac_address'] |
691 | + if not network_ref: |
692 | + raise exception.Error(_("IP %s leased that isn't in network") % |
693 | + address) |
694 | + macs = [x.mac_address for x in instance_ref['mac_address'] |
695 | + if x.network_id == network_ref['id']] |
696 | + if len(macs) != 0 and macs[0] != mac: |
697 | + inst_addr = macs[0] |
698 | raise exception.Error(_("IP %(address)s released from" |
699 | " bad mac %(inst_addr)s vs %(mac)s") % locals()) |
700 | if not fixed_ip_ref['leased']: |
701 | @@ -489,6 +501,29 @@ |
702 | super(VlanManager, self).init_host() |
703 | self.driver.metadata_forward() |
704 | |
705 | + def allocate_fixed_ips(self, context, instance_id, *args, **kwargs): |
706 | + """Gets a fixed ips from the pool""" |
707 | + ctxt = context.elevated() |
708 | + project_id = context.project_id |
709 | + network_refs = self.db.network_get_all_by_project(ctxt, |
710 | + context.project_id) |
711 | + addresses = [] |
712 | + for network_ref in network_refs: |
713 | + if kwargs.get('vpn', None): |
714 | + address = network_ref['vpn_private_address'] |
715 | + self.db.fixed_ip_associate(ctxt, |
716 | + address, |
717 | + instance_id) |
718 | + else: |
719 | + address = self.db.fixed_ip_associate_pool(ctxt, |
720 | + network_ref['id'], |
721 | + instance_id) |
722 | + self.db.fixed_ip_update(context, address, {'allocated': True}) |
723 | + if not FLAGS.fake_network: |
724 | + self.driver.update_dhcp(context, network_ref['id']) |
725 | + addresses.append(address) |
726 | + return addresses |
727 | + |
728 | def allocate_fixed_ip(self, context, instance_id, *args, **kwargs): |
729 | """Gets a fixed ip from the pool.""" |
730 | # TODO(vish): This should probably be getting project_id from |
731 | @@ -517,9 +552,12 @@ |
732 | |
733 | def setup_compute_network(self, context, instance_id): |
734 | """Sets up matching network for compute hosts.""" |
735 | - network_ref = db.network_get_by_instance(context, instance_id) |
736 | - self.driver.ensure_vlan_bridge(network_ref['vlan'], |
737 | - network_ref['bridge']) |
738 | + #network_ref = db.network_get_by_instance(context, instance_id) |
739 | + network_refs = db.network_get_all_by_instance(context, instance_id) |
740 | + for network_ref in network_refs: |
741 | + self.driver.ensure_vlan_bridge(network_ref['vlan'], |
742 | + network_ref['bridge']) |
743 | + |
744 | |
745 | def create_networks(self, context, cidr, num_networks, network_size, |
746 | cidr_v6, vlan_start, vpn_start, **kwargs): |
747 | |
748 | === modified file 'nova/tests/test_cloud.py' |
749 | --- nova/tests/test_cloud.py 2011-03-11 16:55:28 +0000 |
750 | +++ nova/tests/test_cloud.py 2011-03-17 13:48:33 +0000 |
751 | @@ -367,7 +367,7 @@ |
752 | self.cloud.update_instance(self.context, inst['id'], |
753 | mac_address='DE:AD:BE:EF') |
754 | inst = db.instance_get(self.context, inst['id']) |
755 | - self.assertEqual(None, inst['mac_address']) |
756 | + self.assertEqual([], inst['mac_address']) |
757 | db.instance_destroy(self.context, inst['id']) |
758 | |
759 | def test_update_of_volume_display_fields(self): |
760 | |
761 | === modified file 'nova/tests/test_compute.py' |
762 | --- nova/tests/test_compute.py 2011-03-14 22:17:00 +0000 |
763 | +++ nova/tests/test_compute.py 2011-03-17 13:48:33 +0000 |
764 | @@ -77,7 +77,7 @@ |
765 | inst['user_id'] = self.user.id |
766 | inst['project_id'] = self.project.id |
767 | inst['instance_type'] = 'm1.tiny' |
768 | - inst['mac_address'] = utils.generate_mac() |
769 | + inst['mac_address'] = [utils.generate_mac()] |
770 | inst['ami_launch_index'] = 0 |
771 | inst.update(params) |
772 | return db.instance_create(self.context, inst)['id'] |
773 | |
774 | === modified file 'nova/tests/test_console.py' |
775 | --- nova/tests/test_console.py 2011-03-07 01:25:01 +0000 |
776 | +++ nova/tests/test_console.py 2011-03-17 13:48:33 +0000 |
777 | @@ -63,7 +63,7 @@ |
778 | inst['user_id'] = self.user.id |
779 | inst['project_id'] = self.project.id |
780 | inst['instance_type'] = 'm1.tiny' |
781 | - inst['mac_address'] = utils.generate_mac() |
782 | + inst['mac_address'] = [utils.generate_mac()] |
783 | inst['ami_launch_index'] = 0 |
784 | return db.instance_create(self.context, inst)['id'] |
785 | |
786 | |
787 | === modified file 'nova/tests/test_network.py' |
788 | --- nova/tests/test_network.py 2011-03-14 13:21:44 +0000 |
789 | +++ nova/tests/test_network.py 2011-03-17 13:48:33 +0000 |
790 | @@ -214,7 +214,7 @@ |
791 | self.manager.delete_user(self.user) |
792 | super(NetworkTestCase, self).tearDown() |
793 | |
794 | - def _create_instance(self, project_num, mac=None): |
795 | + def _create_instance(self, project_num, mac=None, network_id=None): |
796 | if not mac: |
797 | mac = utils.generate_mac() |
798 | project = self.projects[project_num] |
799 | @@ -222,7 +222,8 @@ |
800 | self.context.project_id = project.id |
801 | return db.instance_create(self.context, |
802 | {'project_id': project.id, |
803 | - 'mac_address': mac}) |
804 | + 'mac_address': mac, |
805 | + 'networks': network_id}) |
806 | |
807 | def _create_address(self, project_num, instance_id=None): |
808 | """Create an address in given project num""" |
809 | @@ -237,27 +238,67 @@ |
810 | self.context.project_id = self.projects[project_num].id |
811 | self.network.deallocate_fixed_ip(self.context, address) |
812 | |
813 | + def test_multi_nic(self): |
814 | + """Makes sure network_associate works""" |
815 | + project_id = self.context.project_id |
816 | + ctxt = context.get_admin_context() |
817 | + |
818 | + before_all_net_count = len(db.network_get_all(ctxt)) |
819 | + before_proj_net_count = len(db.network_get_all_by_project(ctxt, |
820 | + project_id)) |
821 | + additional_net_count = 1 |
822 | + self.network.create_networks(ctxt, '11.0.0.0/8', additional_net_count, |
823 | + FLAGS.network_size, |
824 | + FLAGS.fixed_range_v6, |
825 | + FLAGS.vlan_start, |
826 | + FLAGS.vpn_start,) |
827 | + |
828 | + after_all_networks = db.network_get_all(ctxt) |
829 | + after_all_networks_count = len(after_all_networks) |
830 | + self.assertEqual(before_all_net_count + additional_net_count, |
831 | + after_all_networks_count) |
832 | + |
833 | + expected_count = 0 |
834 | + |
835 | + for net in after_all_networks: |
836 | + if not net.project_id: |
837 | + expected_count += 1 |
838 | + db.network_associate(ctxt, project_id, net.cidr) |
839 | + self.assertTrue(expected_count > 0) |
840 | + |
841 | + after_proj_net_count = len(db.network_get_all_by_project(ctxt, |
842 | + project_id)) |
843 | + |
844 | + self.assertEquals(after_proj_net_count, |
845 | + before_proj_net_count + expected_count) |
846 | + |
847 | def test_private_ipv6(self): |
848 | """Make sure ipv6 is OK""" |
849 | if FLAGS.use_ipv6: |
850 | - instance_ref = self._create_instance(0) |
851 | - address = self._create_address(0, instance_ref['id']) |
852 | network_ref = db.project_get_network( |
853 | context.get_admin_context(), |
854 | self.context.project_id) |
855 | + instance_ref = self._create_instance(0, |
856 | + network_id=network_ref['id']) |
857 | + address = self._create_address(0, instance_ref['id']) |
858 | address_v6 = db.instance_get_fixed_address_v6( |
859 | context.get_admin_context(), |
860 | - instance_ref['id']) |
861 | - self.assertEqual(instance_ref['mac_address'], |
862 | - utils.to_mac(address_v6)) |
863 | + instance_ref['id'], |
864 | + network_ref['id']) |
865 | instance_ref2 = db.fixed_ip_get_instance_v6( |
866 | context.get_admin_context(), |
867 | address_v6) |
868 | self.assertEqual(instance_ref['id'], instance_ref2['id']) |
869 | + nic = db.\ |
870 | + nic_get_by_network_and_instance(context.get_admin_context(), |
871 | + network_id=network_ref['id'], |
872 | + instance_id=instance_ref['id']) |
873 | + self.assertEqual(nic['mac_address'], |
874 | + utils.to_mac(address_v6)) |
875 | self.assertEqual(address_v6, |
876 | utils.to_global_ipv6( |
877 | - network_ref['cidr_v6'], |
878 | - instance_ref['mac_address'])) |
879 | + network_ref['cidr_v6'], |
880 | + nic['mac_address'])) |
881 | self._deallocate_address(0, address) |
882 | db.instance_destroy(context.get_admin_context(), |
883 | instance_ref['id']) |
884 | @@ -512,8 +553,10 @@ |
885 | instance_ref = db.fixed_ip_get_instance(context.get_admin_context(), |
886 | private_ip) |
887 | cmd = (binpath('nova-dhcpbridge'), 'add', |
888 | - instance_ref['mac_address'], |
889 | - private_ip, 'fake') |
890 | + instance_ref['mac_address'][0]['mac_address'], |
891 | + private_ip, 'fake', |
892 | + '--sql_connection=sqlite://%s/tests.sqlite' |
893 | + % os.path.dirname(binpath(''))) |
894 | env = {'DNSMASQ_INTERFACE': network_ref['bridge'], |
895 | 'TESTING': '1', |
896 | 'FLAGFILE': FLAGS.dhcpbridge_flagfile} |
897 | @@ -529,7 +572,9 @@ |
898 | private_ip) |
899 | cmd = (binpath('nova-dhcpbridge'), 'del', |
900 | instance_ref['mac_address'], |
901 | - private_ip, 'fake') |
902 | + private_ip, 'fake', |
903 | + '--sql_connection=sqlite://%s/tests.sqlite' |
904 | + % os.path.dirname(binpath(''))) |
905 | env = {'DNSMASQ_INTERFACE': network_ref['bridge'], |
906 | 'TESTING': '1', |
907 | 'FLAGFILE': FLAGS.dhcpbridge_flagfile} |
908 | |
909 | === modified file 'nova/tests/test_quota.py' |
910 | --- nova/tests/test_quota.py 2011-03-15 21:56:00 +0000 |
911 | +++ nova/tests/test_quota.py 2011-03-17 13:48:33 +0000 |
912 | @@ -69,7 +69,7 @@ |
913 | inst['project_id'] = self.project.id |
914 | inst['instance_type'] = 'm1.large' |
915 | inst['vcpus'] = cores |
916 | - inst['mac_address'] = utils.generate_mac() |
917 | + inst['mac_address'] = [utils.generate_mac()] |
918 | return db.instance_create(self.context, inst)['id'] |
919 | |
920 | def _create_volume(self, size=10): |
921 | |
922 | === modified file 'nova/tests/test_virt.py' |
923 | --- nova/tests/test_virt.py 2011-03-14 17:59:41 +0000 |
924 | +++ nova/tests/test_virt.py 2011-03-17 13:48:33 +0000 |
925 | @@ -560,14 +560,16 @@ |
926 | ] |
927 | |
928 | def test_static_filters(self): |
929 | + ip = '10.11.12.13' |
930 | + |
931 | + network_ref = db.project_get_network(self.context, |
932 | + 'fake') |
933 | + |
934 | instance_ref = db.instance_create(self.context, |
935 | {'user_id': 'fake', |
936 | 'project_id': 'fake', |
937 | - 'mac_address': '56:12:12:12:12:12'}) |
938 | - ip = '10.11.12.13' |
939 | - |
940 | - network_ref = db.project_get_network(self.context, |
941 | - 'fake') |
942 | + 'mac_address': '56:12:12:12:12:12', |
943 | + 'networks': network_ref['id']}) |
944 | |
945 | fixed_ip = {'address': ip, |
946 | 'network_id': network_ref['id']} |
947 | |
948 | === modified file 'nova/virt/libvirt.xml.template' |
949 | --- nova/virt/libvirt.xml.template 2011-01-21 11:04:02 +0000 |
950 | +++ nova/virt/libvirt.xml.template 2011-03-17 13:48:33 +0000 |
951 | @@ -69,22 +69,24 @@ |
952 | </disk> |
953 | #end if |
954 | #end if |
955 | + |
956 | +#for $nic in $nics |
957 | <interface type='bridge'> |
958 | - <source bridge='${bridge_name}'/> |
959 | - <mac address='${mac_address}'/> |
960 | + <source bridge='$nic.bridge_name'/> |
961 | + <mac address='$nic.mac_address'/> |
962 | <!-- <model type='virtio'/> CANT RUN virtio network right now --> |
963 | - <filterref filter="nova-instance-${name}"> |
964 | - <parameter name="IP" value="${ip_address}" /> |
965 | - <parameter name="DHCPSERVER" value="${dhcp_server}" /> |
966 | + <filterref filter="nova-instance-$nic.name"> |
967 | + <parameter name="IP" value="$nic.ip_address" /> |
968 | + <parameter name="DHCPSERVER" value="$nic.dhcp_server" /> |
969 | #if $getVar('extra_params', False) |
970 | - ${extra_params} |
971 | + $nic.extra_params |
972 | #end if |
973 | #if $getVar('ra_server', False) |
974 | - <parameter name="RASERVER" value="${ra_server}" /> |
975 | + <parameter name="RASERVER" value="$nic.ra_server" /> |
976 | #end if |
977 | </filterref> |
978 | </interface> |
979 | - |
980 | +#end for |
981 | <!-- The order is significant here. File must be defined first --> |
982 | <serial type="file"> |
983 | <source path='${basepath}/console.log'/> |
984 | |
985 | === modified file 'nova/virt/libvirt_conn.py' |
986 | --- nova/virt/libvirt_conn.py 2011-03-16 19:26:41 +0000 |
987 | +++ nova/virt/libvirt_conn.py 2011-03-17 13:48:33 +0000 |
988 | @@ -693,41 +693,59 @@ |
989 | def to_xml(self, instance, rescue=False): |
990 | # TODO(termie): cache? |
991 | LOG.debug(_('instance %s: starting toXML method'), instance['name']) |
992 | - network = db.network_get_by_instance(context.get_admin_context(), |
993 | + networks = db.network_get_all_by_instance(context.get_admin_context(), |
994 | instance['id']) |
995 | - # FIXME(vish): stick this in db |
996 | instance_type = instance['instance_type'] |
997 | - # instance_type = test.INSTANCE_TYPES[instance_type] |
998 | + #instance_type = instance_types.INSTANCE_TYPES[instance_type] |
999 | instance_type = instance_types.get_instance_type(instance_type) |
1000 | - ip_address = db.instance_get_fixed_address(context.get_admin_context(), |
1001 | - instance['id']) |
1002 | - # Assume that the gateway also acts as the dhcp server. |
1003 | - dhcp_server = network['gateway'] |
1004 | - ra_server = network['ra_server'] |
1005 | - |
1006 | - if FLAGS.allow_project_net_traffic: |
1007 | - if FLAGS.use_ipv6: |
1008 | - net, mask = _get_net_and_mask(network['cidr']) |
1009 | - net_v6, prefixlen_v6 = _get_net_and_prefixlen( |
1010 | - network['cidr_v6']) |
1011 | - extra_params = ("<parameter name=\"PROJNET\" " |
1012 | - "value=\"%s\" />\n" |
1013 | - "<parameter name=\"PROJMASK\" " |
1014 | - "value=\"%s\" />\n" |
1015 | - "<parameter name=\"PROJNETV6\" " |
1016 | - "value=\"%s\" />\n" |
1017 | - "<parameter name=\"PROJMASKV6\" " |
1018 | - "value=\"%s\" />\n") % \ |
1019 | - (net, mask, net_v6, prefixlen_v6) |
1020 | + |
1021 | + nics = [] |
1022 | + for network in networks: |
1023 | + # FIXME(vish): stick this in db |
1024 | + ip_address = db.instance_get_fixed_address( |
1025 | + context.get_admin_context(), |
1026 | + instance['id'], network['id']) |
1027 | + mac_address = db.\ |
1028 | + nic_get_by_network_and_instance(context.get_admin_context(), |
1029 | + instance['id'], |
1030 | + network['id']) |
1031 | + # Assume that the gateway also acts as the dhcp server. |
1032 | + dhcp_server = network['gateway'] |
1033 | + ra_server = network['ra_server'] |
1034 | + if ra_server: |
1035 | + ra_server = ra_server + "/128" |
1036 | + |
1037 | + if FLAGS.allow_project_net_traffic: |
1038 | + if FLAGS.use_ipv6: |
1039 | + net, mask = _get_net_and_mask(network['cidr']) |
1040 | + net_v6, prefixlen_v6 = _get_net_and_prefixlen( |
1041 | + network['cidr_v6']) |
1042 | + extra_params = ("<parameter name=\"PROJNET\" " |
1043 | + "value=\"%s\" />\n" |
1044 | + "<parameter name=\"PROJMASK\" " |
1045 | + "value=\"%s\" />\n" |
1046 | + "<parameter name=\"PROJNETV6\" " |
1047 | + "value=\"%s\" />\n" |
1048 | + "<parameter name=\"PROJMASKV6\" " |
1049 | + "value=\"%s\" />\n") % \ |
1050 | + (net, mask, net_v6, prefixlen_v6) |
1051 | + else: |
1052 | + net, mask = _get_net_and_mask(network['cidr']) |
1053 | + extra_params = ("<parameter name=\"PROJNET\" " |
1054 | + "value=\"%s\" />\n" |
1055 | + "<parameter name=\"PROJMASK\" " |
1056 | + "value=\"%s\" />\n") % \ |
1057 | + (net, mask) |
1058 | else: |
1059 | - net, mask = _get_net_and_mask(network['cidr']) |
1060 | - extra_params = ("<parameter name=\"PROJNET\" " |
1061 | - "value=\"%s\" />\n" |
1062 | - "<parameter name=\"PROJMASK\" " |
1063 | - "value=\"%s\" />\n") % \ |
1064 | - (net, mask) |
1065 | - else: |
1066 | - extra_params = "\n" |
1067 | + extra_params = "\n" |
1068 | + nic = dict(ip_address=ip_address, mac_address=mac_address, |
1069 | + dhcp_server=dhcp_server, ra_server=ra_server, |
1070 | + net=net, mask=mask, net_v6=net_v6, |
1071 | + prefixlen_v6=prefixlen_v6, extra_params=extra_params, |
1072 | + bridge_name=network['bridge'], |
1073 | + name=('%s-%s' % (instance['id'], network['id']))) |
1074 | + nics.append(nic) |
1075 | + |
1076 | if FLAGS.use_cow_images: |
1077 | driver_type = 'qcow2' |
1078 | else: |
1079 | @@ -739,17 +757,18 @@ |
1080 | instance['name']), |
1081 | 'memory_kb': instance_type['memory_mb'] * 1024, |
1082 | 'vcpus': instance_type['vcpus'], |
1083 | - 'bridge_name': network['bridge'], |
1084 | - 'mac_address': instance['mac_address'], |
1085 | - 'ip_address': ip_address, |
1086 | - 'dhcp_server': dhcp_server, |
1087 | - 'extra_params': extra_params, |
1088 | + #'bridge_name': network['bridge'], |
1089 | + #'mac_address': instance['mac_address'], |
1090 | + #'ip_address': ip_address, |
1091 | + #'dhcp_server': dhcp_server, |
1092 | + #'extra_params': extra_params, |
1093 | + 'nics': nics, |
1094 | 'rescue': rescue, |
1095 | 'local': instance_type['local_gb'], |
1096 | 'driver_type': driver_type} |
1097 | |
1098 | - if ra_server: |
1099 | - xml_info['ra_server'] = ra_server + "/128" |
1100 | +# if ra_server: |
1101 | +# xml_info['ra_server'] = ra_server + "/128" |
1102 | if not rescue: |
1103 | if instance['kernel_id']: |
1104 | xml_info['kernel'] = xml_info['basepath'] + "/kernel" |
1105 | @@ -762,7 +781,6 @@ |
1106 | xml = str(Template(self.libvirt_xml, searchList=[xml_info])) |
1107 | LOG.debug(_('instance %s: finished toXML method'), |
1108 | instance['name']) |
1109 | - |
1110 | return xml |
1111 | |
1112 | def get_info(self, instance_name): |
1113 | @@ -1626,18 +1644,22 @@ |
1114 | chain_name = self._instance_chain_name(instance) |
1115 | |
1116 | self.iptables.ipv4['filter'].add_chain(chain_name) |
1117 | - ipv4_address = self._ip_for_instance(instance) |
1118 | - self.iptables.ipv4['filter'].add_rule('local', |
1119 | - '-d %s -j $%s' % |
1120 | - (ipv4_address, chain_name)) |
1121 | + networks = db.network_get_all_by_instance(context.get_admin_context(), |
1122 | + instance['id']) |
1123 | + for network in networks: |
1124 | + ipv4_address = self._ip_for_instance(instance, network) |
1125 | + self.iptables.ipv4['filter'].add_rule('local', |
1126 | + '-d %s -j $%s' % |
1127 | + (ipv4_address, chain_name)) |
1128 | |
1129 | if FLAGS.use_ipv6: |
1130 | self.iptables.ipv6['filter'].add_chain(chain_name) |
1131 | - ipv6_address = self._ip_for_instance_v6(instance) |
1132 | - self.iptables.ipv6['filter'].add_rule('local', |
1133 | - '-d %s -j $%s' % |
1134 | - (ipv6_address, |
1135 | - chain_name)) |
1136 | + for network in networks: |
1137 | + ipv6_address = self._ip_for_instance_v6(instance, network) |
1138 | + self.iptables.ipv6['filter'].add_rule('local', |
1139 | + '-d %s -j $%s' % |
1140 | + (ipv6_address, |
1141 | + chain_name)) |
1142 | |
1143 | ipv4_rules, ipv6_rules = self.instance_rules(instance) |
1144 | |
1145 | @@ -1669,28 +1691,31 @@ |
1146 | ipv4_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] |
1147 | ipv6_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] |
1148 | |
1149 | - dhcp_server = self._dhcp_server_for_instance(instance) |
1150 | - ipv4_rules += ['-s %s -p udp --sport 67 --dport 68 ' |
1151 | - '-j ACCEPT' % (dhcp_server,)] |
1152 | + dhcp_servers = self._dhcp_servers_for_instance(instance) |
1153 | + for dhcp_server in dhcp_servers: |
1154 | + ipv4_rules += ['-s %s -p udp --sport 67 --dport 68 ' |
1155 | + '-j ACCEPT' % (dhcp_server,)] |
1156 | |
1157 | #Allow project network traffic |
1158 | if FLAGS.allow_project_net_traffic: |
1159 | - cidr = self._project_cidr_for_instance(instance) |
1160 | - ipv4_rules += ['-s %s -j ACCEPT' % (cidr,)] |
1161 | + cidrs = self._project_cidrs_for_instance(instance) |
1162 | + for cidr in cidrs: |
1163 | + ipv4_rules += ['-s %s -j ACCEPT' % (cidr,)] |
1164 | |
1165 | # We wrap these in FLAGS.use_ipv6 because they might cause |
1166 | # a DB lookup. The other ones are just list operations, so |
1167 | # they're not worth the clutter. |
1168 | if FLAGS.use_ipv6: |
1169 | # Allow RA responses |
1170 | - ra_server = self._ra_server_for_instance(instance) |
1171 | - if ra_server: |
1172 | + ra_servers = self._ra_servers_for_instance(instance) |
1173 | + for ra_server in ra_servers: |
1174 | ipv6_rules += ['-s %s/128 -p icmpv6 -j ACCEPT' % (ra_server,)] |
1175 | |
1176 | #Allow project network traffic |
1177 | if FLAGS.allow_project_net_traffic: |
1178 | - cidrv6 = self._project_cidrv6_for_instance(instance) |
1179 | - ipv6_rules += ['-s %s -j ACCEPT' % (cidrv6,)] |
1180 | + cidrs_v6 = self._project_cidrs_v6_for_instance(instance) |
1181 | + for cidr_v6 in cidrs_v6: |
1182 | + ipv6_rules += ['-s %s -j ACCEPT' % (cidr_v6,)] |
1183 | |
1184 | security_groups = db.security_group_get_by_instance(ctxt, |
1185 | instance['id']) |
1186 | @@ -1773,30 +1798,27 @@ |
1187 | def _instance_chain_name(self, instance): |
1188 | return 'inst-%s' % (instance['id'],) |
1189 | |
1190 | - def _ip_for_instance(self, instance): |
1191 | + def _ip_for_instance(self, instance, network): |
1192 | return db.instance_get_fixed_address(context.get_admin_context(), |
1193 | - instance['id']) |
1194 | + instance['id'], network['id']) |
1195 | |
1196 | - def _ip_for_instance_v6(self, instance): |
1197 | + def _ip_for_instance_v6(self, instance, network): |
1198 | return db.instance_get_fixed_address_v6(context.get_admin_context(), |
1199 | - instance['id']) |
1200 | - |
1201 | - def _dhcp_server_for_instance(self, instance): |
1202 | - network = db.network_get_by_instance(context.get_admin_context(), |
1203 | - instance['id']) |
1204 | - return network['gateway'] |
1205 | - |
1206 | - def _ra_server_for_instance(self, instance): |
1207 | - network = db.network_get_by_instance(context.get_admin_context(), |
1208 | - instance['id']) |
1209 | - return network['ra_server'] |
1210 | - |
1211 | - def _project_cidr_for_instance(self, instance): |
1212 | - network = db.network_get_by_instance(context.get_admin_context(), |
1213 | - instance['id']) |
1214 | - return network['cidr'] |
1215 | - |
1216 | - def _project_cidrv6_for_instance(self, instance): |
1217 | - network = db.network_get_by_instance(context.get_admin_context(), |
1218 | - instance['id']) |
1219 | - return network['cidr_v6'] |
1220 | + instance['id'], network['id']) |
1221 | + |
1222 | + def _network_field_for_instance(self, instance, field): |
1223 | + networks = db.network_get_all_by_instance(context.get_admin_context(), |
1224 | + instance['id']) |
1225 | + return [network[field] for network in networks] |
1226 | + |
1227 | + def _dhcp_servers_for_instance(self, instance): |
1228 | + return self._network_field_for_instance(instance, 'gateway') |
1229 | + |
1230 | + def _ra_servers_for_instance(self, instance): |
1231 | + return self._network_field_for_instance(instance, 'ra_server') |
1232 | + |
1233 | + def _project_cidrs_for_instance(self, instance): |
1234 | + return self._network_field_for_instance(instance, 'cidr') |
1235 | + |
1236 | + def _project_cidrs_v6_for_instance(self, instance): |
1237 | + return self._network_field_for_instance(instance, 'cidr_v6') |
1238 | \ No newline at end of file |