Merge lp:~devcamcar/nova/contextual-authorization into lp:~hudson-openstack/nova/trunk
- contextual-authorization
- Merge into trunk
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 |
Related bugs: |
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.
- 319. By Devin Carlen
-
Cleaned up db/api.py
- 320. By Devin Carlen
-
Locked down fixed ips and improved network tests
- 321. By Devin Carlen
-
Merged trunk
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.
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!
Unmerged revisions
Preview Diff
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) |
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) : read_deleted
148 + """Indicates if the context has access to deleted objects."""
149 + if not context:
150 + return False
151 + return context.
Could we name that function "can_read_deleted" instead of "use_deleted"? I think the former is more descriptive.
3)
202 + if not result: NotFound( 'No service for id %s' % service_id)
203 + raise exception.
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) : query(models. Volume
) .filter_ by(id=volume_ id
) .filter_ by(deleted= use_deleted( context)
) .first( ) context( context) : query(models. Volume
) .filter_ by(project_ id=context. project. id
) .filter_ by(id=volume_ id
) .filter_ by(deleted= False
) .first( )
result = session.
elif is_user_
result = session.
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) : by(project_ id=context. project. id)
q = q.filter_
result = q.first()
5)
Were there any new test cases for this functionality?
Cheers!
-jay