Merge lp:~vishvananda/nova/remove-network-index into lp:~hudson-openstack/nova/trunk
- remove-network-index
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Rick Clark (community) | Approve | ||
Jay Pipes (community) | Needs Fixing | ||
Review via email: mp+36921@code.launchpad.net |
Commit message
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_
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_
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.
Comments on these two issues are welcome.
Jay Pipes (jaypipes) wrote : | # |
- 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
Jay Pipes (jaypipes) wrote : | # |
ping. vishy, looks like you need to merge with trunk and resolve conflicts from devin's auth work...
- 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
Preview Diff
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']) |
"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