Merge lp:~ilyaalekseyev/nova/libvirt-multinic-experemental into lp:~openstack-gd/nova/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
Reviewer Review Type Date Requested Status
Ilya Alekseyev (community) Abstain
Review via email: mp+53819@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Ilya Alekseyev (ilyaalekseyev) :
review: Abstain

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

Subscribers

People subscribed via source and target branches