1 from core.models import Site
2 from core.models import *
3 from openstack.manager import OpenStackManager
5 from django.contrib import admin
6 from django.contrib.auth.models import Group
7 from django import forms
8 from django.utils.safestring import mark_safe
9 from django.contrib.auth.admin import UserAdmin
10 from django.contrib.admin.widgets import FilteredSelectMultiple
11 from django.contrib.auth.forms import ReadOnlyPasswordHashField
12 from django.contrib.auth.signals import user_logged_in
13 from django.utils import timezone
14 from django.contrib.contenttypes import generic
15 from django.core.urlresolvers import reverse
16 from suit.widgets import LinkedSelect
18 import django_evolution
20 class SingletonAdmin (admin.ModelAdmin):
21 def has_add_permission(self, request):
22 num_objects = self.model.objects.count()
29 class PlStackTabularInline(admin.TabularInline):
32 class ReservationInline(PlStackTabularInline):
35 suit_classes = 'suit-tab suit-tab-reservations'
38 class ReadonlyTabularInline(PlStackTabularInline):
43 def get_readonly_fields(self, request, obj=None):
45 for field in self.model._meta.get_all_field_names():
46 if (not field == 'id'):
47 if (field not in self.editable_fields):
51 def has_add_permission(self, request):
54 class TagInline(generic.GenericTabularInline):
57 suit_classes = 'suit-tab suit-tab-tags'
59 class NetworkLookerUpper:
60 """ This is a callable that looks up a network name in a sliver and returns
61 the ip address for that network.
64 def __init__(self, name):
65 self.short_description = name
67 self.network_name = name
69 def __call__(self, obj):
71 for nbs in obj.networksliver_set.all():
72 if (nbs.network.name == self.network_name):
77 return self.network_name
79 class SliverInline(PlStackTabularInline):
81 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
83 readonly_fields = ['ip', 'instance_name']
84 suit_classes = 'suit-tab suit-tab-slivers'
86 # Note this is breaking in the admin.py when trying to use an inline to add a node/image
87 # def _declared_fieldsets(self):
88 # # Return None so django will call get_fieldsets and we can insert our
92 # def get_readonly_fields(self, request, obj=None):
93 # readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
95 # # Lookup the networks that are bound to the slivers, and add those
96 # # network names to the list of readonly fields.
98 # for sliver in obj.slivers.all():
99 # for nbs in sliver.networksliver_set.all():
101 # network_name = nbs.network.name
102 # if network_name not in [str(x) for x in readonly_fields]:
103 # readonly_fields.append(NetworkLookerUpper(network_name))
105 # return readonly_fields
107 # def get_fieldsets(self, request, obj=None):
108 # form = self.get_formset(request, obj).form
109 # # fields = the read/write files + the read-only fields
110 # fields = self.fields
111 # for fieldName in self.get_readonly_fields(request,obj):
112 # if not fieldName in fields:
113 # fields.append(fieldName)
115 # return [(None, {'fields': fields})]
119 class SiteInline(PlStackTabularInline):
122 suit_classes = 'suit-tab suit-tab-sites'
124 class UserInline(PlStackTabularInline):
126 fields = ['email', 'firstname', 'lastname']
128 suit_classes = 'suit-tab suit-tab-users'
130 class SliceInline(PlStackTabularInline):
132 fields = ['name','site', 'serviceClass', 'service']
134 suit_classes = 'suit-tab suit-tab-slices'
137 class RoleInline(PlStackTabularInline):
140 suit_classes = 'suit-tab suit-tab-roles'
142 class NodeInline(PlStackTabularInline):
145 suit_classes = 'suit-tab suit-tab-nodes'
147 class SlicePrivilegeInline(PlStackTabularInline):
148 model = SlicePrivilege
150 suit_classes = 'suit-tab suit-tab-sliceprivileges'
152 class DeploymentPrivilegeInline(PlStackTabularInline):
153 model = DeploymentPrivilege
155 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
157 class SitePrivilegeInline(PlStackTabularInline):
158 model = SitePrivilege
160 suit_classes = 'suit-tab suit-tab-siteprivileges'
162 def formfield_for_foreignkey(self, db_field, request, **kwargs):
163 if db_field.name == 'site':
164 if not request.user.is_admin:
165 # only show sites where user is an admin or pi
166 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
167 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
168 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
169 sites = Site.objects.filter(login_base__in=login_bases)
170 kwargs['queryset'] = sites
172 if db_field.name == 'user':
173 if not request.user.is_admin:
174 # only show users from sites where caller has admin or pi role
175 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
176 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
177 sites = [site_privilege.site for site_privilege in site_privileges]
178 site_privileges = SitePrivilege.objects.filter(site__in=sites)
179 emails = [site_privilege.user.email for site_privilege in site_privileges]
180 users = User.objects.filter(email__in=emails)
181 kwargs['queryset'] = users
182 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
184 class SitePrivilegeInline(PlStackTabularInline):
185 model = SitePrivilege
186 suit_classes = 'suit-tab suit-tab-siteprivileges'
188 fields = ('user', 'site','role')
190 class SlicePrivilegeInline(PlStackTabularInline):
191 model = SlicePrivilege
192 suit_classes = 'suit-tab suit-tab-sliceprivileges'
194 fields = ('user', 'slice','role')
196 def formfield_for_foreignkey(self, db_field, request, **kwargs):
197 if db_field.name == 'slice':
198 if not request.user.is_admin:
199 # only show slices at sites where caller has admin or pi role
200 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
201 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
202 sites = [site_privilege.site for site_privilege in site_privileges]
203 slices = Slice.objects.filter(site__in=sites)
204 kwargs['queryset'] = slices
205 if db_field.name == 'user':
206 if not request.user.is_admin:
207 # only show users from sites where caller has admin or pi role
208 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
209 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
210 sites = [site_privilege.site for site_privilege in site_privileges]
211 site_privileges = SitePrivilege.objects.filter(site__in=sites)
212 emails = [site_privilege.user.email for site_privilege in site_privileges]
213 users = User.objects.filter(email__in=emails)
214 kwargs['queryset'] = list(users)
216 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
218 class SliceNetworkInline(PlStackTabularInline):
219 model = Network.slices.through
221 verbose_name = "Network Connection"
222 verbose_name_plural = "Network Connections"
223 suit_classes = 'suit-tab suit-tab-slicenetworks'
225 class SliceTagInline(PlStackTabularInline):
229 class PlainTextWidget(forms.HiddenInput):
230 input_type = 'hidden'
232 def render(self, name, value, attrs=None):
235 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
237 class PlanetStackBaseAdmin(admin.ModelAdmin):
240 class SliceRoleAdmin(PlanetStackBaseAdmin):
244 class SiteRoleAdmin(PlanetStackBaseAdmin):
248 class DeploymentAdminForm(forms.ModelForm):
249 sites = forms.ModelMultipleChoiceField(
250 queryset=Site.objects.all(),
252 widget=FilteredSelectMultiple(
253 verbose_name=('Sites'), is_stacked=False
260 class DeploymentAdmin(PlanetStackBaseAdmin):
261 form = DeploymentAdminForm
262 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
264 (None, {'fields': ['sites'], 'classes':['suit-tab suit-tab-sites']}),]
265 suit_form_tabs =(('sites', 'Sites'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
267 class ServiceAttrAsTabInline(PlStackTabularInline):
268 model = ServiceAttribute
269 fields = ['name','value']
271 suit_classes = 'suit-tab suit-tab-serviceattrs'
273 class ServiceAttributeInline(PlStackTabularInline):
274 model = ServiceAttribute
275 fields = ['name','value']
278 class ServiceAdmin(PlanetStackBaseAdmin):
279 list_display = ("name","enabled")
280 fieldsets = [(None, {'fields': ['name','enabled','description']})]
281 inlines = [ServiceAttributeInline,]
283 class SiteAdmin(PlanetStackBaseAdmin):
285 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink', 'location'], 'classes':['suit-tab suit-tab-general']}),
286 ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
288 suit_form_tabs =(('general', 'Site Details'),
290 ('siteprivileges','Privileges'),
291 ('deployments','Deployments'),
296 readonly_fields = ['accountLink']
297 list_display = ('name', 'login_base','site_url', 'enabled')
298 filter_horizontal = ('deployments',)
299 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline]
300 search_fields = ['name']
302 def queryset(self, request):
303 # admins can see all keys. Users can only see sites they belong to.
304 qs = super(SiteAdmin, self).queryset(request)
305 if not request.user.is_admin:
306 valid_sites = [request.user.site.login_base]
307 roles = request.user.get_roles()
308 for tenant_list in roles.values():
309 valid_sites.extend(tenant_list)
310 qs = qs.filter(login_base__in=valid_sites)
313 def get_formsets(self, request, obj=None):
314 for inline in self.get_inline_instances(request, obj):
315 # hide MyInline in the add view
318 if isinstance(inline, SliceInline):
319 inline.model.caller = request.user
320 yield inline.get_formset(request, obj)
322 def get_formsets(self, request, obj=None):
323 for inline in self.get_inline_instances(request, obj):
324 # hide MyInline in the add view
327 if isinstance(inline, SliverInline):
328 inline.model.caller = request.user
329 yield inline.get_formset(request, obj)
331 def accountLink(self, obj):
332 link_obj = obj.accounts.all()
334 reverse_path = "admin:core_account_change"
335 url = reverse(reverse_path, args =(link_obj[0].id,))
336 return "<a href='%s'>%s</a>" % (url, "view billing details")
338 return "no billing data for this site"
339 accountLink.allow_tags = True
340 accountLink.short_description = "Billing"
342 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
344 (None, {'fields': ['user', 'site', 'role'], 'classes':['collapse']})
346 list_display = ('user', 'site', 'role')
348 def formfield_for_foreignkey(self, db_field, request, **kwargs):
349 if db_field.name == 'site':
350 if not request.user.is_admin:
351 # only show sites where user is an admin or pi
353 for site_privilege in SitePrivilege.objects.filer(user=request.user):
354 if site_privilege.role.role_type in ['admin', 'pi']:
355 sites.add(site_privilege.site)
356 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
358 if db_field.name == 'user':
359 if not request.user.is_admin:
360 # only show users from sites where caller has admin or pi role
361 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
362 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
363 sites = [site_privilege.site for site_privilege in site_privileges]
364 site_privileges = SitePrivilege.objects.filter(site__in=sites)
365 emails = [site_privilege.user.email for site_privilege in site_privileges]
366 users = User.objects.filter(email__in=emails)
367 kwargs['queryset'] = users
369 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
371 def queryset(self, request):
372 # admins can see all privileges. Users can only see privileges at sites
373 # where they have the admin role or pi role.
374 qs = super(SitePrivilegeAdmin, self).queryset(request)
375 if not request.user.is_admin:
376 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
377 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
378 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
379 sites = Site.objects.filter(login_base__in=login_bases)
380 qs = qs.filter(site__in=sites)
383 class SliceForm(forms.ModelForm):
387 'service': LinkedSelect
390 class SliceAdmin(PlanetStackBaseAdmin):
392 fieldsets = [('Slice Details', {'fields': ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url'], 'classes':['suit-tab suit-tab-general']}),]
393 list_display = ('name', 'site','serviceClass', 'slice_url')
394 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
397 #inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline, SliceNetworkInline]
398 suit_form_tabs =(('general', 'Slice Details'),
399 ('slicenetworks','Networks'),
400 ('sliceprivileges','Privileges'),
401 ('slivers','Slivers'),
403 ('reservations','Reservations'),
406 def formfield_for_foreignkey(self, db_field, request, **kwargs):
407 if db_field.name == 'site':
408 if not request.user.is_admin:
409 # only show sites where user is a pi or admin
410 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
411 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
412 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
413 sites = Site.objects.filter(login_base__in=login_bases)
414 kwargs['queryset'] = sites
416 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
418 def queryset(self, request):
419 # admins can see all keys. Users can only see slices they belong to.
420 qs = super(SliceAdmin, self).queryset(request)
421 if not request.user.is_admin:
423 roles = request.user.get_roles()
424 for tenant_list in roles.values():
425 valid_slices.extend(tenant_list)
426 qs = qs.filter(name__in=valid_slices)
429 def get_formsets(self, request, obj=None):
430 for inline in self.get_inline_instances(request, obj):
431 # hide MyInline in the add view
434 if isinstance(inline, SliverInline):
435 inline.model.caller = request.user
436 yield inline.get_formset(request, obj)
438 def get_queryset(self, request):
439 qs = super(SliceAdmin, self).get_queryset(request)
440 if request.user.is_superuser:
442 # users can only see slices at their site
443 return qs.filter(site=request.user.site)
445 def save_model(self, request, obj, form, change):
446 # update openstack connection to use this site/tenant
447 obj.caller = request.user
450 class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
452 (None, {'fields': ['user', 'slice', 'role']})
454 list_display = ('user', 'slice', 'role')
456 def formfield_for_foreignkey(self, db_field, request, **kwargs):
457 if db_field.name == 'slice':
458 if not request.user.is_admin:
459 # only show slices at sites where caller has admin or pi role
460 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
461 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
462 sites = [site_privilege.site for site_privilege in site_privileges]
463 slices = Slice.objects.filter(site__in=sites)
464 kwargs['queryset'] = slices
466 if db_field.name == 'user':
467 if not request.user.is_admin:
468 # only show users from sites where caller has admin or pi role
469 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
470 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
471 sites = [site_privilege.site for site_privilege in site_privileges]
472 site_privileges = SitePrivilege.objects.filter(site__in=sites)
473 emails = [site_privilege.user.email for site_privilege in site_privileges]
474 users = User.objects.filter(email__in=emails)
475 kwargs['queryset'] = users
477 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
479 def queryset(self, request):
480 # admins can see all memberships. Users can only see memberships of
481 # slices where they have the admin role.
482 qs = super(SlicePrivilegeAdmin, self).queryset(request)
483 if not request.user.is_admin:
484 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
485 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
486 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
487 sites = Site.objects.filter(login_base__in=login_bases)
488 slices = Slice.objects.filter(site__in=sites)
489 qs = qs.filter(slice__in=slices)
492 def save_model(self, request, obj, form, change):
493 # update openstack connection to use this site/tenant
494 auth = request.session.get('auth', {})
495 auth['tenant'] = obj.slice.name
496 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
499 def delete_model(self, request, obj):
500 # update openstack connection to use this site/tenant
501 auth = request.session.get('auth', {})
502 auth['tenant'] = obj.slice.name
503 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
507 class ImageAdmin(PlanetStackBaseAdmin):
509 fieldsets = [('Image Details',
510 {'fields': ['image_id', 'name', 'disk_format', 'container_format'],
511 'classes': ['suit-tab suit-tab-general']})
514 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
516 inlines = [SliverInline]
518 class NodeForm(forms.ModelForm):
521 'site': LinkedSelect,
522 'deployment': LinkedSelect
525 class NodeAdmin(admin.ModelAdmin):
527 list_display = ('name', 'site', 'deployment')
528 list_filter = ('deployment',)
529 inlines = [TagInline,SliverInline]
530 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
532 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
535 class SliverForm(forms.ModelForm):
538 ip = forms.CharField(widget=PlainTextWidget)
539 instance_name = forms.CharField(widget=PlainTextWidget)
541 'ip': PlainTextWidget(),
542 'instance_name': PlainTextWidget(),
543 'slice': LinkedSelect,
544 'deploymentNetwork': LinkedSelect,
545 'node': LinkedSelect,
546 'image': LinkedSelect
549 class TagAdmin(admin.ModelAdmin):
550 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
552 class SliverAdmin(PlanetStackBaseAdmin):
555 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
557 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
559 suit_form_tabs =(('general', 'Sliver Details'),
563 inlines = [TagInline]
565 def formfield_for_foreignkey(self, db_field, request, **kwargs):
566 if db_field.name == 'slice':
567 if not request.user.is_admin:
568 slices = set([sm.slice.name for sm in SlicePrivilege.objects.filter(user=request.user)])
569 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
571 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
573 def queryset(self, request):
574 # admins can see all slivers. Users can only see slivers of
575 # the slices they belong to.
576 qs = super(SliverAdmin, self).queryset(request)
577 if not request.user.is_admin:
579 roles = request.user.get_roles()
580 for tenant_list in roles.values():
581 tenants.extend(tenant_list)
582 valid_slices = Slice.objects.filter(name__in=tenants)
583 qs = qs.filter(slice__in=valid_slices)
586 def get_formsets(self, request, obj=None):
587 # make some fields read only if we are updating an existing record
589 #self.readonly_fields = ('ip', 'instance_name')
590 self.readonly_fields = ()
592 self.readonly_fields = ()
593 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
595 for inline in self.get_inline_instances(request, obj):
596 # hide MyInline in the add view
599 # give inline object access to driver and caller
600 auth = request.session.get('auth', {})
601 auth['tenant'] = obj.name # meed to connect using slice's tenant
602 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
603 yield inline.get_formset(request, obj)
605 def save_model(self, request, obj, form, change):
606 # update openstack connection to use this site/tenant
607 auth = request.session.get('auth', {})
608 auth['tenant'] = obj.slice.name
609 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
610 obj.creator = request.user
613 def delete_model(self, request, obj):
614 # update openstack connection to use this site/tenant
615 auth = request.session.get('auth', {})
616 auth['tenant'] = obj.slice.name
617 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
620 class UserCreationForm(forms.ModelForm):
621 """A form for creating new users. Includes all the required
622 fields, plus a repeated password."""
623 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
624 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
628 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
630 def clean_password2(self):
631 # Check that the two password entries match
632 password1 = self.cleaned_data.get("password1")
633 password2 = self.cleaned_data.get("password2")
634 if password1 and password2 and password1 != password2:
635 raise forms.ValidationError("Passwords don't match")
638 def save(self, commit=True):
639 # Save the provided password in hashed format
640 user = super(UserCreationForm, self).save(commit=False)
641 user.password = self.cleaned_data["password1"]
642 #user.set_password(self.cleaned_data["password1"])
648 class UserChangeForm(forms.ModelForm):
649 """A form for updating users. Includes all the fields on
650 the user, but replaces the password field with admin's
651 password hash display field.
653 password = ReadOnlyPasswordHashField()
658 def clean_password(self):
659 # Regardless of what the user provides, return the initial value.
660 # This is done here, rather than on the field, because the
661 # field does not have access to the initial value
662 return self.initial["password"]
665 class UserAdmin(UserAdmin):
669 # The forms to add and change user instances
670 form = UserChangeForm
671 add_form = UserCreationForm
673 # The fields to be used in displaying the User model.
674 # These override the definitions on the base UserAdmin
675 # that reference specific fields on auth.User.
676 list_display = ('email', 'firstname', 'lastname', 'is_admin', 'last_login')
677 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
679 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
681 ('Login Details', {'fields': ('email', 'site','password', 'is_admin', 'public_key'), 'classes':['suit-tab suit-tab-general']}),
682 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
683 #('Important dates', {'fields': ('last_login',)}),
687 'classes': ('wide',),
688 'fields': ('email', 'firstname', 'lastname', 'phone', 'public_key','password1', 'password2')}
691 search_fields = ('email',)
692 ordering = ('email',)
693 filter_horizontal = ()
695 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
697 def formfield_for_foreignkey(self, db_field, request, **kwargs):
698 if db_field.name == 'site':
699 if not request.user.is_admin:
700 # show sites where caller is an admin or pi
702 for site_privilege in SitePrivilege.objects.filer(user=request.user):
703 if site_privilege.role.role_type in ['admin', 'pi']:
704 sites.append(site_privilege.site.login_base)
705 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
707 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
709 class ServiceResourceInline(admin.TabularInline):
710 model = ServiceResource
713 class ServiceClassAdmin(admin.ModelAdmin):
714 list_display = ('name', 'commitment', 'membershipFee')
715 inlines = [ServiceResourceInline]
717 class ReservedResourceInline(admin.TabularInline):
718 model = ReservedResource
720 suit_classes = 'suit-tab suit-tab-reservedresources'
722 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
723 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
725 if db_field.name == 'resource':
726 # restrict resources to those that the slice's service class allows
727 if request._slice is not None:
728 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
729 if len(field.queryset) > 0:
730 field.initial = field.queryset.all()[0]
732 field.queryset = field.queryset.none()
\r
733 elif db_field.name == 'sliver':
\r
734 # restrict slivers to those that belong to the slice
\r
735 if request._slice is not None:
\r
736 field.queryset = field.queryset.filter(slice = request._slice)
738 field.queryset = field.queryset.none()
\r
742 class ReservationChangeForm(forms.ModelForm):
746 'slice' : LinkedSelect
749 class ReservationAddForm(forms.ModelForm):
750 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
751 refresh = forms.CharField(widget=forms.HiddenInput())
754 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
756 def clean_slice(self):
757 slice = self.cleaned_data.get("slice")
758 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
760 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
766 'slice' : LinkedSelect
770 class ReservationAddRefreshForm(ReservationAddForm):
771 """ This form is displayed when the Reservation Form receives an update
772 from the Slice dropdown onChange handler. It doesn't validate the
773 data and doesn't save the data. This will cause the form to be
777 """ don't validate anything other than slice """
778 dont_validate_fields = ("startTime", "duration")
780 def full_clean(self):
781 result = super(ReservationAddForm, self).full_clean()
783 for fieldname in self.dont_validate_fields:
784 if fieldname in self._errors:
785 del self._errors[fieldname]
789 """ don't save anything """
793 class ReservationAdmin(admin.ModelAdmin):
794 fieldsets = [('Reservation Details', {'fields': ['slice', 'startTime', 'duration'], 'classes': ['suit-tab suit-tab-general']})]
795 list_display = ('startTime', 'duration')
796 form = ReservationAddForm
798 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
800 inlines = [ReservedResourceInline]
802 def add_view(self, request, form_url='', extra_context=None):
803 timezone.activate(request.user.timezone)
804 request._refresh = False
805 request._slice = None
806 if request.method == 'POST':
807 # "refresh" will be set to "1" if the form was submitted due to
808 # a change in the Slice dropdown.
809 if request.POST.get("refresh","1") == "1":
810 request._refresh = True
811 request.POST["refresh"] = "0"
813 # Keep track of the slice that was selected, so the
814 # reservedResource inline can filter items for the slice.
815 request._slice = request.POST.get("slice",None)
816 if (request._slice is not None):
817 request._slice = Slice.objects.get(id=request._slice)
819 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
822 def changelist_view(self, request, extra_context = None):
823 timezone.activate(request.user.timezone)
824 return super(ReservationAdmin, self).changelist_view(request, extra_context)
826 def get_form(self, request, obj=None, **kwargs):
829 # For changes, set request._slice to the slice already set in the
831 request._slice = obj.slice
832 self.form = ReservationChangeForm
834 if getattr(request, "_refresh", False):
835 self.form = ReservationAddRefreshForm
837 self.form = ReservationAddForm
838 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
840 def get_readonly_fields(self, request, obj=None):
841 if (obj is not None):
842 # Prevent slice from being changed after the reservation has been
848 class NetworkParameterTypeAdmin(admin.ModelAdmin):
849 list_display = ("name", )
851 class RouterAdmin(admin.ModelAdmin):
852 list_display = ("name", )
854 class RouterInline(admin.TabularInline):
855 model = Router.networks.through
857 verbose_name_plural = "Routers"
858 verbose_name = "Router"
859 suit_classes = 'suit-tab suit-tab-routers'
861 class NetworkParameterInline(generic.GenericTabularInline):
862 model = NetworkParameter
864 verbose_name_plural = "Parameters"
865 verbose_name = "Parameter"
866 suit_classes = 'suit-tab suit-tab-netparams'
868 class NetworkSliversInline(admin.TabularInline):
869 readonly_fields = ("ip", )
870 model = NetworkSliver
872 verbose_name_plural = "Slivers"
873 verbose_name = "Sliver"
874 suit_classes = 'suit-tab suit-tab-networkslivers'
876 class NetworkSlicesInline(admin.TabularInline):
879 verbose_name_plural = "Slices"
880 verbose_name = "Slice"
881 suit_classes = 'suit-tab suit-tab-networkslices'
883 class NetworkForm(forms.ModelForm):
886 'deployment': LinkedSelect,
887 'site': LinkedSelect,
890 class NetworkAdmin(admin.ModelAdmin):
892 list_display = ("name", "subnet", "ports", "labels")
893 list_filter = ('deployment', )
894 readonly_fields = ("subnet", )
896 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
899 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','site','deployment','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
902 ('general','Network Details'),
903 ('netparams', 'Parameters'),
904 ('networkslivers','Slivers'),
905 ('networkslices','Slices'),
906 ('routers','Routers'),
908 class NetworkTemplateAdmin(admin.ModelAdmin):
909 list_display = ("name", "guaranteedBandwidth", "visibility")
911 # register a signal that caches the user's credentials when they log in
912 def cache_credentials(sender, user, request, **kwds):
913 auth = {'username': request.POST['username'],
914 'password': request.POST['password']}
915 request.session['auth'] = auth
916 user_logged_in.connect(cache_credentials)
918 def dollar_field(fieldName, short_description):
919 def newFunc(self, obj):
921 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
923 x=getattr(obj, fieldName, 0.0)
925 newFunc.short_description = short_description
928 def right_dollar_field(fieldName, short_description):
929 def newFunc(self, obj):
931 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
932 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
934 x=getattr(obj, fieldName, 0.0)
936 newFunc.short_description = short_description
937 newFunc.allow_tags = True
940 class InvoiceChargeInline(admin.TabularInline):
943 verbose_name_plural = "Charges"
944 verbose_name = "Charge"
945 exclude = ['enacted', 'account']
946 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
947 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
951 dollar_amount = right_dollar_field("amount", "Amount")
953 class InvoiceAdmin(admin.ModelAdmin):
954 list_display = ("date", "account")
956 inlines = [InvoiceChargeInline]
958 fields = ["date", "account", "dollar_amount"]
959 readonly_fields = ["date", "account", "dollar_amount"]
961 dollar_amount = dollar_field("amount", "Amount")
963 class InvoiceInline(admin.TabularInline):
966 verbose_name_plural = "Invoices"
967 verbose_name = "Invoice"
968 exclude = ['enacted']
969 fields = ["date", "dollar_amount", "invoiceLink"]
970 readonly_fields = ["date", "dollar_amount", "invoiceLink"]
971 suit_classes = 'suit-tab suit-tab-accountinvoice'
975 dollar_amount = right_dollar_field("amount", "Amount")
977 def invoiceLink(self, obj):
978 reverse_path = "admin:core_invoice_change"
979 url = reverse(reverse_path, args =(obj.id,))
980 return "<a href='%s'>%s</a>" % (url, "details")
981 invoiceLink.allow_tags = True
982 invoiceLink.short_description = "Details"
984 class PendingChargeInline(admin.TabularInline):
987 verbose_name_plural = "Charges"
988 verbose_name = "Charge"
989 exclude = ['enacted', "invoice"]
990 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
991 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
992 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
996 def queryset(self, request):
997 qs = super(PendingChargeInline, self).queryset(request)
998 qs = qs.filter(state="pending")
1001 dollar_amount = right_dollar_field("amount", "Amount")
1003 class PaymentInline(admin.TabularInline):
1006 verbose_name_plural = "Payments"
1007 verbose_name = "Payment"
1008 exclude = ['enacted']
1009 fields = ["date", "dollar_amount"]
1010 readonly_fields = ["date", "dollar_amount"]
1011 suit_classes = 'suit-tab suit-tab-accountpayments'
1015 dollar_amount = right_dollar_field("amount", "Amount")
1018 class AccountAdmin(admin.ModelAdmin):
1019 list_display = ("site", "balance_due")
1021 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1024 (None, {'fields': ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']})] # ,'classes':['suit-tab suit-tab-general']}),]
1026 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
1029 ('general','Account Details'),
1030 ('accountinvoice', 'Invoices'),
1031 ('accountpayments', 'Payments'),
1032 ('accountpendingcharges','Pending Charges'),
1035 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1036 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1037 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1040 # Now register the new UserAdmin...
1041 admin.site.register(User, UserAdmin)
1042 # ... and, since we're not using Django's builtin permissions,
1043 # unregister the Group model from admin.
1044 #admin.site.unregister(Group)
1046 #Do not show django evolution in the admin interface
1047 from django_evolution.models import Version, Evolution
1048 admin.site.unregister(Version)
1049 admin.site.unregister(Evolution)
1052 # When debugging it is often easier to see all the classes, but for regular use
1053 # only the top-levels should be displayed
1056 admin.site.register(Account, AccountAdmin)
1057 admin.site.register(Invoice, InvoiceAdmin)
1059 admin.site.register(Deployment, DeploymentAdmin)
1060 admin.site.register(Site, SiteAdmin)
1061 admin.site.register(Slice, SliceAdmin)
1062 admin.site.register(ServiceClass, ServiceClassAdmin)
1063 admin.site.register(Service, ServiceAdmin)
1064 admin.site.register(Reservation, ReservationAdmin)
1065 admin.site.register(Network, NetworkAdmin)
1066 admin.site.register(Router, RouterAdmin)
1067 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1068 admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
1071 #admin.site.register(PlanetStack)
1072 admin.site.register(Tag, TagAdmin)
1073 admin.site.register(DeploymentRole)
1074 admin.site.register(SiteRole)
1075 admin.site.register(SliceRole)
1076 admin.site.register(PlanetStackRole)
1077 admin.site.register(Node, NodeAdmin)
1078 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1079 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
1080 admin.site.register(Sliver, SliverAdmin)
1081 admin.site.register(Image, ImageAdmin)