Merge lp:~vishvananda/nova/remove-network-index into lp:~hudson-openstack/nova/trunk

Proposed by Vish Ishaya
Status: Merged
Approved by: Rick Clark
Approved revision: 304
Merged at revision: 346
Proposed branch: lp:~vishvananda/nova/remove-network-index
Merge into: lp:~hudson-openstack/nova/trunk
Prerequisite: lp:~vishvananda/nova/network-lease-fix
Diff against target: 1162 lines (+297/-254)
17 files modified
bin/nova-manage (+28/-3)
nova/api/ec2/cloud.py (+6/-5)
nova/api/openstack/servers.py (+16/-19)
nova/auth/manager.py (+0/-15)
nova/compute/manager.py (+1/-1)
nova/db/api.py (+25/-20)
nova/db/sqlalchemy/api.py (+58/-65)
nova/db/sqlalchemy/models.py (+10/-23)
nova/network/linux_net.py (+3/-3)
nova/network/manager.py (+94/-77)
nova/test.py (+16/-2)
nova/tests/cloud_unittest.py (+2/-2)
nova/tests/compute_unittest.py (+2/-1)
nova/tests/network_unittest.py (+21/-11)
nova/tests/scheduler_unittest.py (+1/-0)
nova/tests/virt_unittest.py (+11/-5)
nova/virt/libvirt_conn.py (+3/-2)
To merge this branch: bzr merge lp:~vishvananda/nova/remove-network-index
Reviewer Review Type Date Requested Status
Rick Clark (community) Approve
Jay Pipes (community) Needs Fixing
Review via email: mp+36921@code.launchpad.net

Description of the change

This patch removes the ugly network_index that is used by VlanManager and turns network itself into a pool. It adds support for creating the networks through an api command:
    nova-manage network create # creates all of the networks defined by flags
or
    nova-manage network create 5 # create the first five networks

This moves the network out of project.create, associating a network to a project lazily in project_get_network. This allows for a bit greater control over networks. There are a couple outstanding issues:
   1) Where do networks get disassociated? Right now I'm not disassociating at all. We're sharing ldap users across different deploys, whereas sql db is unique per deploy. Perhaps the solution is to have a flag like disassociate_on_project_destroy and make it optional?
   2) How do we handle creation of networks for tests? It is really slow to create a pool of networks and fixed_ips for each test case. Right now I'm taking advantage of the fact that the db isn't cleaned between tests, and creating them if they don't exist in BaseTestCase.SetUp() and disassociating in TearDown(). Ideally this should be replaced with fixtures of some sort.

Comments on these two issues are welcome.

To post a comment you must log in.
Revision history for this message
Jay Pipes (jaypipes) wrote :

"1) Where do networks get disassociated? Right now I'm not disassociating at all. We're sharing ldap users across different deploys, whereas sql db is unique per deploy. Perhaps the solution is to have a flag like disassociate_on_project_destroy and make it optional?"

I think that is an excellent option. ++ on a flag to determine when disassociation occurs.

"2) How do we handle creation of networks for tests? It is really slow to create a pool of networks and fixed_ips for each test case. Right now I'm taking advantage of the fact that the db isn't cleaned between tests, and creating them if they don't exist in BaseTestCase.SetUp() and disassociating in TearDown(). Ideally this should be replaced with fixtures of some sort."

Well, there's a ton to talk about with the current testing systems at the next summit :) I say "systems" because the new rackspace stuff is using nosetests, and the rest is using the nova.test.BaseTestCase or unittest.TestCase.

I'd love to do a discuss the future of how we test OS projects at the summit...including stuff like how we establish fixtures and configuration-dependent environments.

-jay

Revision history for this message
Jay Pipes (jaypipes) wrote :

lgtm.

review: Approve
297. By Vish Ishaya

merged trunk

298. By Vish Ishaya

Fixed flat network manager with network index gone.

Both managers use ips created through nova manage.

Use of project_get_network is minimized to make way for managers that
would prefer to use cluste or host based ips instead of project based ips.

299. By Vish Ishaya

fix typo in setup_compute_network

Revision history for this message
Jay Pipes (jaypipes) wrote :

ping. vishy, looks like you need to merge with trunk and resolve conflicts from devin's auth work...

review: Needs Fixing
300. By Vish Ishaya

merged trunk and fixed tests

301. By Vish Ishaya

merged trunk

302. By Vish Ishaya

fix tests

303. By Vish Ishaya

super teardown

304. By Vish Ishaya

cleanup leftover addresses

Revision history for this message
Rick Clark (dendrobates) wrote :

lgtm

review: Approve

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 2010-10-12 14:23:24 +0000
3+++ bin/nova-manage 2010-10-13 07:50:58 +0000
4@@ -73,6 +73,7 @@
5 from nova import quota
6 from nova import utils
7 from nova.auth import manager
8+from nova.network import manager as network_manager
9 from nova.cloudpipe import pipelib
10
11
12@@ -377,6 +378,29 @@
13 floating_ip['address'],
14 instance)
15
16+class NetworkCommands(object):
17+ """Class for managing networks."""
18+
19+ def create(self, fixed_range=None, num_networks=None,
20+ network_size=None, vlan_start=None, vpn_start=None):
21+ """Creates fixed ips for host by range
22+ arguments: [fixed_range=FLAG], [num_networks=FLAG],
23+ [network_size=FLAG], [vlan_start=FLAG],
24+ [vpn_start=FLAG]"""
25+ if not fixed_range:
26+ fixed_range = FLAGS.fixed_range
27+ if not num_networks:
28+ num_networks = FLAGS.num_networks
29+ if not network_size:
30+ network_size = FLAGS.network_size
31+ if not vlan_start:
32+ vlan_start = FLAGS.vlan_start
33+ if not vpn_start:
34+ vpn_start = FLAGS.vpn_start
35+ net_manager = utils.import_object(FLAGS.network_manager)
36+ net_manager.create_networks(None, fixed_range, int(num_networks),
37+ int(network_size), int(vlan_start),
38+ int(vpn_start))
39
40 CATEGORIES = [
41 ('user', UserCommands),
42@@ -384,7 +408,8 @@
43 ('role', RoleCommands),
44 ('shell', ShellCommands),
45 ('vpn', VpnCommands),
46- ('floating', FloatingIpCommands)
47+ ('floating', FloatingIpCommands),
48+ ('network', NetworkCommands)
49 ]
50
51
52@@ -454,9 +479,9 @@
53 fn(*argv)
54 sys.exit(0)
55 except TypeError:
56- print "Wrong number of arguments supplied"
57+ print "Possible wrong number of arguments supplied"
58 print "%s %s: %s" % (category, action, fn.__doc__)
59- sys.exit(2)
60+ raise
61
62 if __name__ == '__main__':
63 main()
64
65=== modified file 'nova/api/ec2/cloud.py'
66--- nova/api/ec2/cloud.py 2010-10-12 07:24:33 +0000
67+++ nova/api/ec2/cloud.py 2010-10-13 07:50:58 +0000
68@@ -734,13 +734,13 @@
69
70 def _get_network_topic(self, context):
71 """Retrieves the network host for a project"""
72- network_ref = db.project_get_network(context, context.project.id)
73+ network_ref = self.network_manager.get_network(context)
74 host = network_ref['host']
75 if not host:
76 host = rpc.call(FLAGS.network_topic,
77 {"method": "set_network_host",
78 "args": {"context": None,
79- "project_id": context.project.id}})
80+ "network_id": network_ref['id']}})
81 return db.queue_get_for(context, FLAGS.network_topic, host)
82
83 def _ensure_default_security_group(self, context):
84@@ -851,12 +851,13 @@
85 ec2_id = internal_id_to_ec2_id(internal_id)
86 inst['hostname'] = ec2_id
87 db.instance_update(context, inst_id, inst)
88+ # TODO(vish): This probably should be done in the scheduler
89+ # or in compute as a call. The network should be
90+ # allocated after the host is assigned and setup
91+ # can happen at the same time.
92 address = self.network_manager.allocate_fixed_ip(context,
93 inst_id,
94 vpn)
95-
96- # TODO(vish): This probably should be done in the scheduler
97- # network is setup when host is assigned
98 network_topic = self._get_network_topic(context)
99 rpc.call(network_topic,
100 {"method": "setup_fixed_ip",
101
102=== modified file 'nova/api/openstack/servers.py'
103--- nova/api/openstack/servers.py 2010-10-08 21:08:48 +0000
104+++ nova/api/openstack/servers.py 2010-10-13 07:50:58 +0000
105@@ -48,9 +48,9 @@
106 return dict(servers=entities)
107
108 def _entity_detail(inst):
109- """ Maps everything to valid attributes for return"""
110- power_mapping = {
111- power_state.NOSTATE: 'build',
112+ """ Maps everything to Rackspace-like attributes for return"""
113+ power_mapping = {
114+ power_state.NOSTATE: 'build',
115 power_state.RUNNING: 'active',
116 power_state.BLOCKED: 'active',
117 power_state.PAUSED: 'suspended',
118@@ -60,7 +60,7 @@
119 }
120 inst_dict = {}
121
122- mapped_keys = dict(status='state', imageId='image_id',
123+ mapped_keys = dict(status='state', imageId='image_id',
124 flavorId='instance_type', name='server_name', id='id')
125
126 for k, v in mapped_keys.iteritems():
127@@ -83,7 +83,7 @@
128 _serialization_metadata = {
129 'application/xml': {
130 "attributes": {
131- "server": [ "id", "imageId", "name", "flavorId", "hostId",
132+ "server": [ "id", "imageId", "name", "flavorId", "hostId",
133 "status", "progress", "progress" ]
134 }
135 }
136@@ -155,7 +155,7 @@
137 user_id = req.environ['nova.context']['user']['id']
138
139 inst_dict = self._deserialize(req.body, req)
140-
141+
142 if not inst_dict:
143 return faults.Fault(exc.HTTPUnprocessableEntity())
144
145@@ -163,12 +163,12 @@
146 if not instance or instance.user_id != user_id:
147 return faults.Fault(exc.HTTPNotFound())
148
149- self.db_driver.instance_update(None, int(id),
150+ self.db_driver.instance_update(None, int(id),
151 _filter_params(inst_dict['server']))
152 return faults.Fault(exc.HTTPNoContent())
153
154 def action(self, req, id):
155- """ multi-purpose method used to reboot, rebuild, and
156+ """ multi-purpose method used to reboot, rebuild, and
157 resize a server """
158 user_id = req.environ['nova.context']['user']['id']
159 input_dict = self._deserialize(req.body, req)
160@@ -195,12 +195,11 @@
161 if v['flavorid'] == flavor_id][0]
162
163 image_id = env['server']['imageId']
164-
165 img_service = utils.import_object(FLAGS.image_service)
166
167 image = img_service.show(image_id)
168
169- if not image:
170+ if not image:
171 raise Exception, "Image not found"
172
173 inst['server_name'] = env['server']['name']
174@@ -236,15 +235,14 @@
175
176 ref = self.db_driver.instance_create(None, inst)
177 inst['id'] = ref.internal_id
178-
179 # TODO(dietz): this isn't explicitly necessary, but the networking
180 # calls depend on an object with a project_id property, and therefore
181 # should be cleaned up later
182 api_context = context.APIRequestContext(user_id)
183-
184+
185 inst['mac_address'] = utils.generate_mac()
186-
187- #TODO(dietz) is this necessary?
188+
189+ #TODO(dietz) is this necessary?
190 inst['launch_index'] = 0
191
192 inst['hostname'] = str(ref.internal_id)
193@@ -256,21 +254,20 @@
194
195 # TODO(vish): This probably should be done in the scheduler
196 # network is setup when host is assigned
197- network_topic = self._get_network_topic(user_id)
198+ network_topic = self._get_network_topic(None)
199 rpc.call(network_topic,
200 {"method": "setup_fixed_ip",
201 "args": {"context": None,
202 "address": address}})
203 return inst
204
205- def _get_network_topic(self, user_id):
206+ def _get_network_topic(self, context):
207 """Retrieves the network host for a project"""
208- network_ref = self.db_driver.project_get_network(None,
209- user_id)
210+ network_ref = self.network_manager.get_network(context)
211 host = network_ref['host']
212 if not host:
213 host = rpc.call(FLAGS.network_topic,
214 {"method": "set_network_host",
215 "args": {"context": None,
216- "project_id": user_id}})
217+ "network_id": network_ref['id']}})
218 return self.db_driver.queue_get_for(None, FLAGS.network_topic, host)
219
220=== modified file 'nova/auth/manager.py'
221--- nova/auth/manager.py 2010-10-12 20:04:46 +0000
222+++ nova/auth/manager.py 2010-10-13 07:50:58 +0000
223@@ -484,13 +484,6 @@
224 member_users)
225 if project_dict:
226 project = Project(**project_dict)
227- try:
228- self.network_manager.allocate_network(context,
229- project.id)
230- except:
231- drv.delete_project(project.id)
232- raise
233-
234 return project
235
236 def modify_project(self, project, manager_user=None, description=None):
237@@ -559,14 +552,6 @@
238
239 def delete_project(self, project, context=None):
240 """Deletes a project"""
241- try:
242- network_ref = db.project_get_network(context,
243- Project.safe_id(project))
244- db.network_destroy(context, network_ref['id'])
245- except:
246- logging.exception('Could not destroy network for %s',
247- project)
248-
249 with self.driver() as drv:
250 drv.delete_project(Project.safe_id(project))
251
252
253=== modified file 'nova/compute/manager.py'
254--- nova/compute/manager.py 2010-10-12 20:18:29 +0000
255+++ nova/compute/manager.py 2010-10-13 07:50:58 +0000
256@@ -76,7 +76,7 @@
257 raise exception.Error("Instance has already been created")
258 logging.debug("instance %s: starting...", instance_id)
259 project_id = instance_ref['project_id']
260- self.network_manager.setup_compute_network(context, project_id)
261+ self.network_manager.setup_compute_network(context, instance_id)
262 self.db.instance_update(context,
263 instance_id,
264 {'host': self.host})
265
266=== modified file 'nova/db/api.py'
267--- nova/db/api.py 2010-10-12 20:04:46 +0000
268+++ nova/db/api.py 2010-10-13 07:50:58 +0000
269@@ -340,6 +340,11 @@
270 ####################
271
272
273+def network_associate(context, project_id):
274+ """Associate a free network to a project."""
275+ return IMPL.network_associate(context, project_id)
276+
277+
278 def network_count(context):
279 """Return the number of networks."""
280 return IMPL.network_count(context)
281@@ -360,9 +365,12 @@
282 return IMPL.network_count_reserved_ips(context, network_id)
283
284
285-def network_create(context, values):
286- """Create a network from the values dictionary."""
287- return IMPL.network_create(context, values)
288+def network_create_safe(context, values):
289+ """Create a network from the values dict
290+
291+ The network is only returned if the create succeeds. If the create violates
292+ constraints because the network already exists, no exception is raised."""
293+ return IMPL.network_create_safe(context, values)
294
295
296 def network_create_fixed_ips(context, network_id, num_vpn_clients):
297@@ -370,9 +378,14 @@
298 return IMPL.network_create_fixed_ips(context, network_id, num_vpn_clients)
299
300
301-def network_destroy(context, network_id):
302- """Destroy the network or raise if it does not exist."""
303- return IMPL.network_destroy(context, network_id)
304+def network_disassociate(context, network_id):
305+ """Disassociate the network from project or raise if it does not exist."""
306+ return IMPL.network_disassociate(context, network_id)
307+
308+
309+def network_disassociate_all(context):
310+ """Disassociate all networks from projects."""
311+ return IMPL.network_disassociate_all(context)
312
313
314 def network_get(context, network_id):
315@@ -387,10 +400,15 @@
316
317
318 def network_get_by_bridge(context, bridge):
319- """Get an network or raise if it does not exist."""
320+ """Get a network by bridge or raise if it does not exist."""
321 return IMPL.network_get_by_bridge(context, bridge)
322
323
324+def network_get_by_instance(context, instance_id):
325+ """Get a network by instance id or raise if it does not exist."""
326+ return IMPL.network_get_by_instance(context, instance_id)
327+
328+
329 def network_get_index(context, network_id):
330 """Get non-conflicting index for network"""
331 return IMPL.network_get_index(context, network_id)
332@@ -401,19 +419,6 @@
333 return IMPL.network_get_vpn_ip(context, network_id)
334
335
336-def network_index_count(context):
337- """Return count of network indexes"""
338- return IMPL.network_index_count(context)
339-
340-
341-def network_index_create_safe(context, values):
342- """Create a network index from the values dict
343-
344- The index is not returned. If the create violates the unique
345- constraints because the index already exists, no exception is raised."""
346- return IMPL.network_index_create_safe(context, values)
347-
348-
349 def network_set_cidr(context, network_id, cidr):
350 """Set the Classless Inner Domain Routing for the network"""
351 return IMPL.network_set_cidr(context, network_id, cidr)
352
353=== modified file 'nova/db/sqlalchemy/api.py'
354--- nova/db/sqlalchemy/api.py 2010-10-12 05:21:25 +0000
355+++ nova/db/sqlalchemy/api.py 2010-10-13 07:50:58 +0000
356@@ -805,6 +805,24 @@
357
358
359 @require_admin_context
360+def network_associate(context, project_id):
361+ session = get_session()
362+ with session.begin():
363+ network_ref = session.query(models.Network
364+ ).filter_by(deleted=False
365+ ).filter_by(project_id=None
366+ ).with_lockmode('update'
367+ ).first()
368+ # NOTE(vish): if with_lockmode isn't supported, as in sqlite,
369+ # then this has concurrency issues
370+ if not network_ref:
371+ raise db.NoMoreNetworks()
372+ network_ref['project_id'] = project_id
373+ session.add(network_ref)
374+ return network_ref
375+
376+
377+@require_admin_context
378 def network_count(context):
379 session = get_session()
380 return session.query(models.Network
381@@ -844,31 +862,26 @@
382
383
384 @require_admin_context
385-def network_create(context, values):
386+def network_create_safe(context, values):
387 network_ref = models.Network()
388 for (key, value) in values.iteritems():
389 network_ref[key] = value
390- network_ref.save()
391- return network_ref
392-
393-
394-@require_admin_context
395-def network_destroy(context, network_id):
396+ try:
397+ network_ref.save()
398+ return network_ref
399+ except IntegrityError:
400+ return None
401+
402+
403+@require_admin_context
404+def network_disassociate(context, network_id):
405+ network_update(context, network_id, {'project_id': None})
406+
407+
408+@require_admin_context
409+def network_disassociate_all(context):
410 session = get_session()
411- with session.begin():
412- # TODO(vish): do we have to use sql here?
413- session.execute('update networks set deleted=1 where id=:id',
414- {'id': network_id})
415- session.execute('update fixed_ips set deleted=1 where network_id=:id',
416- {'id': network_id})
417- session.execute('update floating_ips set deleted=1 '
418- 'where fixed_ip_id in '
419- '(select id from fixed_ips '
420- 'where network_id=:id)',
421- {'id': network_id})
422- session.execute('update network_indexes set network_id=NULL '
423- 'where network_id=:id',
424- {'id': network_id})
425+ session.execute('update networks set project_id=NULL')
426
427
428 @require_context
429@@ -918,48 +931,21 @@
430
431 if not result:
432 raise exception.NotFound('No network for bridge %s' % bridge)
433-
434 return result
435
436
437 @require_admin_context
438-def network_get_index(context, network_id):
439- session = get_session()
440- with session.begin():
441- network_index = session.query(models.NetworkIndex
442- ).filter_by(network_id=None
443- ).filter_by(deleted=False
444- ).with_lockmode('update'
445- ).first()
446-
447- if not network_index:
448- raise db.NoMoreNetworks()
449-
450- network_index['network'] = network_get(context,
451- network_id,
452- session=session)
453- session.add(network_index)
454-
455- return network_index['index']
456-
457-
458-@require_admin_context
459-def network_index_count(context):
460- session = get_session()
461- return session.query(models.NetworkIndex
462- ).filter_by(deleted=can_read_deleted(context)
463- ).count()
464-
465-
466-@require_admin_context
467-def network_index_create_safe(context, values):
468- network_index_ref = models.NetworkIndex()
469- for (key, value) in values.iteritems():
470- network_index_ref[key] = value
471- try:
472- network_index_ref.save()
473- except IntegrityError:
474- pass
475+def network_get_by_instance(_context, instance_id):
476+ session = get_session()
477+ rv = session.query(models.Network
478+ ).filter_by(deleted=False
479+ ).join(models.Network.fixed_ips
480+ ).filter_by(instance_id=instance_id
481+ ).filter_by(deleted=False
482+ ).first()
483+ if not rv:
484+ raise exception.NotFound('No network for instance %s' % instance_id)
485+ return rv
486
487
488 @require_admin_context
489@@ -999,15 +985,22 @@
490 @require_context
491 def project_get_network(context, project_id):
492 session = get_session()
493- result= session.query(models.Network
494+ rv = session.query(models.Network
495 ).filter_by(project_id=project_id
496 ).filter_by(deleted=False
497 ).first()
498-
499- if not result:
500- raise exception.NotFound('No network for project: %s' % project_id)
501-
502- return result
503+ if not rv:
504+ try:
505+ return network_associate(context, project_id)
506+ except IntegrityError:
507+ # NOTE(vish): We hit this if there is a race and two
508+ # processes are attempting to allocate the
509+ # network at the same time
510+ rv = session.query(models.Network
511+ ).filter_by(project_id=project_id
512+ ).filter_by(deleted=False
513+ ).first()
514+ return rv
515
516
517 ###################
518
519=== modified file 'nova/db/sqlalchemy/models.py'
520--- nova/db/sqlalchemy/models.py 2010-10-12 22:43:37 +0000
521+++ nova/db/sqlalchemy/models.py 2010-10-13 07:50:58 +0000
522@@ -25,7 +25,7 @@
523
524 # TODO(vish): clean up these imports
525 from sqlalchemy.orm import relationship, backref, exc, object_mapper
526-from sqlalchemy import Column, Integer, String
527+from sqlalchemy import Column, Integer, String, schema
528 from sqlalchemy import ForeignKey, DateTime, Boolean, Text
529 from sqlalchemy.exc import IntegrityError
530 from sqlalchemy.ext.declarative import declarative_base
531@@ -363,10 +363,13 @@
532 class Network(BASE, NovaBase):
533 """Represents a network"""
534 __tablename__ = 'networks'
535+ __table_args__ = (schema.UniqueConstraint("vpn_public_address",
536+ "vpn_public_port"),
537+ {'mysql_engine': 'InnoDB'})
538 id = Column(Integer, primary_key=True)
539
540 injected = Column(Boolean, default=False)
541- cidr = Column(String(255))
542+ cidr = Column(String(255), unique=True)
543 netmask = Column(String(255))
544 bridge = Column(String(255))
545 gateway = Column(String(255))
546@@ -379,28 +382,13 @@
547 vpn_private_address = Column(String(255))
548 dhcp_start = Column(String(255))
549
550- project_id = Column(String(255))
551+ # NOTE(vish): The unique constraint below helps avoid a race condition
552+ # when associating a network, but it also means that we
553+ # can't associate two networks with one project.
554+ project_id = Column(String(255), unique=True)
555 host = Column(String(255)) # , ForeignKey('hosts.id'))
556
557
558-class NetworkIndex(BASE, NovaBase):
559- """Represents a unique offset for a network
560-
561- Currently vlan number, vpn port, and fixed ip ranges are keyed off of
562- this index. These may ultimately need to be converted to separate
563- pools.
564- """
565- __tablename__ = 'network_indexes'
566- id = Column(Integer, primary_key=True)
567- index = Column(Integer, unique=True)
568- network_id = Column(Integer, ForeignKey('networks.id'), nullable=True)
569- network = relationship(Network,
570- backref=backref('network_index', uselist=False),
571- foreign_keys=network_id,
572- primaryjoin='and_(NetworkIndex.network_id==Network.id,'
573- 'NetworkIndex.deleted==False)')
574-
575-
576 class AuthToken(BASE, NovaBase):
577 """Represents an authorization token for all API transactions. Fields
578 are a string representing the actual token and a user id for mapping
579@@ -413,7 +401,6 @@
580 cdn_management_url = Column(String(255))
581
582
583-
584 # TODO(vish): can these both come from the same baseclass?
585 class FixedIp(BASE, NovaBase):
586 """Represents a fixed ip for an instance"""
587@@ -517,7 +504,7 @@
588 """Register Models and create metadata"""
589 from sqlalchemy import create_engine
590 models = (Service, Instance, Volume, ExportDevice, FixedIp,
591- FloatingIp, Network, NetworkIndex, SecurityGroup,
592+ FloatingIp, Network, SecurityGroup,
593 SecurityGroupIngressRule, SecurityGroupInstanceAssociation,
594 AuthToken, User, Project) # , Image, Host
595 engine = create_engine(FLAGS.sql_connection, echo=False)
596
597=== modified file 'nova/network/linux_net.py'
598--- nova/network/linux_net.py 2010-10-02 10:39:47 +0000
599+++ nova/network/linux_net.py 2010-10-13 07:50:58 +0000
600@@ -65,12 +65,12 @@
601 # SNAT rule for outbound traffic.
602 _confirm_rule("POSTROUTING", "-t nat -s %s "
603 "-j SNAT --to-source %s"
604- % (FLAGS.private_range, FLAGS.routing_source_ip))
605+ % (FLAGS.fixed_range, FLAGS.routing_source_ip))
606
607 _confirm_rule("POSTROUTING", "-t nat -s %s -j MASQUERADE" %
608- FLAGS.private_range)
609+ FLAGS.fixed_range)
610 _confirm_rule("POSTROUTING", "-t nat -s %(range)s -d %(range)s -j ACCEPT" %
611- {'range': FLAGS.private_range})
612+ {'range': FLAGS.fixed_range})
613
614 def bind_floating_ip(floating_ip):
615 """Bind ip to public interface"""
616
617=== modified file 'nova/network/manager.py'
618--- nova/network/manager.py 2010-10-04 10:53:55 +0000
619+++ nova/network/manager.py 2010-10-13 07:50:58 +0000
620@@ -37,17 +37,6 @@
621 FLAGS = flags.FLAGS
622 flags.DEFINE_string('flat_network_bridge', 'br100',
623 'Bridge for simple network instances')
624-flags.DEFINE_list('flat_network_ips',
625- ['192.168.0.2', '192.168.0.3', '192.168.0.4'],
626- 'Available ips for simple network')
627-flags.DEFINE_string('flat_network_network', '192.168.0.0',
628- 'Network for simple network')
629-flags.DEFINE_string('flat_network_netmask', '255.255.255.0',
630- 'Netmask for simple network')
631-flags.DEFINE_string('flat_network_gateway', '192.168.0.1',
632- 'Broadcast for simple network')
633-flags.DEFINE_string('flat_network_broadcast', '192.168.0.255',
634- 'Broadcast for simple network')
635 flags.DEFINE_string('flat_network_dns', '8.8.4.4',
636 'Dns for simple network')
637 flags.DEFINE_integer('vlan_start', 100, 'First VLAN for private networks')
638@@ -57,8 +46,8 @@
639 flags.DEFINE_integer('vpn_start', 1000, 'First Vpn port for private networks')
640 flags.DEFINE_integer('network_size', 256,
641 'Number of addresses in each private subnet')
642-flags.DEFINE_string('public_range', '4.4.4.0/24', 'Public IP address block')
643-flags.DEFINE_string('private_range', '10.0.0.0/8', 'Private IP address block')
644+flags.DEFINE_string('floating_range', '4.4.4.0/24', 'Floating IP address block')
645+flags.DEFINE_string('fixed_range', '10.0.0.0/8', 'Fixed IP address block')
646 flags.DEFINE_integer('cnt_vpn_clients', 5,
647 'Number of addresses reserved for vpn clients')
648 flags.DEFINE_string('network_driver', 'nova.network.linux_net',
649@@ -91,13 +80,9 @@
650 for network in self.db.host_get_networks(None, self.host):
651 self._on_set_network_host(None, network['id'])
652
653- def set_network_host(self, context, project_id):
654- """Safely sets the host of the projects network"""
655+ def set_network_host(self, context, network_id):
656+ """Safely sets the host of the network"""
657 logging.debug("setting network host")
658- network_ref = self.db.project_get_network(context, project_id)
659- # TODO(vish): can we minimize db access by just getting the
660- # id here instead of the ref?
661- network_id = network_ref['id']
662 host = self.db.network_set_host(None,
663 network_id,
664 self.host)
665@@ -117,10 +102,10 @@
666 raise NotImplementedError()
667
668 def _on_set_network_host(self, context, network_id):
669- """Called when this host becomes the host for a project"""
670+ """Called when this host becomes the host for a network"""
671 raise NotImplementedError()
672
673- def setup_compute_network(self, context, project_id):
674+ def setup_compute_network(self, context, instance_id):
675 """Sets up matching network for compute hosts"""
676 raise NotImplementedError()
677
678@@ -150,6 +135,16 @@
679 """Returns an floating ip to the pool"""
680 self.db.floating_ip_deallocate(context, floating_address)
681
682+ def get_network(self, context):
683+ """Get the network for the current context"""
684+ raise NotImplementedError()
685+
686+ def create_networks(self, context, num_networks, network_size,
687+ *args, **kwargs):
688+ """Create networks based on parameters"""
689+ raise NotImplementedError()
690+
691+
692 @property
693 def _bottom_reserved_ips(self): # pylint: disable-msg=R0201
694 """Number of reserved ips at the bottom of the range"""
695@@ -163,7 +158,7 @@
696 def _create_fixed_ips(self, context, network_id):
697 """Create all fixed ips for network"""
698 network_ref = self.db.network_get(context, network_id)
699- # NOTE(vish): should these be properties of the network as opposed
700+ # NOTE(vish): Should these be properties of the network as opposed
701 # to properties of the manager class?
702 bottom_reserved = self._bottom_reserved_ips
703 top_reserved = self._top_reserved_ips
704@@ -185,8 +180,13 @@
705
706 def allocate_fixed_ip(self, context, instance_id, *args, **kwargs):
707 """Gets a fixed ip from the pool"""
708- network_ref = self.db.project_get_network(context, context.project.id)
709- address = self.db.fixed_ip_associate_pool(context,
710+ # TODO(vish): when this is called by compute, we can associate compute
711+ # with a network, or a cluster of computes with a network
712+ # and use that network here with a method like
713+ # network_get_by_compute_host
714+ network_ref = self.db.network_get_by_bridge(None,
715+ FLAGS.flat_network_bridge)
716+ address = self.db.fixed_ip_associate_pool(None,
717 network_ref['id'],
718 instance_id)
719 self.db.fixed_ip_update(context, address, {'allocated': True})
720@@ -195,9 +195,9 @@
721 def deallocate_fixed_ip(self, context, address, *args, **kwargs):
722 """Returns a fixed ip to the pool"""
723 self.db.fixed_ip_update(context, address, {'allocated': False})
724- self.db.fixed_ip_disassociate(context, address)
725+ self.db.fixed_ip_disassociate(None, address)
726
727- def setup_compute_network(self, context, project_id):
728+ def setup_compute_network(self, context, instance_id):
729 """Network is created manually"""
730 pass
731
732@@ -205,24 +205,42 @@
733 """Currently no setup"""
734 pass
735
736+ def create_networks(self, context, cidr, num_networks, network_size,
737+ *args, **kwargs):
738+ """Create networks based on parameters"""
739+ fixed_net = IPy.IP(cidr)
740+ for index in range(num_networks):
741+ start = index * network_size
742+ significant_bits = 32 - int(math.log(network_size, 2))
743+ cidr = "%s/%s" % (fixed_net[start], significant_bits)
744+ project_net = IPy.IP(cidr)
745+ net = {}
746+ net['cidr'] = cidr
747+ net['netmask'] = str(project_net.netmask())
748+ net['gateway'] = str(project_net[1])
749+ net['broadcast'] = str(project_net.broadcast())
750+ net['dhcp_start'] = str(project_net[2])
751+ network_ref = self.db.network_create_safe(context, net)
752+ if network_ref:
753+ self._create_fixed_ips(context, network_ref['id'])
754+
755+ def get_network(self, context):
756+ """Get the network for the current context"""
757+ # NOTE(vish): To support mutilple network hosts, This could randomly
758+ # select from multiple networks instead of just
759+ # returning the one. It could also potentially be done
760+ # in the scheduler.
761+ return self.db.network_get_by_bridge(context,
762+ FLAGS.flat_network_bridge)
763+
764 def _on_set_network_host(self, context, network_id):
765- """Called when this host becomes the host for a project"""
766- # NOTE(vish): should there be two types of network objects
767- # in the datastore?
768+ """Called when this host becomes the host for a network"""
769 net = {}
770 net['injected'] = True
771- net['netmask'] = FLAGS.flat_network_netmask
772 net['bridge'] = FLAGS.flat_network_bridge
773- net['gateway'] = FLAGS.flat_network_gateway
774- net['broadcast'] = FLAGS.flat_network_broadcast
775 net['dns'] = FLAGS.flat_network_dns
776 self.db.network_update(context, network_id, net)
777- # NOTE(vish): Rignt now we are putting all of the fixed ips in
778- # one large pool, but ultimately it may be better to
779- # have each network manager have its own network that
780- # it is responsible for and its own pool of ips.
781- for address in FLAGS.flat_network_ips:
782- self.db.fixed_ip_create(context, {'address': address})
783+
784
785
786 class VlanManager(NetworkManager):
787@@ -250,10 +268,13 @@
788
789 def allocate_fixed_ip(self, context, instance_id, *args, **kwargs):
790 """Gets a fixed ip from the pool"""
791+ # TODO(vish): This should probably be getting project_id from
792+ # the instance, but it is another trip to the db.
793+ # Perhaps this method should take an instance_ref.
794 network_ref = self.db.project_get_network(context, context.project.id)
795 if kwargs.get('vpn', None):
796 address = network_ref['vpn_private_address']
797- self.db.fixed_ip_associate(context, address, instance_id)
798+ self.db.fixed_ip_associate(None, address, instance_id)
799 else:
800 address = self.db.fixed_ip_associate_pool(None,
801 network_ref['id'],
802@@ -319,38 +340,9 @@
803 network_ref = self.db.fixed_ip_get_network(context, address)
804 self.driver.update_dhcp(context, network_ref['id'])
805
806- def allocate_network(self, context, project_id):
807- """Set up the network"""
808- self._ensure_indexes(context)
809- network_ref = db.network_create(context, {'project_id': project_id})
810- network_id = network_ref['id']
811- private_net = IPy.IP(FLAGS.private_range)
812- index = db.network_get_index(context, network_id)
813- vlan = FLAGS.vlan_start + index
814- start = index * FLAGS.network_size
815- significant_bits = 32 - int(math.log(FLAGS.network_size, 2))
816- cidr = "%s/%s" % (private_net[start], significant_bits)
817- project_net = IPy.IP(cidr)
818-
819- net = {}
820- net['cidr'] = cidr
821- # NOTE(vish): we could turn these into properties
822- net['netmask'] = str(project_net.netmask())
823- net['gateway'] = str(project_net[1])
824- net['broadcast'] = str(project_net.broadcast())
825- net['vpn_private_address'] = str(project_net[2])
826- net['dhcp_start'] = str(project_net[3])
827- net['vlan'] = vlan
828- net['bridge'] = 'br%s' % vlan
829- net['vpn_public_address'] = FLAGS.vpn_ip
830- net['vpn_public_port'] = FLAGS.vpn_start + index
831- db.network_update(context, network_id, net)
832- self._create_fixed_ips(context, network_id)
833- return network_id
834-
835- def setup_compute_network(self, context, project_id):
836+ def setup_compute_network(self, context, instance_id):
837 """Sets up matching network for compute hosts"""
838- network_ref = self.db.project_get_network(context, project_id)
839+ network_ref = db.network_get_by_instance(context, instance_id)
840 self.driver.ensure_vlan_bridge(network_ref['vlan'],
841 network_ref['bridge'])
842
843@@ -359,17 +351,42 @@
844 # TODO(vish): Implement this
845 pass
846
847- def _ensure_indexes(self, context):
848- """Ensure the indexes for the network exist
849+ def create_networks(self, context, cidr, num_networks, network_size,
850+ vlan_start, vpn_start):
851+ """Create networks based on parameters"""
852+ fixed_net = IPy.IP(cidr)
853+ for index in range(num_networks):
854+ vlan = vlan_start + index
855+ start = index * network_size
856+ significant_bits = 32 - int(math.log(network_size, 2))
857+ cidr = "%s/%s" % (fixed_net[start], significant_bits)
858+ project_net = IPy.IP(cidr)
859+ net = {}
860+ net['cidr'] = cidr
861+ net['netmask'] = str(project_net.netmask())
862+ net['gateway'] = str(project_net[1])
863+ net['broadcast'] = str(project_net.broadcast())
864+ net['vpn_private_address'] = str(project_net[2])
865+ net['dhcp_start'] = str(project_net[3])
866+ net['vlan'] = vlan
867+ net['bridge'] = 'br%s' % vlan
868+ # NOTE(vish): This makes ports unique accross the cloud, a more
869+ # robust solution would be to make them unique per ip
870+ net['vpn_public_port'] = vpn_start + index
871+ network_ref = self.db.network_create_safe(context, net)
872+ if network_ref:
873+ self._create_fixed_ips(context, network_ref['id'])
874
875- This could use a manage command instead of keying off of a flag"""
876- if not self.db.network_index_count(context):
877- for index in range(FLAGS.num_networks):
878- self.db.network_index_create_safe(context, {'index': index})
879+ def get_network(self, context):
880+ """Get the network for the current context"""
881+ return self.db.project_get_network(None, context.project.id)
882
883 def _on_set_network_host(self, context, network_id):
884- """Called when this host becomes the host for a project"""
885+ """Called when this host becomes the host for a network"""
886 network_ref = self.db.network_get(context, network_id)
887+ net = {}
888+ net['vpn_public_address'] = FLAGS.vpn_ip
889+ db.network_update(context, network_id, net)
890 self.driver.ensure_vlan_bridge(network_ref['vlan'],
891 network_ref['bridge'],
892 network_ref)
893
894=== modified file 'nova/test.py'
895--- nova/test.py 2010-09-29 11:39:09 +0000
896+++ nova/test.py 2010-10-13 07:50:58 +0000
897@@ -24,6 +24,7 @@
898
899 import sys
900 import time
901+import datetime
902
903 import mox
904 import stubout
905@@ -35,6 +36,7 @@
906 from nova import fakerabbit
907 from nova import flags
908 from nova import rpc
909+from nova.network import manager as network_manager
910
911
912 FLAGS = flags.FLAGS
913@@ -58,6 +60,16 @@
914 def setUp(self): # pylint: disable-msg=C0103
915 """Run before each test method to initialize test environment"""
916 super(TrialTestCase, self).setUp()
917+ # NOTE(vish): We need a better method for creating fixtures for tests
918+ # now that we have some required db setup for the system
919+ # to work properly.
920+ self.start = datetime.datetime.utcnow()
921+ if db.network_count(None) != 5:
922+ network_manager.VlanManager().create_networks(None,
923+ FLAGS.fixed_range,
924+ 5, 16,
925+ FLAGS.vlan_start,
926+ FLAGS.vpn_start)
927
928 # emulate some of the mox stuff, we can't use the metaclass
929 # because it screws with our generators
930@@ -74,7 +86,9 @@
931 self.stubs.UnsetAll()
932 self.stubs.SmartUnsetAll()
933 self.mox.VerifyAll()
934-
935+ # NOTE(vish): Clean up any ips associated during the test.
936+ db.fixed_ip_disassociate_all_by_timeout(None, FLAGS.host, self.start)
937+ db.network_disassociate_all(None)
938 rpc.Consumer.attach_to_twisted = self.originalAttach
939 for x in self.injected:
940 try:
941@@ -140,7 +154,7 @@
942 class BaseTestCase(TrialTestCase):
943 # TODO(jaypipes): Can this be moved into the TrialTestCase class?
944 """Base test case class for all unit tests.
945-
946+
947 DEPRECATED: This is being removed once Tornado is gone, use TrialTestCase.
948 """
949 def setUp(self): # pylint: disable-msg=C0103
950
951=== modified file 'nova/tests/cloud_unittest.py'
952--- nova/tests/cloud_unittest.py 2010-10-11 11:39:33 +0000
953+++ nova/tests/cloud_unittest.py 2010-10-13 07:50:58 +0000
954@@ -64,12 +64,12 @@
955 self.cloud = cloud.CloudController()
956
957 # set up a service
958- self.compute = utils.import_class(FLAGS.compute_manager)()
959+ self.compute = utils.import_object(FLAGS.compute_manager)
960 self.compute_consumer = rpc.AdapterConsumer(connection=self.conn,
961 topic=FLAGS.compute_topic,
962 proxy=self.compute)
963 self.compute_consumer.attach_to_eventlet()
964- self.network = utils.import_class(FLAGS.network_manager)()
965+ self.network = utils.import_object(FLAGS.network_manager)
966 self.network_consumer = rpc.AdapterConsumer(connection=self.conn,
967 topic=FLAGS.network_topic,
968 proxy=self.network)
969
970=== modified file 'nova/tests/compute_unittest.py'
971--- nova/tests/compute_unittest.py 2010-09-30 09:47:05 +0000
972+++ nova/tests/compute_unittest.py 2010-10-13 07:50:58 +0000
973@@ -40,7 +40,8 @@
974 def setUp(self): # pylint: disable-msg=C0103
975 logging.getLogger().setLevel(logging.DEBUG)
976 super(ComputeTestCase, self).setUp()
977- self.flags(connection_type='fake')
978+ self.flags(connection_type='fake',
979+ network_manager='nova.network.manager.FlatManager')
980 self.compute = utils.import_object(FLAGS.compute_manager)
981 self.manager = manager.AuthManager()
982 self.user = self.manager.create_user('fake', 'fake', 'fake')
983
984=== modified file 'nova/tests/network_unittest.py'
985--- nova/tests/network_unittest.py 2010-10-03 18:22:35 +0000
986+++ nova/tests/network_unittest.py 2010-10-13 07:50:58 +0000
987@@ -52,13 +52,14 @@
988 self.context = context.APIRequestContext(project=None, user=self.user)
989 for i in range(5):
990 name = 'project%s' % i
991- self.projects.append(self.manager.create_project(name,
992- 'netuser',
993- name))
994+ project = self.manager.create_project(name, 'netuser', name)
995+ self.projects.append(project)
996 # create the necessary network data for the project
997- user_context = context.get_admin_context(user=self.user)
998-
999- self.network.set_network_host(user_context, self.projects[i].id)
1000+ user_context = context.APIRequestContext(project=self.projects[i],
1001+ user=self.user)
1002+ network_ref = self.network.get_network(user_context)
1003+ self.network.set_network_host(context.get_admin_context(),
1004+ network_ref['id'])
1005 instance_ref = self._create_instance(0)
1006 self.instance_id = instance_ref['id']
1007 instance_ref = self._create_instance(1)
1008@@ -99,7 +100,7 @@
1009 """Makes sure that we can allocaate a public ip"""
1010 # TODO(vish): better way of adding floating ips
1011 self.context.project = self.projects[0]
1012- pubnet = IPy.IP(flags.FLAGS.public_range)
1013+ pubnet = IPy.IP(flags.FLAGS.floating_range)
1014 address = str(pubnet[0])
1015 try:
1016 db.floating_ip_get_by_address(None, address)
1017@@ -109,6 +110,7 @@
1018 float_addr = self.network.allocate_floating_ip(self.context,
1019 self.projects[0].id)
1020 fix_addr = self._create_address(0)
1021+ lease_ip(fix_addr)
1022 self.assertEqual(float_addr, str(pubnet[0]))
1023 self.network.associate_floating_ip(self.context, float_addr, fix_addr)
1024 address = db.instance_get_floating_address(None, self.instance_id)
1025@@ -118,6 +120,7 @@
1026 self.assertEqual(address, None)
1027 self.network.deallocate_floating_ip(self.context, float_addr)
1028 self.network.deallocate_fixed_ip(self.context, fix_addr)
1029+ release_ip(fix_addr)
1030
1031 def test_allocate_deallocate_fixed_ip(self):
1032 """Makes sure that we can allocate and deallocate a fixed ip"""
1033@@ -190,8 +193,10 @@
1034 release_ip(address3)
1035 for instance_id in instance_ids:
1036 db.instance_destroy(None, instance_id)
1037+ self.context.project = self.projects[0]
1038+ self.network.deallocate_fixed_ip(self.context, first)
1039+ self._deallocate_address(0, first)
1040 release_ip(first)
1041- self._deallocate_address(0, first)
1042
1043 def test_vpn_ip_and_port_looks_valid(self):
1044 """Ensure the vpn ip and port are reasonable"""
1045@@ -207,10 +212,13 @@
1046 for i in range(networks_left):
1047 project = self.manager.create_project('many%s' % i, self.user)
1048 projects.append(project)
1049+ db.project_get_network(None, project.id)
1050+ project = self.manager.create_project('last', self.user)
1051+ projects.append(project)
1052 self.assertRaises(db.NoMoreNetworks,
1053- self.manager.create_project,
1054- 'boom',
1055- self.user)
1056+ db.project_get_network,
1057+ None,
1058+ project.id)
1059 for project in projects:
1060 self.manager.delete_project(project)
1061
1062@@ -223,7 +231,9 @@
1063
1064 address2 = self._create_address(0)
1065 self.assertEqual(address, address2)
1066+ lease_ip(address)
1067 self.network.deallocate_fixed_ip(self.context, address2)
1068+ release_ip(address)
1069
1070 def test_available_ips(self):
1071 """Make sure the number of available ips for the network is correct
1072
1073=== modified file 'nova/tests/scheduler_unittest.py'
1074--- nova/tests/scheduler_unittest.py 2010-10-04 09:53:27 +0000
1075+++ nova/tests/scheduler_unittest.py 2010-10-13 07:50:58 +0000
1076@@ -75,6 +75,7 @@
1077 self.flags(connection_type='fake',
1078 max_cores=4,
1079 max_gigabytes=4,
1080+ network_manager='nova.network.manager.FlatManager',
1081 volume_driver='nova.volume.driver.FakeAOEDriver',
1082 scheduler_driver='nova.scheduler.simple.SimpleScheduler')
1083 self.scheduler = manager.SchedulerManager()
1084
1085=== modified file 'nova/tests/virt_unittest.py'
1086--- nova/tests/virt_unittest.py 2010-10-12 20:18:29 +0000
1087+++ nova/tests/virt_unittest.py 2010-10-13 07:50:58 +0000
1088@@ -20,21 +20,22 @@
1089 from nova import db
1090 from nova import flags
1091 from nova import test
1092+from nova import utils
1093 from nova.api import context
1094 from nova.api.ec2 import cloud
1095 from nova.auth import manager
1096-
1097-# Needed to get FLAGS.instances_path defined:
1098-from nova.compute import manager as compute_manager
1099 from nova.virt import libvirt_conn
1100
1101 FLAGS = flags.FLAGS
1102+flags.DECLARE('instances_path', 'nova.compute.manager')
1103
1104 class LibvirtConnTestCase(test.TrialTestCase):
1105 def setUp(self):
1106+ super(LibvirtConnTestCase, self).setUp()
1107 self.manager = manager.AuthManager()
1108 self.user = self.manager.create_user('fake', 'fake', 'fake', admin=True)
1109 self.project = self.manager.create_project('fake', 'fake', 'fake')
1110+ self.network = utils.import_object(FLAGS.network_manager)
1111 FLAGS.instances_path = ''
1112
1113 def test_get_uri_and_template(self):
1114@@ -51,11 +52,15 @@
1115 'instance_type' : 'm1.small'}
1116
1117 instance_ref = db.instance_create(None, instance)
1118- network_ref = db.project_get_network(None, self.project.id)
1119+ user_context = context.APIRequestContext(project=self.project,
1120+ user=self.user)
1121+ network_ref = self.network.get_network(user_context)
1122+ self.network.set_network_host(context.get_admin_context(),
1123+ network_ref['id'])
1124
1125 fixed_ip = { 'address' : ip,
1126 'network_id' : network_ref['id'] }
1127-
1128+
1129 fixed_ip_ref = db.fixed_ip_create(None, fixed_ip)
1130 db.fixed_ip_update(None, ip, { 'allocated' : True,
1131 'instance_id' : instance_ref['id'] })
1132@@ -113,6 +118,7 @@
1133
1134
1135 def tearDown(self):
1136+ super(LibvirtConnTestCase, self).tearDown()
1137 self.manager.delete_project(self.project)
1138 self.manager.delete_user(self.user)
1139
1140
1141=== modified file 'nova/virt/libvirt_conn.py'
1142--- nova/virt/libvirt_conn.py 2010-10-04 19:58:22 +0000
1143+++ nova/virt/libvirt_conn.py 2010-10-13 07:50:58 +0000
1144@@ -287,7 +287,7 @@
1145
1146 key = str(inst['key_data'])
1147 net = None
1148- network_ref = db.project_get_network(None, project.id)
1149+ network_ref = db.network_get_by_instance(None, inst['id'])
1150 if network_ref['injected']:
1151 address = db.instance_get_fixed_address(None, inst['id'])
1152 with open(FLAGS.injected_network_template) as f:
1153@@ -320,7 +320,8 @@
1154 def to_xml(self, instance):
1155 # TODO(termie): cache?
1156 logging.debug('instance %s: starting toXML method', instance['name'])
1157- network = db.project_get_network(None, instance['project_id'])
1158+ network = db.project_get_network(None,
1159+ instance['project_id'])
1160 # FIXME(vish): stick this in db
1161 instance_type = instance_types.INSTANCE_TYPES[instance['instance_type']]
1162 ip_address = db.instance_get_fixed_address({}, instance['id'])