Merge lp:~devcamcar/nova/contextual-authorization into lp:~hudson-openstack/nova/trunk

Proposed by Devin Carlen
Status: Superseded
Proposed branch: lp:~devcamcar/nova/contextual-authorization
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 1818 lines (+659/-400)
8 files modified
nova/api/context.py (+13/-0)
nova/api/ec2/__init__.py (+4/-4)
nova/db/api.py (+0/-5)
nova/db/sqlalchemy/api.py (+581/-246)
nova/db/sqlalchemy/models.py (+26/-120)
nova/network/manager.py (+2/-2)
nova/tests/compute_unittest.py (+4/-2)
nova/tests/network_unittest.py (+29/-21)
To merge this branch: bzr merge lp:~devcamcar/nova/contextual-authorization
Reviewer Review Type Date Requested Status
Jay Pipes (community) Approve
Review via email: mp+37113@code.launchpad.net

This proposal has been superseded by a proposal from 2010-10-01.

Commit message

Refactor sqlalchemy api to perform contextual authorization.

Description of the change

Refactor sqlalchemy api to perform contextual authorization.

All database calls now examine the context object for information about what kind of user is accessing the data. If an administrator is accessing, full privileges are granted. If a normal user is accessing, then checks are made to ensure that the user does indeed have the rights to the data.

Also refactored NovaBase and removed several methods since they would have to be changed when we move away from sqlalchemy models and begin using sqlalchemy table definitions.

To post a comment you must log in.
319. By Devin Carlen

Cleaned up db/api.py

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

Hi! I like a lot of this, Devin :) Nice work.

Couple suggestions on some stuff, though.

1)

106 +def is_admin_context(context):
107 + """Indicates if the request context is an administrator."""
108 + if not context:
109 + warnings.warn('Use of empty request context is deprecated',
110 + DeprecationWarning)
111 + return True
112 + return context.is_admin

Did you really mean to return True there if a context is missing? That seems like it's a bit of a security hole :)

2)

147 +def use_deleted(context):
148 + """Indicates if the context has access to deleted objects."""
149 + if not context:
150 + return False
151 + return context.read_deleted

Could we name that function "can_read_deleted" instead of "use_deleted"? I think the former is more descriptive.

3)

202 + if not result:
203 + raise exception.NotFound('No service for id %s' % service_id)

service_id may not be a string. Probably best to str(service_id) that to avoid a TypeError fuddling up the exception raised.

4)

There are a number of places where you use this pattern in the new code:

if is_admin_context(context):
    result = session.query(models.Volume
                           ).filter_by(id=volume_id
                           ).filter_by(deleted=use_deleted(context)
                           ).first()
elif is_user_context(context):
    result = session.query(models.Volume
                           ).filter_by(project_id=context.project.id
                           ).filter_by(id=volume_id
                           ).filter_by(deleted=False
                           ).first()

It may be a bit more succinct to do this:

q = session.query(models.Volume
                  ).filter_by(id=volume_id
                  ).filter_by(deleted=use_deleted(context))

if is_user_context(context):
   q = q.filter_by(project_id=context.project.id)

result = q.first()

5)

Were there any new test cases for this functionality?

Cheers!

-jay

review: Needs Information
320. By Devin Carlen

Locked down fixed ips and improved network tests

321. By Devin Carlen

Merged trunk

Revision history for this message
Devin Carlen (devcamcar) wrote :

Jay,

1) I did intend to leave that hole for now and add the deprecation warning. If I had implemented it in its final form it would break pretty much the entire system right now. :)

2) done

3) ints are ok with %s, and this form is used tons of places, so should be fine.

4) It's actually important (or will be important in the future) to have project_id first, since that is how the database indexes will be created, and order of filters matters in that case. There is some room for further clean up though and I may get time to take a pass at that, and some better tests, soon.

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

OK on 1 through 3 :)

For #4, though, I'm sorry, I'm going to have to disagree with you on that one :) The order that a filter_by() is added to a Query object does not determine the order in which indexes are created on a table in a RDBMS. The indexes are created on a table already. The query optimizer in the RDBMS *chooses* which indexes to apply depending on the cardinality of the index. The query that is sent to the RDBMS is constructed by SA when the first() method is called, not when the filter_by() method is called.

That said, it was only a suggestion, not something to be fixed immediately :)

Good job on that patch!

review: Approve

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'nova/api/ec2/context.py' => 'nova/api/context.py'
2--- nova/api/ec2/context.py 2010-09-09 23:23:27 +0000
3+++ nova/api/context.py 2010-10-01 09:31:00 +0000
4@@ -31,3 +31,16 @@
5 [random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-')
6 for x in xrange(20)]
7 )
8+ if user:
9+ self.is_admin = user.is_admin()
10+ else:
11+ self.is_admin = False
12+ self.read_deleted = False
13+
14+
15+def get_admin_context(user=None, read_deleted=False):
16+ context_ref = APIRequestContext(user=user, project=None)
17+ context_ref.is_admin = True
18+ context_ref.read_deleted = read_deleted
19+ return context_ref
20+
21
22=== modified file 'nova/api/ec2/__init__.py'
23--- nova/api/ec2/__init__.py 2010-09-28 20:47:29 +0000
24+++ nova/api/ec2/__init__.py 2010-10-01 09:31:00 +0000
25@@ -27,8 +27,8 @@
26 from nova import exception
27 from nova import flags
28 from nova import wsgi
29+from nova.api import context
30 from nova.api.ec2 import apirequest
31-from nova.api.ec2 import context
32 from nova.api.ec2 import admin
33 from nova.api.ec2 import cloud
34 from nova.auth import manager
35@@ -193,15 +193,15 @@
36 return True
37 if 'none' in roles:
38 return False
39- return any(context.project.has_role(context.user.id, role)
40+ return any(context.project.has_role(context.user.id, role)
41 for role in roles)
42-
43+
44
45 class Executor(wsgi.Application):
46
47 """Execute an EC2 API request.
48
49- Executes 'ec2.action' upon 'ec2.controller', passing 'ec2.context' and
50+ Executes 'ec2.action' upon 'ec2.controller', passing 'ec2.context' and
51 'ec2.action_args' (all variables in WSGI environ.) Returns an XML
52 response, or a 400 upon failure.
53 """
54
55=== modified file 'nova/db/api.py'
56--- nova/db/api.py 2010-10-01 01:13:45 +0000
57+++ nova/db/api.py 2010-10-01 09:31:00 +0000
58@@ -175,11 +175,6 @@
59 return IMPL.floating_ip_get_by_address(context, address)
60
61
62-def floating_ip_get_instance(context, address):
63- """Get an instance for a floating ip by address."""
64- return IMPL.floating_ip_get_instance(context, address)
65-
66-
67 ####################
68
69
70
71=== modified file 'nova/db/sqlalchemy/api.py'
72--- nova/db/sqlalchemy/api.py 2010-10-01 01:13:45 +0000
73+++ nova/db/sqlalchemy/api.py 2010-10-01 09:31:00 +0000
74@@ -19,6 +19,8 @@
75 Implementation of SQLAlchemy backend
76 """
77
78+import warnings
79+
80 from nova import db
81 from nova import exception
82 from nova import flags
83@@ -27,39 +29,108 @@
84 from nova.db.sqlalchemy.session import get_session
85 from sqlalchemy import or_
86 from sqlalchemy.exc import IntegrityError
87-from sqlalchemy.orm import joinedload_all
88-from sqlalchemy.orm.exc import NoResultFound
89+from sqlalchemy.orm import joinedload, joinedload_all
90 from sqlalchemy.sql import exists, func
91
92 FLAGS = flags.FLAGS
93
94
95-# NOTE(vish): disabling docstring pylint because the docstrings are
96-# in the interface definition
97-# pylint: disable-msg=C0111
98-def _deleted(context):
99- """Calculates whether to include deleted objects based on context.
100-
101- Currently just looks for a flag called deleted in the context dict.
102- """
103- if not hasattr(context, 'get'):
104- return False
105- return context.get('deleted', False)
106+def is_admin_context(context):
107+ """Indicates if the request context is an administrator."""
108+ if not context:
109+ warnings.warn('Use of empty request context is deprecated',
110+ DeprecationWarning)
111+ return True
112+ return context.is_admin
113+
114+
115+def is_user_context(context):
116+ """Indicates if the request context is a normal user."""
117+ if not context:
118+ return False
119+ if not context.user or not context.project:
120+ return False
121+ return True
122+
123+
124+def authorize_project_context(context, project_id):
125+ """Ensures that the request context has permission to access the
126+ given project.
127+ """
128+ if is_user_context(context):
129+ if not context.project:
130+ raise exception.NotAuthorized()
131+ elif context.project.id != project_id:
132+ raise exception.NotAuthorized()
133+
134+
135+def authorize_user_context(context, user_id):
136+ """Ensures that the request context has permission to access the
137+ given user.
138+ """
139+ if is_user_context(context):
140+ if not context.user:
141+ raise exception.NotAuthorized()
142+ elif context.user.id != user_id:
143+ raise exception.NotAuthorized()
144+
145+
146+def can_read_deleted(context):
147+ """Indicates if the context has access to deleted objects."""
148+ if not context:
149+ return False
150+ return context.read_deleted
151+
152+
153+def require_admin_context(f):
154+ """Decorator used to indicate that the method requires an
155+ administrator context.
156+ """
157+ def wrapper(*args, **kwargs):
158+ if not is_admin_context(args[0]):
159+ raise exception.NotAuthorized()
160+ return f(*args, **kwargs)
161+ return wrapper
162+
163+
164+def require_context(f):
165+ """Decorator used to indicate that the method requires either
166+ an administrator or normal user context.
167+ """
168+ def wrapper(*args, **kwargs):
169+ if not is_admin_context(args[0]) and not is_user_context(args[0]):
170+ raise exception.NotAuthorized()
171+ return f(*args, **kwargs)
172+ return wrapper
173
174
175 ###################
176
177-
178+@require_admin_context
179 def service_destroy(context, service_id):
180 session = get_session()
181 with session.begin():
182- service_ref = models.Service.find(service_id, session=session)
183+ service_ref = service_get(context, service_id, session=session)
184 service_ref.delete(session=session)
185
186-def service_get(_context, service_id):
187- return models.Service.find(service_id)
188-
189-
190+
191+@require_admin_context
192+def service_get(context, service_id, session=None):
193+ if not session:
194+ session = get_session()
195+
196+ result = session.query(models.Service
197+ ).filter_by(id=service_id
198+ ).filter_by(deleted=can_read_deleted(context)
199+ ).first()
200+
201+ if not result:
202+ raise exception.NotFound('No service for id %s' % service_id)
203+
204+ return result
205+
206+
207+@require_admin_context
208 def service_get_all_by_topic(context, topic):
209 session = get_session()
210 return session.query(models.Service
211@@ -69,7 +140,8 @@
212 ).all()
213
214
215-def _service_get_all_topic_subquery(_context, session, topic, subq, label):
216+@require_admin_context
217+def _service_get_all_topic_subquery(context, session, topic, subq, label):
218 sort_value = getattr(subq.c, label)
219 return session.query(models.Service, func.coalesce(sort_value, 0)
220 ).filter_by(topic=topic
221@@ -80,6 +152,7 @@
222 ).all()
223
224
225+@require_admin_context
226 def service_get_all_compute_sorted(context):
227 session = get_session()
228 with session.begin():
229@@ -104,6 +177,7 @@
230 label)
231
232
233+@require_admin_context
234 def service_get_all_network_sorted(context):
235 session = get_session()
236 with session.begin():
237@@ -121,6 +195,7 @@
238 label)
239
240
241+@require_admin_context
242 def service_get_all_volume_sorted(context):
243 session = get_session()
244 with session.begin():
245@@ -138,11 +213,22 @@
246 label)
247
248
249-def service_get_by_args(_context, host, binary):
250- return models.Service.find_by_args(host, binary)
251-
252-
253-def service_create(_context, values):
254+@require_admin_context
255+def service_get_by_args(context, host, binary):
256+ session = get_session()
257+ result = session.query(models.Service
258+ ).filter_by(host=host
259+ ).filter_by(binary=binary
260+ ).filter_by(deleted=can_read_deleted(context)
261+ ).first()
262+ if not result:
263+ raise exception.NotFound('No service for %s, %s' % (host, binary))
264+
265+ return result
266+
267+
268+@require_admin_context
269+def service_create(context, values):
270 service_ref = models.Service()
271 for (key, value) in values.iteritems():
272 service_ref[key] = value
273@@ -150,10 +236,11 @@
274 return service_ref
275
276
277-def service_update(_context, service_id, values):
278+@require_admin_context
279+def service_update(context, service_id, values):
280 session = get_session()
281 with session.begin():
282- service_ref = models.Service.find(service_id, session=session)
283+ service_ref = session_get(context, service_id, session=session)
284 for (key, value) in values.iteritems():
285 service_ref[key] = value
286 service_ref.save(session=session)
287@@ -162,7 +249,9 @@
288 ###################
289
290
291-def floating_ip_allocate_address(_context, host, project_id):
292+@require_context
293+def floating_ip_allocate_address(context, host, project_id):
294+ authorize_project_context(context, project_id)
295 session = get_session()
296 with session.begin():
297 floating_ip_ref = session.query(models.FloatingIp
298@@ -181,7 +270,8 @@
299 return floating_ip_ref['address']
300
301
302-def floating_ip_create(_context, values):
303+@require_context
304+def floating_ip_create(context, values):
305 floating_ip_ref = models.FloatingIp()
306 for (key, value) in values.iteritems():
307 floating_ip_ref[key] = value
308@@ -189,7 +279,9 @@
309 return floating_ip_ref['address']
310
311
312-def floating_ip_count_by_project(_context, project_id):
313+@require_context
314+def floating_ip_count_by_project(context, project_id):
315+ authorize_project_context(context, project_id)
316 session = get_session()
317 return session.query(models.FloatingIp
318 ).filter_by(project_id=project_id
319@@ -197,39 +289,53 @@
320 ).count()
321
322
323-def floating_ip_fixed_ip_associate(_context, floating_address, fixed_address):
324+@require_context
325+def floating_ip_fixed_ip_associate(context, floating_address, fixed_address):
326 session = get_session()
327 with session.begin():
328- floating_ip_ref = models.FloatingIp.find_by_str(floating_address,
329- session=session)
330- fixed_ip_ref = models.FixedIp.find_by_str(fixed_address,
331- session=session)
332+ # TODO(devcamcar): How to ensure floating_id belongs to user?
333+ floating_ip_ref = floating_ip_get_by_address(context,
334+ floating_address,
335+ session=session)
336+ fixed_ip_ref = fixed_ip_get_by_address(context,
337+ fixed_address,
338+ session=session)
339 floating_ip_ref.fixed_ip = fixed_ip_ref
340 floating_ip_ref.save(session=session)
341
342
343-def floating_ip_deallocate(_context, address):
344+@require_context
345+def floating_ip_deallocate(context, address):
346 session = get_session()
347 with session.begin():
348- floating_ip_ref = models.FloatingIp.find_by_str(address,
349- session=session)
350+ # TODO(devcamcar): How to ensure floating id belongs to user?
351+ floating_ip_ref = floating_ip_get_by_address(context,
352+ address,
353+ session=session)
354 floating_ip_ref['project_id'] = None
355 floating_ip_ref.save(session=session)
356
357
358-def floating_ip_destroy(_context, address):
359+@require_context
360+def floating_ip_destroy(context, address):
361 session = get_session()
362 with session.begin():
363- floating_ip_ref = models.FloatingIp.find_by_str(address,
364- session=session)
365+ # TODO(devcamcar): Ensure address belongs to user.
366+ floating_ip_ref = get_floating_ip_by_address(context,
367+ address,
368+ session=session)
369 floating_ip_ref.delete(session=session)
370
371
372-def floating_ip_disassociate(_context, address):
373+@require_context
374+def floating_ip_disassociate(context, address):
375 session = get_session()
376 with session.begin():
377- floating_ip_ref = models.FloatingIp.find_by_str(address,
378- session=session)
379+ # TODO(devcamcar): Ensure address belongs to user.
380+ # Does get_floating_ip_by_address handle this?
381+ floating_ip_ref = floating_ip_get_by_address(context,
382+ address,
383+ session=session)
384 fixed_ip_ref = floating_ip_ref.fixed_ip
385 if fixed_ip_ref:
386 fixed_ip_address = fixed_ip_ref['address']
387@@ -240,7 +346,8 @@
388 return fixed_ip_address
389
390
391-def floating_ip_get_all(_context):
392+@require_admin_context
393+def floating_ip_get_all(context):
394 session = get_session()
395 return session.query(models.FloatingIp
396 ).options(joinedload_all('fixed_ip.instance')
397@@ -248,7 +355,8 @@
398 ).all()
399
400
401-def floating_ip_get_all_by_host(_context, host):
402+@require_admin_context
403+def floating_ip_get_all_by_host(context, host):
404 session = get_session()
405 return session.query(models.FloatingIp
406 ).options(joinedload_all('fixed_ip.instance')
407@@ -256,7 +364,10 @@
408 ).filter_by(deleted=False
409 ).all()
410
411-def floating_ip_get_all_by_project(_context, project_id):
412+
413+@require_context
414+def floating_ip_get_all_by_project(context, project_id):
415+ authorize_project_context(context, project_id)
416 session = get_session()
417 return session.query(models.FloatingIp
418 ).options(joinedload_all('fixed_ip.instance')
419@@ -264,24 +375,31 @@
420 ).filter_by(deleted=False
421 ).all()
422
423-def floating_ip_get_by_address(_context, address):
424- return models.FloatingIp.find_by_str(address)
425-
426-
427-def floating_ip_get_instance(_context, address):
428- session = get_session()
429- with session.begin():
430- floating_ip_ref = models.FloatingIp.find_by_str(address,
431- session=session)
432- return floating_ip_ref.fixed_ip.instance
433+
434+@require_context
435+def floating_ip_get_by_address(context, address, session=None):
436+ # TODO(devcamcar): Ensure the address belongs to user.
437+ if not session:
438+ session = get_session()
439+
440+ result = session.query(models.FloatingIp
441+ ).filter_by(address=address
442+ ).filter_by(deleted=can_read_deleted(context)
443+ ).first()
444+ if not result:
445+ raise exception.NotFound('No fixed ip for address %s' % address)
446+
447+ return result
448
449
450 ###################
451
452
453-def fixed_ip_associate(_context, address, instance_id):
454+@require_context
455+def fixed_ip_associate(context, address, instance_id):
456 session = get_session()
457 with session.begin():
458+ instance = instance_get(context, instance_id, session=session)
459 fixed_ip_ref = session.query(models.FixedIp
460 ).filter_by(address=address
461 ).filter_by(deleted=False
462@@ -292,12 +410,12 @@
463 # then this has concurrency issues
464 if not fixed_ip_ref:
465 raise db.NoMoreAddresses()
466- fixed_ip_ref.instance = models.Instance.find(instance_id,
467- session=session)
468+ fixed_ip_ref.instance = instance
469 session.add(fixed_ip_ref)
470
471
472-def fixed_ip_associate_pool(_context, network_id, instance_id):
473+@require_admin_context
474+def fixed_ip_associate_pool(context, network_id, instance_id):
475 session = get_session()
476 with session.begin():
477 network_or_none = or_(models.FixedIp.network_id == network_id,
478@@ -314,14 +432,17 @@
479 if not fixed_ip_ref:
480 raise db.NoMoreAddresses()
481 if not fixed_ip_ref.network:
482- fixed_ip_ref.network = models.Network.find(network_id,
483- session=session)
484- fixed_ip_ref.instance = models.Instance.find(instance_id,
485- session=session)
486+ fixed_ip_ref.network = network_get(context,
487+ network_id,
488+ session=session)
489+ fixed_ip_ref.instance = instance_get(context,
490+ instance_id,
491+ session=session)
492 session.add(fixed_ip_ref)
493 return fixed_ip_ref['address']
494
495
496+@require_context
497 def fixed_ip_create(_context, values):
498 fixed_ip_ref = models.FixedIp()
499 for (key, value) in values.iteritems():
500@@ -330,14 +451,18 @@
501 return fixed_ip_ref['address']
502
503
504-def fixed_ip_disassociate(_context, address):
505+@require_context
506+def fixed_ip_disassociate(context, address):
507 session = get_session()
508 with session.begin():
509- fixed_ip_ref = models.FixedIp.find_by_str(address, session=session)
510+ fixed_ip_ref = fixed_ip_get_by_address(context,
511+ address,
512+ session=session)
513 fixed_ip_ref.instance = None
514 fixed_ip_ref.save(session=session)
515
516
517+@require_admin_context
518 def fixed_ip_disassociate_all_by_timeout(_context, host, time):
519 session = get_session()
520 # NOTE(vish): The nested select is because sqlite doesn't support
521@@ -354,34 +479,44 @@
522 return result.rowcount
523
524
525-def fixed_ip_get_by_address(_context, address):
526- session = get_session()
527+@require_context
528+def fixed_ip_get_by_address(context, address, session=None):
529+ if not session:
530+ session = get_session()
531 result = session.query(models.FixedIp
532- ).options(joinedload_all('instance')
533 ).filter_by(address=address
534- ).filter_by(deleted=False
535+ ).filter_by(deleted=can_read_deleted(context)
536+ ).options(joinedload('network')
537+ ).options(joinedload('instance')
538 ).first()
539 if not result:
540- raise exception.NotFound("No model for address %s" % address)
541+ raise exception.NotFound('No floating ip for address %s' % address)
542+
543+ if is_user_context(context):
544+ authorize_project_context(context, result.instance.project_id)
545+
546 return result
547
548
549-def fixed_ip_get_instance(_context, address):
550- session = get_session()
551- with session.begin():
552- return models.FixedIp.find_by_str(address, session=session).instance
553-
554-
555-def fixed_ip_get_network(_context, address):
556- session = get_session()
557- with session.begin():
558- return models.FixedIp.find_by_str(address, session=session).network
559-
560-
561-def fixed_ip_update(_context, address, values):
562- session = get_session()
563- with session.begin():
564- fixed_ip_ref = models.FixedIp.find_by_str(address, session=session)
565+@require_context
566+def fixed_ip_get_instance(context, address):
567+ fixed_ip_ref = fixed_ip_get_by_address(context, address)
568+ return fixed_ip_ref.instance
569+
570+
571+@require_admin_context
572+def fixed_ip_get_network(context, address):
573+ fixed_ip_ref = fixed_ip_get_by_address(context, address)
574+ return fixed_ip_ref.network
575+
576+
577+@require_context
578+def fixed_ip_update(context, address, values):
579+ session = get_session()
580+ with session.begin():
581+ fixed_ip_ref = fixed_ip_get_by_address(context,
582+ address,
583+ session=session)
584 for (key, value) in values.iteritems():
585 fixed_ip_ref[key] = value
586 fixed_ip_ref.save(session=session)
587@@ -390,7 +525,8 @@
588 ###################
589
590
591-def instance_create(_context, values):
592+@require_context
593+def instance_create(context, values):
594 instance_ref = models.Instance()
595 for (key, value) in values.iteritems():
596 instance_ref[key] = value
597@@ -399,12 +535,14 @@
598 with session.begin():
599 while instance_ref.ec2_id == None:
600 ec2_id = utils.generate_uid(instance_ref.__prefix__)
601- if not instance_ec2_id_exists(_context, ec2_id, session=session):
602+ if not instance_ec2_id_exists(context, ec2_id, session=session):
603 instance_ref.ec2_id = ec2_id
604 instance_ref.save(session=session)
605 return instance_ref
606
607-def instance_data_get_for_project(_context, project_id):
608+
609+@require_admin_context
610+def instance_data_get_for_project(context, project_id):
611 session = get_session()
612 result = session.query(func.count(models.Instance.id),
613 func.sum(models.Instance.vcpus)
614@@ -415,81 +553,130 @@
615 return (result[0] or 0, result[1] or 0)
616
617
618-def instance_destroy(_context, instance_id):
619+@require_context
620+def instance_destroy(context, instance_id):
621 session = get_session()
622 with session.begin():
623- instance_ref = models.Instance.find(instance_id, session=session)
624+ instance_ref = instance_get(context, instance_id, session=session)
625 instance_ref.delete(session=session)
626
627
628-def instance_get(context, instance_id):
629- return models.Instance.find(instance_id, deleted=_deleted(context))
630-
631-
632+@require_context
633+def instance_get(context, instance_id, session=None):
634+ if not session:
635+ session = get_session()
636+ result = None
637+
638+ if is_admin_context(context):
639+ result = session.query(models.Instance
640+ ).filter_by(id=instance_id
641+ ).filter_by(deleted=can_read_deleted(context)
642+ ).first()
643+ elif is_user_context(context):
644+ result = session.query(models.Instance
645+ ).filter_by(project_id=context.project.id
646+ ).filter_by(id=instance_id
647+ ).filter_by(deleted=False
648+ ).first()
649+ if not result:
650+ raise exception.NotFound('No instance for id %s' % instance_id)
651+
652+ return result
653+
654+
655+@require_admin_context
656 def instance_get_all(context):
657 session = get_session()
658 return session.query(models.Instance
659 ).options(joinedload_all('fixed_ip.floating_ips')
660- ).filter_by(deleted=_deleted(context)
661+ ).filter_by(deleted=can_read_deleted(context)
662 ).all()
663
664+
665+@require_admin_context
666 def instance_get_all_by_user(context, user_id):
667 session = get_session()
668 return session.query(models.Instance
669 ).options(joinedload_all('fixed_ip.floating_ips')
670- ).filter_by(deleted=_deleted(context)
671+ ).filter_by(deleted=can_read_deleted(context)
672 ).filter_by(user_id=user_id
673 ).all()
674
675+
676+@require_context
677 def instance_get_all_by_project(context, project_id):
678+ authorize_project_context(context, project_id)
679+
680 session = get_session()
681 return session.query(models.Instance
682 ).options(joinedload_all('fixed_ip.floating_ips')
683 ).filter_by(project_id=project_id
684- ).filter_by(deleted=_deleted(context)
685+ ).filter_by(deleted=can_read_deleted(context)
686 ).all()
687
688
689-def instance_get_all_by_reservation(_context, reservation_id):
690+@require_context
691+def instance_get_all_by_reservation(context, reservation_id):
692 session = get_session()
693- return session.query(models.Instance
694- ).options(joinedload_all('fixed_ip.floating_ips')
695- ).filter_by(reservation_id=reservation_id
696- ).filter_by(deleted=False
697- ).all()
698-
699-
700+
701+ if is_admin_context(context):
702+ return session.query(models.Instance
703+ ).options(joinedload_all('fixed_ip.floating_ips')
704+ ).filter_by(reservation_id=reservation_id
705+ ).filter_by(deleted=can_read_deleted(context)
706+ ).all()
707+ elif is_user_context(context):
708+ return session.query(models.Instance
709+ ).options(joinedload_all('fixed_ip.floating_ips')
710+ ).filter_by(project_id=context.project.id
711+ ).filter_by(reservation_id=reservation_id
712+ ).filter_by(deleted=False
713+ ).all()
714+
715+
716+@require_context
717 def instance_get_by_ec2_id(context, ec2_id):
718 session = get_session()
719- instance_ref = session.query(models.Instance
720- ).filter_by(ec2_id=ec2_id
721- ).filter_by(deleted=_deleted(context)
722- ).first()
723- if not instance_ref:
724+
725+ if is_admin_context(context):
726+ result = session.query(models.Instance
727+ ).filter_by(ec2_id=ec2_id
728+ ).filter_by(deleted=can_read_deleted(context)
729+ ).first()
730+ elif is_user_context(context):
731+ result = session.query(models.Instance
732+ ).filter_by(project_id=context.project.id
733+ ).filter_by(ec2_id=ec2_id
734+ ).filter_by(deleted=False
735+ ).first()
736+ if not result:
737 raise exception.NotFound('Instance %s not found' % (ec2_id))
738
739- return instance_ref
740-
741-
742+ return result
743+
744+
745+@require_context
746 def instance_ec2_id_exists(context, ec2_id, session=None):
747 if not session:
748 session = get_session()
749 return session.query(exists().where(models.Instance.id==ec2_id)).one()[0]
750
751
752-def instance_get_fixed_address(_context, instance_id):
753+@require_context
754+def instance_get_fixed_address(context, instance_id):
755 session = get_session()
756 with session.begin():
757- instance_ref = models.Instance.find(instance_id, session=session)
758+ instance_ref = instance_get(context, instance_id, session=session)
759 if not instance_ref.fixed_ip:
760 return None
761 return instance_ref.fixed_ip['address']
762
763
764-def instance_get_floating_address(_context, instance_id):
765+@require_context
766+def instance_get_floating_address(context, instance_id):
767 session = get_session()
768 with session.begin():
769- instance_ref = models.Instance.find(instance_id, session=session)
770+ instance_ref = instance_get(context, instance_id, session=session)
771 if not instance_ref.fixed_ip:
772 return None
773 if not instance_ref.fixed_ip.floating_ips:
774@@ -498,12 +685,14 @@
775 return instance_ref.fixed_ip.floating_ips[0]['address']
776
777
778+@require_admin_context
779 def instance_is_vpn(context, instance_id):
780 # TODO(vish): Move this into image code somewhere
781 instance_ref = instance_get(context, instance_id)
782 return instance_ref['image_id'] == FLAGS.vpn_image_id
783
784
785+@require_admin_context
786 def instance_set_state(context, instance_id, state, description=None):
787 # TODO(devcamcar): Move this out of models and into driver
788 from nova.compute import power_state
789@@ -515,10 +704,11 @@
790 'state_description': description})
791
792
793-def instance_update(_context, instance_id, values):
794+@require_context
795+def instance_update(context, instance_id, values):
796 session = get_session()
797 with session.begin():
798- instance_ref = models.Instance.find(instance_id, session=session)
799+ instance_ref = instance_get(context, instance_id, session=session)
800 for (key, value) in values.iteritems():
801 instance_ref[key] = value
802 instance_ref.save(session=session)
803@@ -527,7 +717,8 @@
804 ###################
805
806
807-def key_pair_create(_context, values):
808+@require_context
809+def key_pair_create(context, values):
810 key_pair_ref = models.KeyPair()
811 for (key, value) in values.iteritems():
812 key_pair_ref[key] = value
813@@ -535,16 +726,18 @@
814 return key_pair_ref
815
816
817-def key_pair_destroy(_context, user_id, name):
818+@require_context
819+def key_pair_destroy(context, user_id, name):
820+ authorize_user_context(context, user_id)
821 session = get_session()
822 with session.begin():
823- key_pair_ref = models.KeyPair.find_by_args(user_id,
824- name,
825- session=session)
826+ key_pair_ref = key_pair_get(context, user_id, name, session=session)
827 key_pair_ref.delete(session=session)
828
829
830-def key_pair_destroy_all_by_user(_context, user_id):
831+@require_context
832+def key_pair_destroy_all_by_user(context, user_id):
833+ authorize_user_context(context, user_id)
834 session = get_session()
835 with session.begin():
836 # TODO(vish): do we have to use sql here?
837@@ -552,11 +745,27 @@
838 {'id': user_id})
839
840
841-def key_pair_get(_context, user_id, name):
842- return models.KeyPair.find_by_args(user_id, name)
843-
844-
845-def key_pair_get_all_by_user(_context, user_id):
846+@require_context
847+def key_pair_get(context, user_id, name, session=None):
848+ authorize_user_context(context, user_id)
849+
850+ if not session:
851+ session = get_session()
852+
853+ result = session.query(models.KeyPair
854+ ).filter_by(user_id=user_id
855+ ).filter_by(name=name
856+ ).filter_by(deleted=can_read_deleted(context)
857+ ).first()
858+ if not result:
859+ raise exception.NotFound('no keypair for user %s, name %s' %
860+ (user_id, name))
861+ return result
862+
863+
864+@require_context
865+def key_pair_get_all_by_user(context, user_id):
866+ authorize_user_context(context, user_id)
867 session = get_session()
868 return session.query(models.KeyPair
869 ).filter_by(user_id=user_id
870@@ -567,11 +776,16 @@
871 ###################
872
873
874-def network_count(_context):
875- return models.Network.count()
876-
877-
878-def network_count_allocated_ips(_context, network_id):
879+@require_admin_context
880+def network_count(context):
881+ session = get_session()
882+ return session.query(models.Network
883+ ).filter_by(deleted=can_read_deleted(context)
884+ ).count()
885+
886+
887+@require_admin_context
888+def network_count_allocated_ips(context, network_id):
889 session = get_session()
890 return session.query(models.FixedIp
891 ).filter_by(network_id=network_id
892@@ -580,7 +794,8 @@
893 ).count()
894
895
896-def network_count_available_ips(_context, network_id):
897+@require_admin_context
898+def network_count_available_ips(context, network_id):
899 session = get_session()
900 return session.query(models.FixedIp
901 ).filter_by(network_id=network_id
902@@ -590,7 +805,8 @@
903 ).count()
904
905
906-def network_count_reserved_ips(_context, network_id):
907+@require_admin_context
908+def network_count_reserved_ips(context, network_id):
909 session = get_session()
910 return session.query(models.FixedIp
911 ).filter_by(network_id=network_id
912@@ -599,7 +815,8 @@
913 ).count()
914
915
916-def network_create(_context, values):
917+@require_admin_context
918+def network_create(context, values):
919 network_ref = models.Network()
920 for (key, value) in values.iteritems():
921 network_ref[key] = value
922@@ -607,7 +824,8 @@
923 return network_ref
924
925
926-def network_destroy(_context, network_id):
927+@require_admin_context
928+def network_destroy(context, network_id):
929 session = get_session()
930 with session.begin():
931 # TODO(vish): do we have to use sql here?
932@@ -625,14 +843,34 @@
933 {'id': network_id})
934
935
936-def network_get(_context, network_id):
937- return models.Network.find(network_id)
938+@require_context
939+def network_get(context, network_id, session=None):
940+ if not session:
941+ session = get_session()
942+ result = None
943+
944+ if is_admin_context(context):
945+ result = session.query(models.Network
946+ ).filter_by(id=network_id
947+ ).filter_by(deleted=can_read_deleted(context)
948+ ).first()
949+ elif is_user_context(context):
950+ result = session.query(models.Network
951+ ).filter_by(project_id=context.project.id
952+ ).filter_by(id=network_id
953+ ).filter_by(deleted=False
954+ ).first()
955+ if not result:
956+ raise exception.NotFound('No network for id %s' % network_id)
957+
958+ return result
959
960
961 # NOTE(vish): pylint complains because of the long method name, but
962 # it fits with the names of the rest of the methods
963 # pylint: disable-msg=C0103
964-def network_get_associated_fixed_ips(_context, network_id):
965+@require_admin_context
966+def network_get_associated_fixed_ips(context, network_id):
967 session = get_session()
968 return session.query(models.FixedIp
969 ).options(joinedload_all('instance')
970@@ -642,18 +880,22 @@
971 ).all()
972
973
974-def network_get_by_bridge(_context, bridge):
975+@require_admin_context
976+def network_get_by_bridge(context, bridge):
977 session = get_session()
978- rv = session.query(models.Network
979+ result = session.query(models.Network
980 ).filter_by(bridge=bridge
981 ).filter_by(deleted=False
982 ).first()
983- if not rv:
984+
985+ if not result:
986 raise exception.NotFound('No network for bridge %s' % bridge)
987- return rv
988-
989-
990-def network_get_index(_context, network_id):
991+
992+ return result
993+
994+
995+@require_admin_context
996+def network_get_index(context, network_id):
997 session = get_session()
998 with session.begin():
999 network_index = session.query(models.NetworkIndex
1000@@ -661,19 +903,28 @@
1001 ).filter_by(deleted=False
1002 ).with_lockmode('update'
1003 ).first()
1004+
1005 if not network_index:
1006 raise db.NoMoreNetworks()
1007- network_index['network'] = models.Network.find(network_id,
1008- session=session)
1009+
1010+ network_index['network'] = network_get(context,
1011+ network_id,
1012+ session=session)
1013 session.add(network_index)
1014+
1015 return network_index['index']
1016
1017
1018-def network_index_count(_context):
1019- return models.NetworkIndex.count()
1020-
1021-
1022-def network_index_create_safe(_context, values):
1023+@require_admin_context
1024+def network_index_count(context):
1025+ session = get_session()
1026+ return session.query(models.NetworkIndex
1027+ ).filter_by(deleted=can_read_deleted(context)
1028+ ).count()
1029+
1030+
1031+@require_admin_context
1032+def network_index_create_safe(context, values):
1033 network_index_ref = models.NetworkIndex()
1034 for (key, value) in values.iteritems():
1035 network_index_ref[key] = value
1036@@ -683,29 +934,32 @@
1037 pass
1038
1039
1040-def network_set_host(_context, network_id, host_id):
1041+@require_admin_context
1042+def network_set_host(context, network_id, host_id):
1043 session = get_session()
1044 with session.begin():
1045- network = session.query(models.Network
1046- ).filter_by(id=network_id
1047- ).filter_by(deleted=False
1048- ).with_lockmode('update'
1049- ).first()
1050- if not network:
1051- raise exception.NotFound("Couldn't find network with %s" %
1052- network_id)
1053+ network_ref = session.query(models.Network
1054+ ).filter_by(id=network_id
1055+ ).filter_by(deleted=False
1056+ ).with_lockmode('update'
1057+ ).first()
1058+ if not network_ref:
1059+ raise exception.NotFound('No network for id %s' % network_id)
1060+
1061 # NOTE(vish): if with_lockmode isn't supported, as in sqlite,
1062 # then this has concurrency issues
1063- if not network['host']:
1064- network['host'] = host_id
1065- session.add(network)
1066- return network['host']
1067-
1068-
1069-def network_update(_context, network_id, values):
1070+ if not network_ref['host']:
1071+ network_ref['host'] = host_id
1072+ session.add(network_ref)
1073+
1074+ return network_ref['host']
1075+
1076+
1077+@require_context
1078+def network_update(context, network_id, values):
1079 session = get_session()
1080 with session.begin():
1081- network_ref = models.Network.find(network_id, session=session)
1082+ network_ref = network_get(context, network_id, session=session)
1083 for (key, value) in values.iteritems():
1084 network_ref[key] = value
1085 network_ref.save(session=session)
1086@@ -714,15 +968,18 @@
1087 ###################
1088
1089
1090-def project_get_network(_context, project_id):
1091+@require_context
1092+def project_get_network(context, project_id):
1093 session = get_session()
1094- rv = session.query(models.Network
1095+ result= session.query(models.Network
1096 ).filter_by(project_id=project_id
1097 ).filter_by(deleted=False
1098 ).first()
1099- if not rv:
1100+
1101+ if not result:
1102 raise exception.NotFound('No network for project: %s' % project_id)
1103- return rv
1104+
1105+ return result
1106
1107
1108 ###################
1109@@ -732,14 +989,20 @@
1110 # FIXME(ja): this should be servername?
1111 return "%s.%s" % (topic, physical_node_id)
1112
1113+
1114 ###################
1115
1116
1117-def export_device_count(_context):
1118- return models.ExportDevice.count()
1119-
1120-
1121-def export_device_create(_context, values):
1122+@require_admin_context
1123+def export_device_count(context):
1124+ session = get_session()
1125+ return session.query(models.ExportDevice
1126+ ).filter_by(deleted=can_read_deleted(context)
1127+ ).count()
1128+
1129+
1130+@require_admin_context
1131+def export_device_create(context, values):
1132 export_device_ref = models.ExportDevice()
1133 for (key, value) in values.iteritems():
1134 export_device_ref[key] = value
1135@@ -773,7 +1036,23 @@
1136 ###################
1137
1138
1139-def quota_create(_context, values):
1140+@require_admin_context
1141+def quota_get(context, project_id, session=None):
1142+ if not session:
1143+ session = get_session()
1144+
1145+ result = session.query(models.Quota
1146+ ).filter_by(project_id=project_id
1147+ ).filter_by(deleted=can_read_deleted(context)
1148+ ).first()
1149+ if not result:
1150+ raise exception.NotFound('No quota for project_id %s' % project_id)
1151+
1152+ return result
1153+
1154+
1155+@require_admin_context
1156+def quota_create(context, values):
1157 quota_ref = models.Quota()
1158 for (key, value) in values.iteritems():
1159 quota_ref[key] = value
1160@@ -781,30 +1060,29 @@
1161 return quota_ref
1162
1163
1164-def quota_get(_context, project_id):
1165- return models.Quota.find_by_str(project_id)
1166-
1167-
1168-def quota_update(_context, project_id, values):
1169+@require_admin_context
1170+def quota_update(context, project_id, values):
1171 session = get_session()
1172 with session.begin():
1173- quota_ref = models.Quota.find_by_str(project_id, session=session)
1174+ quota_ref = quota_get(context, project_id, session=session)
1175 for (key, value) in values.iteritems():
1176 quota_ref[key] = value
1177 quota_ref.save(session=session)
1178
1179
1180-def quota_destroy(_context, project_id):
1181+@require_admin_context
1182+def quota_destroy(context, project_id):
1183 session = get_session()
1184 with session.begin():
1185- quota_ref = models.Quota.find_by_str(project_id, session=session)
1186+ quota_ref = quota_get(context, project_id, session=session)
1187 quota_ref.delete(session=session)
1188
1189
1190 ###################
1191
1192
1193-def volume_allocate_shelf_and_blade(_context, volume_id):
1194+@require_admin_context
1195+def volume_allocate_shelf_and_blade(context, volume_id):
1196 session = get_session()
1197 with session.begin():
1198 export_device = session.query(models.ExportDevice
1199@@ -821,19 +1099,20 @@
1200 return (export_device.shelf_id, export_device.blade_id)
1201
1202
1203-def volume_attached(_context, volume_id, instance_id, mountpoint):
1204+@require_admin_context
1205+def volume_attached(context, volume_id, instance_id, mountpoint):
1206 session = get_session()
1207 with session.begin():
1208- volume_ref = models.Volume.find(volume_id, session=session)
1209+ volume_ref = volume_get(context, volume_id, session=session)
1210 volume_ref['status'] = 'in-use'
1211 volume_ref['mountpoint'] = mountpoint
1212 volume_ref['attach_status'] = 'attached'
1213- volume_ref.instance = models.Instance.find(instance_id,
1214- session=session)
1215+ volume_ref.instance = instance_get(context, instance_id, session=session)
1216 volume_ref.save(session=session)
1217
1218
1219-def volume_create(_context, values):
1220+@require_context
1221+def volume_create(context, values):
1222 volume_ref = models.Volume()
1223 for (key, value) in values.iteritems():
1224 volume_ref[key] = value
1225@@ -842,13 +1121,14 @@
1226 with session.begin():
1227 while volume_ref.ec2_id == None:
1228 ec2_id = utils.generate_uid(volume_ref.__prefix__)
1229- if not volume_ec2_id_exists(_context, ec2_id, session=session):
1230+ if not volume_ec2_id_exists(context, ec2_id, session=session):
1231 volume_ref.ec2_id = ec2_id
1232 volume_ref.save(session=session)
1233 return volume_ref
1234
1235
1236-def volume_data_get_for_project(_context, project_id):
1237+@require_admin_context
1238+def volume_data_get_for_project(context, project_id):
1239 session = get_session()
1240 result = session.query(func.count(models.Volume.id),
1241 func.sum(models.Volume.size)
1242@@ -859,7 +1139,8 @@
1243 return (result[0] or 0, result[1] or 0)
1244
1245
1246-def volume_destroy(_context, volume_id):
1247+@require_admin_context
1248+def volume_destroy(context, volume_id):
1249 session = get_session()
1250 with session.begin():
1251 # TODO(vish): do we have to use sql here?
1252@@ -870,10 +1151,11 @@
1253 {'id': volume_id})
1254
1255
1256-def volume_detached(_context, volume_id):
1257+@require_admin_context
1258+def volume_detached(context, volume_id):
1259 session = get_session()
1260 with session.begin():
1261- volume_ref = models.Volume.find(volume_id, session=session)
1262+ volume_ref = volume_get(context, volume_id, session=session)
1263 volume_ref['status'] = 'available'
1264 volume_ref['mountpoint'] = None
1265 volume_ref['attach_status'] = 'detached'
1266@@ -881,60 +1163,113 @@
1267 volume_ref.save(session=session)
1268
1269
1270-def volume_get(context, volume_id):
1271- return models.Volume.find(volume_id, deleted=_deleted(context))
1272-
1273-
1274+@require_context
1275+def volume_get(context, volume_id, session=None):
1276+ if not session:
1277+ session = get_session()
1278+ result = None
1279+
1280+ if is_admin_context(context):
1281+ result = session.query(models.Volume
1282+ ).filter_by(id=volume_id
1283+ ).filter_by(deleted=can_read_deleted(context)
1284+ ).first()
1285+ elif is_user_context(context):
1286+ result = session.query(models.Volume
1287+ ).filter_by(project_id=context.project.id
1288+ ).filter_by(id=volume_id
1289+ ).filter_by(deleted=False
1290+ ).first()
1291+ if not result:
1292+ raise exception.NotFound('No volume for id %s' % volume_id)
1293+
1294+ return result
1295+
1296+
1297+@require_admin_context
1298 def volume_get_all(context):
1299- return models.Volume.all(deleted=_deleted(context))
1300-
1301-
1302+ return session.query(models.Volume
1303+ ).filter_by(deleted=can_read_deleted(context)
1304+ ).all()
1305+
1306+@require_context
1307 def volume_get_all_by_project(context, project_id):
1308+ authorize_project_context(context, project_id)
1309+
1310 session = get_session()
1311 return session.query(models.Volume
1312 ).filter_by(project_id=project_id
1313- ).filter_by(deleted=_deleted(context)
1314+ ).filter_by(deleted=can_read_deleted(context)
1315 ).all()
1316
1317
1318+@require_context
1319 def volume_get_by_ec2_id(context, ec2_id):
1320 session = get_session()
1321- volume_ref = session.query(models.Volume
1322- ).filter_by(ec2_id=ec2_id
1323- ).filter_by(deleted=_deleted(context)
1324- ).first()
1325- if not volume_ref:
1326- raise exception.NotFound('Volume %s not found' % (ec2_id))
1327-
1328- return volume_ref
1329-
1330-
1331+ result = None
1332+
1333+ if is_admin_context(context):
1334+ result = session.query(models.Volume
1335+ ).filter_by(ec2_id=ec2_id
1336+ ).filter_by(deleted=can_read_deleted(context)
1337+ ).first()
1338+ elif is_user_context(context):
1339+ result = session.query(models.Volume
1340+ ).filter_by(project_id=context.project.id
1341+ ).filter_by(ec2_id=ec2_id
1342+ ).filter_by(deleted=False
1343+ ).first()
1344+ else:
1345+ raise exception.NotAuthorized()
1346+
1347+ if not result:
1348+ raise exception.NotFound('Volume %s not found' % ec2_id)
1349+
1350+ return result
1351+
1352+
1353+@require_context
1354 def volume_ec2_id_exists(context, ec2_id, session=None):
1355 if not session:
1356 session = get_session()
1357- return session.query(exists().where(models.Volume.id==ec2_id)).one()[0]
1358-
1359-
1360-def volume_get_instance(_context, volume_id):
1361- session = get_session()
1362- with session.begin():
1363- return models.Volume.find(volume_id, session=session).instance
1364-
1365-
1366-def volume_get_shelf_and_blade(_context, volume_id):
1367- session = get_session()
1368- export_device = session.query(models.ExportDevice
1369- ).filter_by(volume_id=volume_id
1370- ).first()
1371- if not export_device:
1372- raise exception.NotFound()
1373- return (export_device.shelf_id, export_device.blade_id)
1374-
1375-
1376-def volume_update(_context, volume_id, values):
1377- session = get_session()
1378- with session.begin():
1379- volume_ref = models.Volume.find(volume_id, session=session)
1380+
1381+ return session.query(exists(
1382+ ).where(models.Volume.id==ec2_id)
1383+ ).one()[0]
1384+
1385+
1386+@require_admin_context
1387+def volume_get_instance(context, volume_id):
1388+ session = get_session()
1389+ result = session.query(models.Volume
1390+ ).filter_by(id=volume_id
1391+ ).filter_by(deleted=can_read_deleted(context)
1392+ ).options(joinedload('instance')
1393+ ).first()
1394+ if not result:
1395+ raise exception.NotFound('Volume %s not found' % ec2_id)
1396+
1397+ return result.instance
1398+
1399+
1400+@require_admin_context
1401+def volume_get_shelf_and_blade(context, volume_id):
1402+ session = get_session()
1403+ result = session.query(models.ExportDevice
1404+ ).filter_by(volume_id=volume_id
1405+ ).first()
1406+ if not result:
1407+ raise exception.NotFound('No export device found for volume %s' %
1408+ volume_id)
1409+
1410+ return (result.shelf_id, result.blade_id)
1411+
1412+
1413+@require_context
1414+def volume_update(context, volume_id, values):
1415+ session = get_session()
1416+ with session.begin():
1417+ volume_ref = volume_get(context, volume_id, session=session)
1418 for (key, value) in values.iteritems():
1419 volume_ref[key] = value
1420 volume_ref.save(session=session)
1421
1422=== modified file 'nova/db/sqlalchemy/models.py'
1423--- nova/db/sqlalchemy/models.py 2010-09-29 22:24:36 +0000
1424+++ nova/db/sqlalchemy/models.py 2010-10-01 09:31:00 +0000
1425@@ -50,44 +50,6 @@
1426 deleted_at = Column(DateTime)
1427 deleted = Column(Boolean, default=False)
1428
1429- @classmethod
1430- def all(cls, session=None, deleted=False):
1431- """Get all objects of this type"""
1432- if not session:
1433- session = get_session()
1434- return session.query(cls
1435- ).filter_by(deleted=deleted
1436- ).all()
1437-
1438- @classmethod
1439- def count(cls, session=None, deleted=False):
1440- """Count objects of this type"""
1441- if not session:
1442- session = get_session()
1443- return session.query(cls
1444- ).filter_by(deleted=deleted
1445- ).count()
1446-
1447- @classmethod
1448- def find(cls, obj_id, session=None, deleted=False):
1449- """Find object by id"""
1450- if not session:
1451- session = get_session()
1452- try:
1453- return session.query(cls
1454- ).filter_by(id=obj_id
1455- ).filter_by(deleted=deleted
1456- ).one()
1457- except exc.NoResultFound:
1458- new_exc = exception.NotFound("No model for id %s" % obj_id)
1459- raise new_exc.__class__, new_exc, sys.exc_info()[2]
1460-
1461- @classmethod
1462- def find_by_str(cls, str_id, session=None, deleted=False):
1463- """Find object by str_id"""
1464- int_id = int(str_id.rpartition('-')[2])
1465- return cls.find(int_id, session=session, deleted=deleted)
1466-
1467 @property
1468 def str_id(self):
1469 """Get string id of object (generally prefix + '-' + id)"""
1470@@ -176,21 +138,6 @@
1471 report_count = Column(Integer, nullable=False, default=0)
1472 disabled = Column(Boolean, default=False)
1473
1474- @classmethod
1475- def find_by_args(cls, host, binary, session=None, deleted=False):
1476- if not session:
1477- session = get_session()
1478- try:
1479- return session.query(cls
1480- ).filter_by(host=host
1481- ).filter_by(binary=binary
1482- ).filter_by(deleted=deleted
1483- ).one()
1484- except exc.NoResultFound:
1485- new_exc = exception.NotFound("No model for %s, %s" % (host,
1486- binary))
1487- raise new_exc.__class__, new_exc, sys.exc_info()[2]
1488-
1489
1490 class Instance(BASE, NovaBase):
1491 """Represents a guest vm"""
1492@@ -284,7 +231,11 @@
1493 size = Column(Integer)
1494 availability_zone = Column(String(255)) # TODO(vish): foreign key?
1495 instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
1496- instance = relationship(Instance, backref=backref('volumes'))
1497+ instance = relationship(Instance,
1498+ backref=backref('volumes'),
1499+ foreign_keys=instance_id,
1500+ primaryjoin='and_(Volume.instance_id==Instance.id,'
1501+ 'Volume.deleted==False)')
1502 mountpoint = Column(String(255))
1503 attach_time = Column(String(255)) # TODO(vish): datetime
1504 status = Column(String(255)) # TODO(vish): enum?
1505@@ -315,18 +266,6 @@
1506 def str_id(self):
1507 return self.project_id
1508
1509- @classmethod
1510- def find_by_str(cls, str_id, session=None, deleted=False):
1511- if not session:
1512- session = get_session()
1513- try:
1514- return session.query(cls
1515- ).filter_by(project_id=str_id
1516- ).filter_by(deleted=deleted
1517- ).one()
1518- except exc.NoResultFound:
1519- new_exc = exception.NotFound("No model for project_id %s" % str_id)
1520- raise new_exc.__class__, new_exc, sys.exc_info()[2]
1521
1522 class ExportDevice(BASE, NovaBase):
1523 """Represates a shelf and blade that a volume can be exported on"""
1524@@ -335,8 +274,11 @@
1525 shelf_id = Column(Integer)
1526 blade_id = Column(Integer)
1527 volume_id = Column(Integer, ForeignKey('volumes.id'), nullable=True)
1528- volume = relationship(Volume, backref=backref('export_device',
1529- uselist=False))
1530+ volume = relationship(Volume,
1531+ backref=backref('export_device', uselist=False),
1532+ foreign_keys=volume_id,
1533+ primaryjoin='and_(ExportDevice.volume_id==Volume.id,'
1534+ 'ExportDevice.deleted==False)')
1535
1536
1537 class KeyPair(BASE, NovaBase):
1538@@ -354,26 +296,6 @@
1539 def str_id(self):
1540 return '%s.%s' % (self.user_id, self.name)
1541
1542- @classmethod
1543- def find_by_str(cls, str_id, session=None, deleted=False):
1544- user_id, _sep, name = str_id.partition('.')
1545- return cls.find_by_str(user_id, name, session, deleted)
1546-
1547- @classmethod
1548- def find_by_args(cls, user_id, name, session=None, deleted=False):
1549- if not session:
1550- session = get_session()
1551- try:
1552- return session.query(cls
1553- ).filter_by(user_id=user_id
1554- ).filter_by(name=name
1555- ).filter_by(deleted=deleted
1556- ).one()
1557- except exc.NoResultFound:
1558- new_exc = exception.NotFound("No model for user %s, name %s" %
1559- (user_id, name))
1560- raise new_exc.__class__, new_exc, sys.exc_info()[2]
1561-
1562
1563 class Network(BASE, NovaBase):
1564 """Represents a network"""
1565@@ -409,8 +331,12 @@
1566 id = Column(Integer, primary_key=True)
1567 index = Column(Integer, unique=True)
1568 network_id = Column(Integer, ForeignKey('networks.id'), nullable=True)
1569- network = relationship(Network, backref=backref('network_index',
1570- uselist=False))
1571+ network = relationship(Network,
1572+ backref=backref('network_index', uselist=False),
1573+ foreign_keys=network_id,
1574+ primaryjoin='and_(NetworkIndex.network_id==Network.id,'
1575+ 'NetworkIndex.deleted==False)')
1576+
1577
1578 class AuthToken(BASE, NovaBase):
1579 """Represents an authorization token for all API transactions. Fields
1580@@ -434,8 +360,11 @@
1581 network_id = Column(Integer, ForeignKey('networks.id'), nullable=True)
1582 network = relationship(Network, backref=backref('fixed_ips'))
1583 instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
1584- instance = relationship(Instance, backref=backref('fixed_ip',
1585- uselist=False))
1586+ instance = relationship(Instance,
1587+ backref=backref('fixed_ip', uselist=False),
1588+ foreign_keys=instance_id,
1589+ primaryjoin='and_(FixedIp.instance_id==Instance.id,'
1590+ 'FixedIp.deleted==False)')
1591 allocated = Column(Boolean, default=False)
1592 leased = Column(Boolean, default=False)
1593 reserved = Column(Boolean, default=False)
1594@@ -444,19 +373,6 @@
1595 def str_id(self):
1596 return self.address
1597
1598- @classmethod
1599- def find_by_str(cls, str_id, session=None, deleted=False):
1600- if not session:
1601- session = get_session()
1602- try:
1603- return session.query(cls
1604- ).filter_by(address=str_id
1605- ).filter_by(deleted=deleted
1606- ).one()
1607- except exc.NoResultFound:
1608- new_exc = exception.NotFound("No model for address %s" % str_id)
1609- raise new_exc.__class__, new_exc, sys.exc_info()[2]
1610-
1611
1612 class FloatingIp(BASE, NovaBase):
1613 """Represents a floating ip that dynamically forwards to a fixed ip"""
1614@@ -464,24 +380,14 @@
1615 id = Column(Integer, primary_key=True)
1616 address = Column(String(255))
1617 fixed_ip_id = Column(Integer, ForeignKey('fixed_ips.id'), nullable=True)
1618- fixed_ip = relationship(FixedIp, backref=backref('floating_ips'))
1619-
1620+ fixed_ip = relationship(FixedIp,
1621+ backref=backref('floating_ips'),
1622+ foreign_keys=fixed_ip_id,
1623+ primaryjoin='and_(FloatingIp.fixed_ip_id==FixedIp.id,'
1624+ 'FloatingIp.deleted==False)')
1625 project_id = Column(String(255))
1626 host = Column(String(255)) # , ForeignKey('hosts.id'))
1627
1628- @classmethod
1629- def find_by_str(cls, str_id, session=None, deleted=False):
1630- if not session:
1631- session = get_session()
1632- try:
1633- return session.query(cls
1634- ).filter_by(address=str_id
1635- ).filter_by(deleted=deleted
1636- ).one()
1637- except exc.NoResultFound:
1638- new_exc = exception.NotFound("No model for address %s" % str_id)
1639- raise new_exc.__class__, new_exc, sys.exc_info()[2]
1640-
1641
1642 def register_models():
1643 """Register Models and create metadata"""
1644
1645=== modified file 'nova/network/manager.py'
1646--- nova/network/manager.py 2010-10-01 01:13:45 +0000
1647+++ nova/network/manager.py 2010-10-01 09:31:00 +0000
1648@@ -92,7 +92,7 @@
1649 # TODO(vish): can we minimize db access by just getting the
1650 # id here instead of the ref?
1651 network_id = network_ref['id']
1652- host = self.db.network_set_host(context,
1653+ host = self.db.network_set_host(None,
1654 network_id,
1655 self.host)
1656 self._on_set_network_host(context, network_id)
1657@@ -249,7 +249,7 @@
1658 address = network_ref['vpn_private_address']
1659 self.db.fixed_ip_associate(context, address, instance_id)
1660 else:
1661- address = self.db.fixed_ip_associate_pool(context,
1662+ address = self.db.fixed_ip_associate_pool(None,
1663 network_ref['id'],
1664 instance_id)
1665 self.db.fixed_ip_update(context, address, {'allocated': True})
1666
1667=== modified file 'nova/tests/compute_unittest.py'
1668--- nova/tests/compute_unittest.py 2010-09-12 03:00:56 +0000
1669+++ nova/tests/compute_unittest.py 2010-10-01 09:31:00 +0000
1670@@ -30,7 +30,7 @@
1671 from nova import test
1672 from nova import utils
1673 from nova.auth import manager
1674-
1675+from nova.api import context
1676
1677 FLAGS = flags.FLAGS
1678
1679@@ -96,7 +96,9 @@
1680 self.assertEqual(instance_ref['deleted_at'], None)
1681 terminate = datetime.datetime.utcnow()
1682 yield self.compute.terminate_instance(self.context, instance_id)
1683- instance_ref = db.instance_get({'deleted': True}, instance_id)
1684+ self.context = context.get_admin_context(user=self.user,
1685+ read_deleted=True)
1686+ instance_ref = db.instance_get(self.context, instance_id)
1687 self.assert_(instance_ref['launched_at'] < terminate)
1688 self.assert_(instance_ref['deleted_at'] > terminate)
1689
1690
1691=== modified file 'nova/tests/network_unittest.py'
1692--- nova/tests/network_unittest.py 2010-09-16 16:39:35 +0000
1693+++ nova/tests/network_unittest.py 2010-10-01 09:31:00 +0000
1694@@ -56,12 +56,12 @@
1695 'netuser',
1696 name))
1697 # create the necessary network data for the project
1698- self.network.set_network_host(self.context, self.projects[i].id)
1699- instance_ref = db.instance_create(None,
1700- {'mac_address': utils.generate_mac()})
1701+ user_context = context.APIRequestContext(project=self.projects[i],
1702+ user=self.user)
1703+ self.network.set_network_host(user_context, self.projects[i].id)
1704+ instance_ref = self._create_instance(0)
1705 self.instance_id = instance_ref['id']
1706- instance_ref = db.instance_create(None,
1707- {'mac_address': utils.generate_mac()})
1708+ instance_ref = self._create_instance(1)
1709 self.instance2_id = instance_ref['id']
1710
1711 def tearDown(self): # pylint: disable-msg=C0103
1712@@ -74,6 +74,15 @@
1713 self.manager.delete_project(project)
1714 self.manager.delete_user(self.user)
1715
1716+ def _create_instance(self, project_num, mac=None):
1717+ if not mac:
1718+ mac = utils.generate_mac()
1719+ project = self.projects[project_num]
1720+ self.context.project = project
1721+ return db.instance_create(self.context,
1722+ {'project_id': project.id,
1723+ 'mac_address': mac})
1724+
1725 def _create_address(self, project_num, instance_id=None):
1726 """Create an address in given project num"""
1727 if instance_id is None:
1728@@ -81,9 +90,15 @@
1729 self.context.project = self.projects[project_num]
1730 return self.network.allocate_fixed_ip(self.context, instance_id)
1731
1732+ def _deallocate_address(self, project_num, address):
1733+ self.context.project = self.projects[project_num]
1734+ self.network.deallocate_fixed_ip(self.context, address)
1735+
1736+
1737 def test_public_network_association(self):
1738 """Makes sure that we can allocaate a public ip"""
1739 # TODO(vish): better way of adding floating ips
1740+ self.context.project = self.projects[0]
1741 pubnet = IPy.IP(flags.FLAGS.public_range)
1742 address = str(pubnet[0])
1743 try:
1744@@ -109,7 +124,7 @@
1745 address = self._create_address(0)
1746 self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
1747 lease_ip(address)
1748- self.network.deallocate_fixed_ip(self.context, address)
1749+ self._deallocate_address(0, address)
1750
1751 # Doesn't go away until it's dhcp released
1752 self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
1753@@ -130,14 +145,14 @@
1754 lease_ip(address)
1755 lease_ip(address2)
1756
1757- self.network.deallocate_fixed_ip(self.context, address)
1758+ self._deallocate_address(0, address)
1759 release_ip(address)
1760 self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
1761
1762 # First address release shouldn't affect the second
1763 self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
1764
1765- self.network.deallocate_fixed_ip(self.context, address2)
1766+ self._deallocate_address(1, address2)
1767 release_ip(address2)
1768 self.assertFalse(is_allocated_in_project(address2,
1769 self.projects[1].id))
1770@@ -148,24 +163,19 @@
1771 lease_ip(first)
1772 instance_ids = []
1773 for i in range(1, 5):
1774- mac = utils.generate_mac()
1775- instance_ref = db.instance_create(None,
1776- {'mac_address': mac})
1777+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
1778 instance_ids.append(instance_ref['id'])
1779 address = self._create_address(i, instance_ref['id'])
1780- mac = utils.generate_mac()
1781- instance_ref = db.instance_create(None,
1782- {'mac_address': mac})
1783+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
1784 instance_ids.append(instance_ref['id'])
1785 address2 = self._create_address(i, instance_ref['id'])
1786- mac = utils.generate_mac()
1787- instance_ref = db.instance_create(None,
1788- {'mac_address': mac})
1789+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
1790 instance_ids.append(instance_ref['id'])
1791 address3 = self._create_address(i, instance_ref['id'])
1792 lease_ip(address)
1793 lease_ip(address2)
1794 lease_ip(address3)
1795+ self.context.project = self.projects[i]
1796 self.assertFalse(is_allocated_in_project(address,
1797 self.projects[0].id))
1798 self.assertFalse(is_allocated_in_project(address2,
1799@@ -181,7 +191,7 @@
1800 for instance_id in instance_ids:
1801 db.instance_destroy(None, instance_id)
1802 release_ip(first)
1803- self.network.deallocate_fixed_ip(self.context, first)
1804+ self._deallocate_address(0, first)
1805
1806 def test_vpn_ip_and_port_looks_valid(self):
1807 """Ensure the vpn ip and port are reasonable"""
1808@@ -242,9 +252,7 @@
1809 addresses = []
1810 instance_ids = []
1811 for i in range(num_available_ips):
1812- mac = utils.generate_mac()
1813- instance_ref = db.instance_create(None,
1814- {'mac_address': mac})
1815+ instance_ref = self._create_instance(0)
1816 instance_ids.append(instance_ref['id'])
1817 address = self._create_address(0, instance_ref['id'])
1818 addresses.append(address)