Merge lp:~devcamcar/django-nova/maintenance_mode into lp:django-nova

Proposed by Devin Carlen
Status: Merged
Approved by: Devin Carlen
Approved revision: 3
Merged at revision: 3
Proposed branch: lp:~devcamcar/django-nova/maintenance_mode
Merge into: lp:django-nova
Diff against target: 867 lines (+155/-95)
10 files modified
src/django_nova/exceptions.py (+39/-11)
src/django_nova/forms.py (+44/-21)
src/django_nova/manager.py (+25/-25)
src/django_nova/shortcuts.py (+6/-2)
src/django_nova/urls/project.py (+1/-0)
src/django_nova/views/images.py (+7/-6)
src/django_nova/views/instances.py (+12/-10)
src/django_nova/views/keypairs.py (+6/-6)
src/django_nova/views/projects.py (+8/-7)
src/django_nova/views/securitygroups.py (+7/-7)
To merge this branch: bzr merge lp:~devcamcar/django-nova/maintenance_mode
Reviewer Review Type Date Requested Status
Devin Carlen Approve
Review via email: mp+46376@code.launchpad.net

Description of the change

Added awareness of nova's maintenance mode to django-nova

To post a comment you must log in.
Revision history for this message
Devin Carlen (devcamcar) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/django_nova/exceptions.py'
2--- src/django_nova/exceptions.py 2011-01-12 20:02:06 +0000
3+++ src/django_nova/exceptions.py 2011-01-15 09:31:13 +0000
4@@ -15,14 +15,20 @@
5 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
6 # License for the specific language governing permissions and limitations
7 # under the License.
8+
9 """
10 Better wrappers for errors from Nova's admin api.
11 """
12
13 import boto.exception
14+from django.shortcuts import redirect
15+from django.utils.http import urlquote
16
17
18 class NovaResponseError(Exception):
19+ """
20+ Consumes a BotoServerError and gives more meaningful errors.
21+ """
22 def __init__(self, ec2error):
23 self.code = ec2error.reason
24 if ec2error.reason == 'Unauthorized':
25@@ -36,15 +42,37 @@
26 return self.message
27
28
29-def handle_nova_error(fn):
30- def decorator(view_func):
31- def wrapper(*args, **kwargs):
32- try:
33- return view_func(*args, **kwargs)
34- except boto.exception.EC2ResponseError, e:
35- raise NovaResponseError(e)
36- return wrapper
37- return decorator(fn)
38-
39-
40+class NovaUnavailableError(Exception):
41+ """
42+ Used when Nova returns a 503 Service Unavailable status.
43+ """
44+ pass
45+
46+
47+def wrap_nova_error(func):
48+ """
49+ Used to decorate a function that interacts with boto. It will catch
50+ and convert boto server errors and reraise as a more specific nova error.
51+ """
52+ def decorator(*args, **kwargs):
53+ try:
54+ return func(*args, **kwargs)
55+ except boto.exception.BotoServerError, e:
56+ if e.status == 503:
57+ raise NovaUnavailableError(e)
58+ raise NovaResponseError(e)
59+ return decorator
60+
61+
62+def handle_nova_error(func):
63+ """
64+ Decorator for handling nova errors in a generalized way.
65+ """
66+ def decorator(*args, **kwargs):
67+ try:
68+ return func(*args, **kwargs)
69+ except NovaUnavailableError:
70+ return redirect('nova_unavailable')
71+ return decorator
72+
73
74
75=== modified file 'src/django_nova/forms.py'
76--- src/django_nova/forms.py 2011-01-12 20:02:06 +0000
77+++ src/django_nova/forms.py 2011-01-15 09:31:13 +0000
78@@ -15,6 +15,7 @@
79 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
80 # License for the specific language governing permissions and limitations
81 # under the License.
82+
83 """
84 Forms used by various views.
85 """
86@@ -24,6 +25,7 @@
87 from django import forms
88 from django.contrib.auth import models as auth_models
89 from django_nova.connection import get_nova_admin_connection
90+from django_nova.exceptions import wrap_nova_error
91
92
93 # TODO: Store this in settings.
94@@ -32,6 +34,7 @@
95 alphanumeric_re = re.compile(r'^\w+$')
96
97
98+@wrap_nova_error
99 def get_instance_type_choices():
100 """
101 Returns list of instance types from nova admin api
102@@ -75,11 +78,13 @@
103 ('udp', 'udp'),
104 )
105
106+
107 class ProjectFormBase(forms.Form):
108 def __init__(self, project, *args, **kwargs):
109 self.project = project
110 super(ProjectFormBase, self).__init__(*args, **kwargs)
111
112+
113 class LaunchInstanceForm(forms.Form):
114 # nickname = forms.CharField()
115 # description = forms.CharField()
116@@ -96,6 +101,7 @@
117 self.fields['key_name'].choices = get_key_pair_choices(project)
118 self.fields['size'].choices = get_instance_type_choices()
119
120+
121 class UpdateInstanceForm(forms.Form):
122 nickname = forms.CharField(required=False, label="Name")
123 description = forms.CharField(required=False, widget=forms.Textarea, max_length=70)
124@@ -105,6 +111,7 @@
125 self.fields['nickname'].initial = instance.displayName
126 self.fields['description'].initial = instance.displayDescription
127
128+
129 class UpdateImageForm(forms.Form):
130 nickname = forms.CharField(required=False, label="Name")
131 description = forms.CharField(required=False, widget=forms.Textarea, max_length=70)
132@@ -126,6 +133,7 @@
133
134 return name
135
136+
137 class CreateSecurityGroupForm(ProjectFormBase):
138 name = forms.RegexField(regex=alphanumeric_re)
139 description = forms.CharField()
140@@ -138,16 +146,19 @@
141
142 return name
143
144+
145 class AuthorizeSecurityGroupRuleForm(forms.Form):
146 protocol = forms.ChoiceField(choices=get_protocols())
147 from_port = forms.IntegerField(min_value=1, max_value=65535)
148 to_port = forms.IntegerField(min_value=1, max_value=65535)
149
150+
151 class CreateVolumeForm(forms.Form):
152 size = forms.IntegerField(label='Size (in GB)', min_value=1, max_value=MAX_VOLUME_SIZE)
153 nickname = forms.CharField()
154 description = forms.CharField()
155
156+
157 class AttachVolumeForm(ProjectFormBase):
158 volume = forms.ChoiceField()
159 instance = forms.ChoiceField()
160@@ -158,6 +169,7 @@
161 self.fields['volume'].choices = get_available_volume_choices(project)
162 self.fields['instance'].choices = get_instance_choices(project)
163
164+
165 class ProjectForm(forms.Form):
166 projectname = forms.CharField(label="Project Name", max_length=20)
167 description = forms.CharField(label="Description",
168@@ -165,38 +177,50 @@
169 manager = forms.ModelChoiceField(queryset=auth_models.User.objects.all(),
170 label="Project Manager")
171
172-def get_roles():
173- return (
174- ('netadmin', 'Netadmin'),
175- ('sysadmin', 'Sysadmin'),
176- ('developer', 'Developer'),
177- )
178+@wrap_nova_error
179+def get_roles(project_roles=True):
180+ nova = get_nova_admin_connection()
181+ roles = nova.get_roles(project_roles=project_roles)
182+ return [(role.role, role.role) for role in roles]
183+
184+
185+@wrap_nova_error
186+def get_members(project):
187+ nova = get_nova_admin_connection()
188+ members = nova.get_project_members(project)
189+ return [str(user.memberId) for user in members]
190+
191
192 class GlobalRolesForm(forms.Form):
193- nova = get_nova_admin_connection()
194- roles = [(role.role, role.role) for role in nova.get_roles(project_roles=False)]
195-
196- role = forms.MultipleChoiceField(choices=roles, label='Roles', required=False)
197+ role = forms.MultipleChoiceField(label='Roles', required=False)
198+
199+ def __init__(self, *args, **kwargs):
200+ super(GlobalRolesForm, self).__init__(*args, **kwargs)
201+ self.fields['role'].choices = get_roles(project_roles=False)
202+
203
204 class ProjectUserForm(forms.Form):
205- nova = get_nova_admin_connection()
206- roles = [(role.role, role.role) for role in nova.get_roles(project_roles=True)]
207-
208- role = forms.MultipleChoiceField(choices=roles, label='Roles', required=False)
209+ role = forms.MultipleChoiceField(label='Roles', required=False)
210+
211+ def __init__(self, *args, **kwargs):
212+ super(ProjectUserForm, self).__init__(*args, **kwargs)
213+ self.fields['role'].choices = get_roles(project_roles=False)
214+
215
216 class AddProjectUserForm(forms.Form):
217- username = forms.ModelChoiceField(queryset='', label='Username', empty_label='Select a Username')
218- role = forms.MultipleChoiceField(choices=get_roles(), label='Roles')
219+ username = forms.ModelChoiceField(queryset='',
220+ label='Username',
221+ empty_label='Select a Username')
222+ role = forms.MultipleChoiceField(label='Roles')
223
224 def __init__(self, *args, **kwargs):
225 project = kwargs.pop('project')
226 super(AddProjectUserForm, self).__init__(*args, **kwargs)
227-
228- nova = get_nova_admin_connection()
229- current_members = [str(user.memberId) for user in nova.get_project_members(project)]
230+ members = get_members(project)
231
232 self.fields['username'].queryset = \
233- auth_models.User.objects.exclude(username__in=current_members)
234+ auth_models.User.objects.exclude(username__in=members)
235+ self.fields['role'].choices = get_roles()
236
237
238 class SendCredentialsForm(forms.Form):
239@@ -205,7 +229,6 @@
240 def __init__(self, *args, **kwargs):
241 query_list = kwargs.pop('query_list')
242 super(SendCredentialsForm, self).__init__(*args, **kwargs)
243- choices = []
244
245 self.fields['users'].choices = [(choices, choices) for choices in query_list]
246
247
248=== modified file 'src/django_nova/manager.py'
249--- src/django_nova/manager.py 2011-01-12 20:02:06 +0000
250+++ src/django_nova/manager.py 2011-01-15 09:31:13 +0000
251@@ -25,7 +25,7 @@
252 import boto.s3
253 from django.conf import settings
254 from django_nova.connection import get_nova_admin_connection
255-from django_nova.exceptions import handle_nova_error
256+from django_nova.exceptions import wrap_nova_error
257
258
259 class ProjectManager(object):
260@@ -67,7 +67,7 @@
261 except IndexError:
262 return None
263
264- @handle_nova_error
265+ @wrap_nova_error
266 def deregister_image(self, image_id):
267 """
268 Removes the image's listing but leaves the image
269@@ -76,7 +76,7 @@
270 conn = self.get_nova_connection()
271 return conn.deregister_image(image_id)
272
273- @handle_nova_error
274+ @wrap_nova_error
275 def update_image(self, image_id, display_name=None, description=None):
276 conn = self.get_nova_connection()
277 params = {
278@@ -86,7 +86,7 @@
279 }
280 return conn.get_object('UpdateImage', params, boto.ec2.image.Image)
281
282- @handle_nova_error
283+ @wrap_nova_error
284 def run_instances(self, image_id, **kwargs):
285 """
286 Runs instances of the specified image id.
287@@ -103,7 +103,7 @@
288 except:
289 return None
290
291- @handle_nova_error
292+ @wrap_nova_error
293 def get_instances(self):
294 """
295 Returns all instances in this project.
296@@ -116,7 +116,7 @@
297 instances.append(instance)
298 return instances
299
300- @handle_nova_error
301+ @wrap_nova_error
302 def get_instance(self, instance_id):
303 """
304 Returns detail about the specified instance.
305@@ -130,7 +130,7 @@
306 return instance
307 return None
308
309- @handle_nova_error
310+ @wrap_nova_error
311 def update_instance(self, instance_id, updates):
312 conn = self.get_nova_connection()
313 params = {'InstanceId': instance_id, 'DisplayName': updates['nickname'],
314@@ -163,13 +163,13 @@
315
316 return key.read()
317
318- @handle_nova_error
319+ @wrap_nova_error
320 def terminate_instance(self, instance_id):
321 """ Terminates the specified instance within this project. """
322 conn = self.get_nova_connection()
323 conn.terminate_instances([instance_id])
324
325- @handle_nova_error
326+ @wrap_nova_error
327 def get_security_groups(self):
328 """
329 Returns all security groups associated with this project.
330@@ -184,7 +184,7 @@
331
332 return groups
333
334- @handle_nova_error
335+ @wrap_nova_error
336 def get_security_group(self, name):
337 """
338 Returns the specified security group for this project.
339@@ -196,14 +196,14 @@
340 except IndexError:
341 return None
342
343- @handle_nova_error
344+ @wrap_nova_error
345 def has_security_group(self, name):
346 """
347 Indicates whether a security group with the specified name exists in this project.
348 """
349 return self.get_security_group(name) != None
350
351- @handle_nova_error
352+ @wrap_nova_error
353 def create_security_group(self, name, description):
354 """
355 Creates a new security group in this project.
356@@ -211,7 +211,7 @@
357 conn = self.get_nova_connection()
358 return conn.create_security_group(name, description)
359
360- @handle_nova_error
361+ @wrap_nova_error
362 def delete_security_group(self, name):
363 """
364 Deletes a security group from the project.
365@@ -219,7 +219,7 @@
366 conn = self.get_nova_connection()
367 return conn.delete_security_group(name = name)
368
369- @handle_nova_error
370+ @wrap_nova_error
371 def authorize_security_group(self, group_name, ip_protocol, from_port, to_port):
372 """
373 Authorizes a rule for the specified security group.
374@@ -233,7 +233,7 @@
375 cidr_ip = '0.0.0.0/0'
376 )
377
378- @handle_nova_error
379+ @wrap_nova_error
380 def revoke_security_group(self, group_name, ip_protocol, from_port, to_port):
381 """
382 Revokes a rule for the specified security group.
383@@ -247,7 +247,7 @@
384 cidr_ip = '0.0.0.0/0'
385 )
386
387- @handle_nova_error
388+ @wrap_nova_error
389 def get_key_pairs(self):
390 """
391 Returns all key pairs associated with this project.
392@@ -262,7 +262,7 @@
393
394 return keys
395
396- @handle_nova_error
397+ @wrap_nova_error
398 def get_key_pair(self, name):
399 """
400 Returns the specified security group for this project.
401@@ -274,14 +274,14 @@
402 except IndexError:
403 return None
404
405- @handle_nova_error
406+ @wrap_nova_error
407 def has_key_pair(self, name):
408 """
409 Indicates whether a key pair with the specified name exists in this project.
410 """
411 return self.get_key_pair(name) != None
412
413- @handle_nova_error
414+ @wrap_nova_error
415 def create_key_pair(self, name):
416 """
417 Creates a new key pair for this project.
418@@ -289,7 +289,7 @@
419 conn = self.get_nova_connection()
420 return conn.create_key_pair(name)
421
422- @handle_nova_error
423+ @wrap_nova_error
424 def delete_key_pair(self, name):
425 """
426 Deletes a new key pair from this project.
427@@ -297,7 +297,7 @@
428 conn = self.get_nova_connection()
429 conn.delete_key_pair(name)
430
431- @handle_nova_error
432+ @wrap_nova_error
433 def get_volumes(self):
434 """
435 Returns all volumes in this project.
436@@ -305,7 +305,7 @@
437 conn = self.get_nova_connection()
438 return conn.get_all_volumes()
439
440- @handle_nova_error
441+ @wrap_nova_error
442 def create_volume(self, size, display_name=None, display_description=None,
443 snapshot=None):
444 conn = self.get_nova_connection()
445@@ -313,17 +313,17 @@
446 'DisplayDescription': display_description}
447 return conn.get_object('CreateVolume', params, boto.ec2.volume.Volume)
448
449- @handle_nova_error
450+ @wrap_nova_error
451 def delete_volume(self, volume_id):
452 conn = self.get_nova_connection()
453 return conn.delete_volume(volume_id)
454
455- @handle_nova_error
456+ @wrap_nova_error
457 def attach_volume(self, volume_id, instance_id, device):
458 conn = self.get_nova_connection()
459 return conn.attach_volume(volume_id, instance_id, device)
460
461- @handle_nova_error
462+ @wrap_nova_error
463 def detach_volume(self, volume_id):
464 conn = self.get_nova_connection()
465 return conn.detach_volume(volume_id)
466
467=== modified file 'src/django_nova/shortcuts.py'
468--- src/django_nova/shortcuts.py 2011-01-12 20:02:06 +0000
469+++ src/django_nova/shortcuts.py 2011-01-15 09:31:13 +0000
470@@ -25,8 +25,10 @@
471 from django.http import Http404
472 from django_nova import manager
473 from django_nova.connection import get_nova_admin_connection
474-
475-
476+from django_nova.exceptions import wrap_nova_error
477+
478+
479+@wrap_nova_error
480 def get_project_or_404(request, project_id):
481 """
482 Returns a project or 404s if it doesn't exist.
483@@ -46,6 +48,7 @@
484 return manager.ProjectManager(request.user, project, region)
485
486
487+@wrap_nova_error
488 def get_projects(user):
489 """
490 Returns a list of projects for a user.
491@@ -102,6 +105,7 @@
492 request.session['region'] = region_name
493
494
495+@wrap_nova_error
496 def get_user_image_permissions(username, project_name):
497 """
498 Returns true if user is a sysadmin and can modify image attributes.
499
500=== modified file 'src/django_nova/urls/project.py'
501--- src/django_nova/urls/project.py 2011-01-12 20:02:06 +0000
502+++ src/django_nova/urls/project.py 2011-01-15 09:31:13 +0000
503@@ -15,6 +15,7 @@
504 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
505 # License for the specific language governing permissions and limitations
506 # under the License.
507+
508 """
509 URL patterns for managing Nova projects.
510 """
511
512=== modified file 'src/django_nova/views/images.py'
513--- src/django_nova/views/images.py 2011-01-12 20:02:06 +0000
514+++ src/django_nova/views/images.py 2011-01-15 09:31:13 +0000
515@@ -28,9 +28,9 @@
516 from django.contrib import messages
517 from django.contrib.auth.decorators import login_required
518 from django.shortcuts import redirect, render_to_response
519-from django.views.decorators.cache import never_cache
520 from django_nova import exceptions
521 from django_nova import forms
522+from django_nova.exceptions import handle_nova_error
523 from django_nova.shortcuts import get_project_or_404, get_projects, get_user_image_permissions
524
525
526@@ -50,7 +50,7 @@
527
528
529 @login_required
530-@never_cache
531+@handle_nova_error
532 def index(request, project_id):
533 project = get_project_or_404(request, project_id)
534 project_list = get_projects(request.user)
535@@ -67,6 +67,7 @@
536
537
538 @login_required
539+@handle_nova_error
540 def launch(request, project_id, image_id):
541 project = get_project_or_404(request, project_id)
542 project_list = get_projects(request.user)
543@@ -107,7 +108,7 @@
544
545
546 @login_required
547-@never_cache
548+@handle_nova_error
549 def detail(request, project_id, image_id):
550 project = get_project_or_404(request, project_id)
551 project_list = get_projects(request.user)
552@@ -133,7 +134,7 @@
553
554
555 @login_required
556-@never_cache
557+@handle_nova_error
558 def remove(request, project_id, image_id):
559 project = get_project_or_404(request, project_id)
560
561@@ -163,7 +164,7 @@
562
563
564 @login_required
565-@never_cache
566+@handle_nova_error
567 def privacy(request, project_id, image_id):
568 project = get_project_or_404(request, project_id)
569 conn = project.get_nova_connection()
570@@ -196,7 +197,7 @@
571
572
573 @login_required
574-@never_cache
575+@handle_nova_error
576 def update(request, project_id, image_id):
577 project = get_project_or_404(request, project_id)
578 project_list = get_projects(request.user)
579
580=== modified file 'src/django_nova/views/instances.py'
581--- src/django_nova/views/instances.py 2011-01-12 20:02:06 +0000
582+++ src/django_nova/views/instances.py 2011-01-15 09:31:13 +0000
583@@ -25,14 +25,14 @@
584 from django.contrib import messages
585 from django.contrib.auth.decorators import login_required
586 from django.shortcuts import redirect, render_to_response
587-from django.views.decorators.cache import never_cache
588 from django_nova import exceptions
589 from django_nova import forms as nova_forms
590+from django_nova.exceptions import handle_nova_error
591 from django_nova.shortcuts import get_project_or_404, get_projects
592
593
594 @login_required
595-@never_cache
596+@handle_nova_error
597 def index(request, project_id):
598 project = get_project_or_404(request, project_id)
599 project_list = get_projects(request.user)
600@@ -50,7 +50,7 @@
601
602
603 @login_required
604-@never_cache
605+@handle_nova_error
606 def detail(request, project_id, instance_id):
607 project = get_project_or_404(request, project_id)
608 project_list = get_projects(request.user)
609@@ -74,7 +74,7 @@
610
611
612 @login_required
613-@never_cache
614+@handle_nova_error
615 def performance(request, project_id, instance_id):
616 project = get_project_or_404(request, project_id)
617 project_list = get_projects(request.user)
618@@ -95,7 +95,6 @@
619
620
621 # TODO(devcamcar): Wrap this in an @ajax decorator.
622-@never_cache
623 def refresh(request, project_id):
624 # TODO(devcamcar): This logic belongs in decorator.
625 if not request.user.is_authenticated():
626@@ -110,7 +109,7 @@
627 }, context_instance = template.RequestContext(request))
628
629
630-@never_cache
631+@handle_nova_error
632 def refresh_detail(request, project_id, instance_id):
633 # TODO(devcamcar): This logic belongs in decorator.
634 if not request.user.is_authenticated():
635@@ -128,7 +127,7 @@
636
637
638 @login_required
639-@never_cache
640+@handle_nova_error
641 def terminate(request, project_id):
642 project = get_project_or_404(request, project_id)
643
644@@ -146,6 +145,7 @@
645
646
647 @login_required
648+@handle_nova_error
649 def console(request, project_id, instance_id):
650 project = get_project_or_404(request, project_id)
651 conn = project.get_nova_connection()
652@@ -158,10 +158,12 @@
653
654
655 @login_required
656+@handle_nova_error
657 def graph(request, project_id, instance_id, graph_name):
658 project = get_project_or_404(request, project_id)
659 graph = project.get_instance_graph(instance_id, graph_name)
660- if graph == None:
661+
662+ if graph is None:
663 raise http.Http404()
664
665 response = http.HttpResponse(mimetype='image/png')
666@@ -171,14 +173,14 @@
667
668
669 @login_required
670-@never_cache
671+@handle_nova_error
672 def update(request, project_id, instance_id):
673 project = get_project_or_404(request, project_id)
674 project_list = get_projects(request.user)
675 page_type = "instances"
676 instance = project.get_instance(instance_id)
677
678- if instance == None:
679+ if instance is None:
680 raise http.Http404()
681
682 if request.method == 'POST':
683
684=== modified file 'src/django_nova/views/keypairs.py'
685--- src/django_nova/views/keypairs.py 2011-01-12 20:02:06 +0000
686+++ src/django_nova/views/keypairs.py 2011-01-15 09:31:13 +0000
687@@ -25,14 +25,14 @@
688 from django.contrib import messages
689 from django.contrib.auth.decorators import login_required
690 from django.shortcuts import redirect, render_to_response
691-from django.views.decorators.cache import never_cache
692 from django_nova import exceptions
693 from django_nova import forms
694+from django_nova.exceptions import handle_nova_error
695 from django_nova.shortcuts import get_project_or_404, get_projects
696
697
698 @login_required
699-@never_cache
700+@handle_nova_error
701 def index(request, project_id, download_key=None):
702 project = get_project_or_404(request, project_id)
703 project_list = get_projects(request.user)
704@@ -50,7 +50,7 @@
705 }, context_instance = template.RequestContext(request))
706
707 @login_required
708-@never_cache
709+@handle_nova_error
710 def add(request, project_id):
711 project = get_project_or_404(request, project_id)
712 project_list = get_projects(request.user)
713@@ -94,7 +94,7 @@
714 return redirect('nova_keypairs', project_id)
715
716 @login_required
717-@never_cache
718+@handle_nova_error
719 def delete(request, project_id):
720 project = get_project_or_404(request, project_id)
721
722@@ -105,7 +105,7 @@
723 project.delete_key_pair(key_name)
724 except exceptions.NovaResponseError, e:
725 messages.error(request,
726- 'Unable to delete key: %s - %s (%s)' % \
727+ 'Unable to delete key: %s - %s' % \
728 (e.code, e.message,))
729 else:
730 messages.success(request,
731@@ -115,7 +115,7 @@
732 return redirect('nova_keypairs', project_id)
733
734 @login_required
735-@never_cache
736+@handle_nova_error
737 def download(request, project_id, key_name):
738 # Ensure the project exists.
739 get_project_or_404(request, project_id)
740
741=== modified file 'src/django_nova/views/projects.py'
742--- src/django_nova/views/projects.py 2011-01-12 20:02:06 +0000
743+++ src/django_nova/views/projects.py 2011-01-15 09:31:13 +0000
744@@ -25,14 +25,14 @@
745 from django.contrib.auth import models as auth_models
746 from django.contrib.auth.decorators import login_required
747 from django.shortcuts import redirect, render_to_response
748-from django.views.decorators.cache import never_cache
749 from django_nova import forms as nova_forms
750 from django_nova.connection import get_nova_admin_connection
751+from django_nova.exceptions import handle_nova_error
752 from django_nova.shortcuts import get_project_or_404, get_projects
753
754
755 @login_required
756-@never_cache
757+@handle_nova_error
758 def detail(request, project_id):
759 project = get_project_or_404(request, project_id)
760 project_list = get_projects(user=request.user)
761@@ -46,11 +46,12 @@
762
763
764 @login_required
765-@never_cache
766+@handle_nova_error
767 def manage(request, project_id):
768 project = get_project_or_404(request, project_id)
769 project_list = get_projects(user=request.user)
770- if project.projectManagerId <> request.user.username:
771+
772+ if project.projectManagerId != request.user.username:
773 return redirect('login')
774
775 nova = get_nova_admin_connection()
776@@ -86,7 +87,7 @@
777
778
779 @login_required
780-@never_cache
781+@handle_nova_error
782 def edit_user(request, project_id, project_user):
783 nova = get_nova_admin_connection()
784 userroles = nova.get_user_roles(project_user, project_id)
785@@ -94,7 +95,7 @@
786 project_list = get_projects(user=request.user)
787 edit_user = nova.get_user(project_user)
788
789- if project.projectManagerId <> request.user.username:
790+ if project.projectManagerId != request.user.username:
791 return redirect('login')
792
793 try:
794@@ -130,7 +131,7 @@
795
796
797 @login_required
798-@never_cache
799+@handle_nova_error
800 def download_credentials(request, project_id):
801 project = get_project_or_404(request, project_id)
802
803
804=== modified file 'src/django_nova/views/securitygroups.py'
805--- src/django_nova/views/securitygroups.py 2011-01-12 20:02:06 +0000
806+++ src/django_nova/views/securitygroups.py 2011-01-15 09:31:13 +0000
807@@ -25,14 +25,14 @@
808 from django.contrib import messages
809 from django.contrib.auth.decorators import login_required
810 from django.shortcuts import redirect, render_to_response
811-from django.views.decorators.cache import never_cache
812 from django_nova import exceptions
813 from django_nova import forms
814+from django_nova.exceptions import handle_nova_error
815 from django_nova.shortcuts import get_project_or_404
816
817
818 @login_required
819-@never_cache
820+@handle_nova_error
821 def index(request, project_id):
822 project = get_project_or_404(request, project_id)
823 securitygroups = project.get_security_groups()
824@@ -46,7 +46,7 @@
825
826
827 @login_required
828-@never_cache
829+@handle_nova_error
830 def detail(request, project_id, group_name):
831 project = get_project_or_404(request, project_id)
832 securitygroup = project.get_security_group(group_name)
833@@ -62,7 +62,7 @@
834
835
836 @login_required
837-@never_cache
838+@handle_nova_error
839 def add(request, project_id):
840 project = get_project_or_404(request, project_id)
841
842@@ -95,7 +95,7 @@
843
844
845 @login_required
846-@never_cache
847+@handle_nova_error
848 def authorize(request, project_id, group_name):
849 project = get_project_or_404(request, project_id)
850
851@@ -137,7 +137,7 @@
852
853
854 @login_required
855-@never_cache
856+@handle_nova_error
857 def revoke(request, project_id, group_name):
858 project = get_project_or_404(request, project_id)
859
860@@ -164,7 +164,7 @@
861
862
863 @login_required
864-@never_cache
865+@handle_nova_error
866 def delete(request, project_id, group_name):
867 project = get_project_or_404(request, project_id)
868

Subscribers

People subscribed via source and target branches

to all changes:
to status/vote changes: