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 import django_evolution
17 class ReadonlyTabularInline(admin.TabularInline):
22 def get_readonly_fields(self, request, obj=None):
24 for field in self.model._meta.get_all_field_names():
25 if (not field == 'id'):
26 if (field not in self.editable_fields):
30 def has_add_permission(self, request):
33 class SliverInline(admin.TabularInline):
35 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
37 #readonly_fields = ['ip', 'instance_name', 'image']
38 readonly_fields = ['ip', 'instance_name']
41 class SiteInline(admin.TabularInline):
45 class UserInline(admin.TabularInline):
47 fields = ['email', 'firstname', 'lastname']
50 class SliceInline(admin.TabularInline):
54 class RoleInline(admin.TabularInline):
58 class NodeInline(admin.TabularInline):
62 class SitePrivilegeInline(admin.TabularInline):
66 def formfield_for_foreignkey(self, db_field, request, **kwargs):
67 if db_field.name == 'site':
68 if not request.user.is_admin:
69 # only show sites where user is an admin or pi
70 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
71 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
72 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
73 sites = Site.objects.filter(login_base__in=login_bases)
74 kwargs['queryset'] = sites
76 if db_field.name == 'user':
77 if not request.user.is_admin:
78 # only show users from sites where caller has admin or pi role
79 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
80 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
81 sites = [site_privilege.site for site_privilege in site_privileges]
82 site_privileges = SitePrivilege.objects.filter(site__in=sites)
83 emails = [site_privilege.user.email for site_privilege in site_privileges]
84 users = User.objects.filter(email__in=emails)
85 kwargs['queryset'] = users
86 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
88 class SliceMembershipInline(admin.TabularInline):
89 model = SliceMembership
91 fields = ('user', 'role')
93 def formfield_for_foreignkey(self, db_field, request, **kwargs):
94 if db_field.name == 'slice':
95 if not request.user.is_admin:
96 # only show slices at sites where caller has admin or pi role
97 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
98 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
99 sites = [site_privilege.site for site_privilege in site_privileges]
100 slices = Slice.objects.filter(site__in=sites)
101 kwargs['queryset'] = slices
102 if db_field.name == 'user':
103 if not request.user.is_admin:
104 # only show users from sites where caller has admin or pi role
105 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
106 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
107 sites = [site_privilege.site for site_privilege in site_privileges]
108 site_privileges = SitePrivilege.objects.filter(site__in=sites)
109 emails = [site_privilege.user.email for site_privilege in site_privileges]
110 users = User.objects.filter(email__in=emails)
111 kwargs['queryset'] = list(users)
113 return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
115 class SliceTagInline(admin.TabularInline):
119 class PlainTextWidget(forms.HiddenInput):
120 input_type = 'hidden'
122 def render(self, name, value, attrs=None):
125 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
127 class PlanetStackBaseAdmin(admin.ModelAdmin):
130 class RoleAdmin(PlanetStackBaseAdmin):
132 ('Role', {'fields': ['role_type']})
134 list_display = ('role_type',)
137 class DeploymentAdminForm(forms.ModelForm):
138 sites = forms.ModelMultipleChoiceField(
139 queryset=Site.objects.all(),
141 widget=FilteredSelectMultiple(
142 verbose_name=('Sites'), is_stacked=False
148 def __init__(self, *args, **kwargs):
149 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
151 if self.instance and self.instance.pk:
152 self.fields['sites'].initial = self.instance.sites.all()
154 def save(self, commit=True):
155 deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
157 deploymentNetwork.save()
159 if deploymentNetwork.pk:
160 deploymentNetwork.sites = self.cleaned_data['sites']
163 return deploymentNetwork
165 class DeploymentAdmin(PlanetStackBaseAdmin):
166 form = DeploymentAdminForm
167 inlines = [NodeInline,SliverInline]
169 def get_formsets(self, request, obj=None):
170 for inline in self.get_inline_instances(request, obj):
171 # hide MyInline in the add view
174 # give inline object access to driver and caller
175 auth = request.session.get('auth', {})
176 if request.user.site:
177 auth['tenant'] = request.user.site.login_base
178 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
179 yield inline.get_formset(request, obj)
181 class SiteAdmin(PlanetStackBaseAdmin):
183 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
184 ('Location', {'fields': ['latitude', 'longitude']}),
185 ('Deployment Networks', {'fields': ['deployments']})
187 list_display = ('name', 'login_base','site_url', 'enabled')
188 filter_horizontal = ('deployments',)
189 inlines = [NodeInline, UserInline, SitePrivilegeInline]
190 search_fields = ['name']
192 def queryset(self, request):
193 # admins can see all keys. Users can only see sites they belong to.
194 qs = super(SiteAdmin, self).queryset(request)
195 if not request.user.is_admin:
196 valid_sites = [request.user.site.login_base]
197 roles = request.user.get_roles()
198 for tenant_list in roles.values():
199 valid_sites.extend(tenant_list)
200 qs = qs.filter(login_base__in=valid_sites)
203 def get_formsets(self, request, obj=None):
204 for inline in self.get_inline_instances(request, obj):
205 # hide MyInline in the add view
208 if isinstance(inline, SliceInline):
209 inline.model.caller = request.user
210 yield inline.get_formset(request, obj)
212 def get_formsets(self, request, obj=None):
213 for inline in self.get_inline_instances(request, obj):
214 # hide MyInline in the add view
217 if isinstance(inline, SliverInline):
218 inline.model.caller = request.user
219 yield inline.get_formset(request, obj)
221 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
223 (None, {'fields': ['user', 'site', 'role']})
225 list_display = ('user', 'site', 'role')
227 def formfield_for_foreignkey(self, db_field, request, **kwargs):
228 if db_field.name == 'site':
229 if not request.user.is_admin:
230 # only show sites where user is an admin or pi
232 for site_privilege in SitePrivilege.objects.filer(user=request.user):
233 if site_privilege.role.role_type in ['admin', 'pi']:
234 sites.add(site_privilege.site)
235 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
237 if db_field.name == 'user':
238 if not request.user.is_admin:
239 # only show users from sites where caller has admin or pi role
240 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
241 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
242 sites = [site_privilege.site for site_privilege in site_privileges]
243 site_privileges = SitePrivilege.objects.filter(site__in=sites)
244 emails = [site_privilege.user.email for site_privilege in site_privileges]
245 users = User.objects.filter(email__in=emails)
246 kwargs['queryset'] = users
248 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
250 def queryset(self, request):
251 # admins can see all privileges. Users can only see privileges at sites
252 # where they have the admin role or pi role.
253 qs = super(SitePrivilegeAdmin, self).queryset(request)
254 if not request.user.is_admin:
255 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
256 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
257 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
258 sites = Site.objects.filter(login_base__in=login_bases)
259 qs = qs.filter(site__in=sites)
262 class SliceAdmin(PlanetStackBaseAdmin):
263 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
264 list_display = ('name', 'site','serviceClass', 'slice_url')
265 inlines = [SliverInline, SliceMembershipInline, SliceTagInline]
267 def formfield_for_foreignkey(self, db_field, request, **kwargs):
268 if db_field.name == 'site':
269 if not request.user.is_admin:
270 # only show sites where user is a pi or admin
271 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
272 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
273 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
274 sites = Site.objects.filter(login_base__in=login_bases)
275 kwargs['queryset'] = sites
277 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
279 def queryset(self, request):
280 # admins can see all keys. Users can only see slices they belong to.
281 qs = super(SliceAdmin, self).queryset(request)
282 if not request.user.is_admin:
284 roles = request.user.get_roles()
285 for tenant_list in roles.values():
286 valid_slices.extend(tenant_list)
287 qs = qs.filter(name__in=valid_slices)
290 def get_formsets(self, request, obj=None):
291 for inline in self.get_inline_instances(request, obj):
292 # hide MyInline in the add view
295 if isinstance(inline, SliverInline):
296 inline.model.caller = request.user
297 yield inline.get_formset(request, obj)
299 def get_queryset(self, request):
300 qs = super(SliceAdmin, self).get_queryset(request)
301 if request.user.is_superuser:
303 # users can only see slices at their site
304 return qs.filter(site=request.user.site)
306 def save_model(self, request, obj, form, change):
307 # update openstack connection to use this site/tenant
308 obj.caller = request.user
311 class SliceMembershipAdmin(PlanetStackBaseAdmin):
313 (None, {'fields': ['user', 'slice', 'role']})
315 list_display = ('user', 'slice', 'role')
317 def formfield_for_foreignkey(self, db_field, request, **kwargs):
318 if db_field.name == 'slice':
319 if not request.user.is_admin:
320 # only show slices at sites where caller has admin or pi role
321 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
322 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
323 sites = [site_privilege.site for site_privilege in site_privileges]
324 slices = Slice.objects.filter(site__in=sites)
325 kwargs['queryset'] = slices
327 if db_field.name == 'user':
328 if not request.user.is_admin:
329 # only show users from sites where caller has admin or pi role
330 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
331 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
332 sites = [site_privilege.site for site_privilege in site_privileges]
333 site_privileges = SitePrivilege.objects.filter(site__in=sites)
334 emails = [site_privilege.user.email for site_privilege in site_privileges]
335 users = User.objects.filter(email__in=emails)
336 kwargs['queryset'] = users
338 return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
340 def queryset(self, request):
341 # admins can see all memberships. Users can only see memberships of
342 # slices where they have the admin role.
343 qs = super(SliceMembershipAdmin, self).queryset(request)
344 if not request.user.is_admin:
345 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
346 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
347 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
348 sites = Site.objects.filter(login_base__in=login_bases)
349 slices = Slice.objects.filter(site__in=sites)
350 qs = qs.filter(slice__in=slices)
353 def save_model(self, request, obj, form, change):
354 # update openstack connection to use this site/tenant
355 auth = request.session.get('auth', {})
356 auth['tenant'] = obj.slice.name
357 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
360 def delete_model(self, request, obj):
361 # update openstack connection to use this site/tenant
362 auth = request.session.get('auth', {})
363 auth['tenant'] = obj.slice.name
364 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
368 class ImageAdmin(admin.ModelAdmin):
369 fields = ['image_id', 'name', 'disk_format', 'container_format']
371 class NodeAdmin(admin.ModelAdmin):
372 list_display = ('name', 'site', 'deployment')
373 list_filter = ('deployment',)
376 class SliverForm(forms.ModelForm):
379 ip = forms.CharField(widget=PlainTextWidget)
380 instance_name = forms.CharField(widget=PlainTextWidget)
382 'ip': PlainTextWidget(),
383 'instance_name': PlainTextWidget(),
386 class SliverAdmin(PlanetStackBaseAdmin):
389 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
391 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
393 def formfield_for_foreignkey(self, db_field, request, **kwargs):
394 if db_field.name == 'slice':
395 if not request.user.is_admin:
396 slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)])
397 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
399 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
401 def queryset(self, request):
402 # admins can see all slivers. Users can only see slivers of
403 # the slices they belong to.
404 qs = super(SliverAdmin, self).queryset(request)
405 if not request.user.is_admin:
407 roles = request.user.get_roles()
408 for tenant_list in roles.values():
409 tenants.extend(tenant_list)
410 valid_slices = Slice.objects.filter(name__in=tenants)
411 qs = qs.filter(slice__in=valid_slices)
414 def get_formsets(self, request, obj=None):
415 # make some fields read only if we are updating an existing record
417 #self.readonly_fields = ('ip', 'instance_name')
418 self.readonly_fields = ()
420 self.readonly_fields = ()
421 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
423 for inline in self.get_inline_instances(request, obj):
424 # hide MyInline in the add view
427 # give inline object access to driver and caller
428 auth = request.session.get('auth', {})
429 auth['tenant'] = obj.name # meed to connect using slice's tenant
430 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
431 yield inline.get_formset(request, obj)
433 def save_model(self, request, obj, form, change):
434 # update openstack connection to use this site/tenant
435 auth = request.session.get('auth', {})
436 auth['tenant'] = obj.slice.name
437 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
438 obj.creator = request.user
441 def delete_model(self, request, obj):
442 # update openstack connection to use this site/tenant
443 auth = request.session.get('auth', {})
444 auth['tenant'] = obj.slice.name
445 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
448 class UserCreationForm(forms.ModelForm):
449 """A form for creating new users. Includes all the required
450 fields, plus a repeated password."""
451 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
452 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
456 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site')
458 def clean_password2(self):
459 # Check that the two password entries match
460 password1 = self.cleaned_data.get("password1")
461 password2 = self.cleaned_data.get("password2")
462 if password1 and password2 and password1 != password2:
463 raise forms.ValidationError("Passwords don't match")
466 def save(self, commit=True):
467 # Save the provided password in hashed format
468 user = super(UserCreationForm, self).save(commit=False)
469 user.password = self.cleaned_data["password1"]
470 #user.set_password(self.cleaned_data["password1"])
476 class UserChangeForm(forms.ModelForm):
477 """A form for updating users. Includes all the fields on
478 the user, but replaces the password field with admin's
479 password hash display field.
481 password = ReadOnlyPasswordHashField()
486 def clean_password(self):
487 # Regardless of what the user provides, return the initial value.
488 # This is done here, rather than on the field, because the
489 # field does not have access to the initial value
490 return self.initial["password"]
493 class UserAdmin(UserAdmin):
497 # The forms to add and change user instances
498 form = UserChangeForm
499 add_form = UserCreationForm
501 # The fields to be used in displaying the User model.
502 # These override the definitions on the base UserAdmin
503 # that reference specific fields on auth.User.
504 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
505 list_filter = ('site',)
506 inlines = [SitePrivilegeInline, SliceMembershipInline]
508 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
509 ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}),
510 #('Important dates', {'fields': ('last_login',)}),
514 'classes': ('wide',),
515 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')}
518 search_fields = ('email',)
519 ordering = ('email',)
520 filter_horizontal = ()
522 def formfield_for_foreignkey(self, db_field, request, **kwargs):
523 if db_field.name == 'site':
524 if not request.user.is_admin:
525 # show sites where caller is an admin or pi
527 for site_privilege in SitePrivilege.objects.filer(user=request.user):
528 if site_privilege.role.role_type in ['admin', 'pi']:
529 sites.append(site_privilege.site.login_base)
530 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
532 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
534 class ServiceResourceInline(admin.TabularInline):
535 model = ServiceResource
538 class ServiceClassAdmin(admin.ModelAdmin):
539 list_display = ('name', 'commitment', 'membershipFee')
540 inlines = [ServiceResourceInline]
542 class ReservedResourceInline(admin.TabularInline):
543 model = ReservedResource
546 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
547 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
549 if db_field.name == 'resource':
550 # restrict resources to those that the slice's service class allows
551 if request._slice is not None:
552 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
553 if len(field.queryset) > 0:
554 field.initial = field.queryset.all()[0]
556 field.queryset = field.queryset.none()
\r
557 elif db_field.name == 'sliver':
\r
558 # restrict slivers to those that belong to the slice
\r
559 if request._slice is not None:
\r
560 field.queryset = field.queryset.filter(slice = request._slice)
562 field.queryset = field.queryset.none()
\r
566 class ReservationChangeForm(forms.ModelForm):
570 class ReservationAddForm(forms.ModelForm):
571 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
572 refresh = forms.CharField(widget=forms.HiddenInput())
575 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
577 def clean_slice(self):
578 slice = self.cleaned_data.get("slice")
579 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
581 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
587 class ReservationAddRefreshForm(ReservationAddForm):
588 """ This form is displayed when the Reservation Form receives an update
589 from the Slice dropdown onChange handler. It doesn't validate the
590 data and doesn't save the data. This will cause the form to be
594 """ don't validate anything other than slice """
595 dont_validate_fields = ("startTime", "duration")
597 def full_clean(self):
598 result = super(ReservationAddForm, self).full_clean()
600 for fieldname in self.dont_validate_fields:
601 if fieldname in self._errors:
602 del self._errors[fieldname]
606 """ don't save anything """
610 class ReservationAdmin(admin.ModelAdmin):
611 list_display = ('startTime', 'duration')
612 inlines = [ReservedResourceInline]
613 form = ReservationAddForm
615 def add_view(self, request, form_url='', extra_context=None):
616 timezone.activate(request.user.timezone)
617 request._refresh = False
618 request._slice = None
619 if request.method == 'POST':
620 # "refresh" will be set to "1" if the form was submitted due to
621 # a change in the Slice dropdown.
622 if request.POST.get("refresh","1") == "1":
623 request._refresh = True
624 request.POST["refresh"] = "0"
626 # Keep track of the slice that was selected, so the
627 # reservedResource inline can filter items for the slice.
628 request._slice = request.POST.get("slice",None)
629 if (request._slice is not None):
630 request._slice = Slice.objects.get(id=request._slice)
632 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
635 def changelist_view(self, request, extra_context = None):
636 timezone.activate(request.user.timezone)
637 return super(ReservationAdmin, self).changelist_view(request, extra_context)
639 def get_form(self, request, obj=None, **kwargs):
640 request._obj_ = obj
\r
641 if obj is not None:
\r
642 # For changes, set request._slice to the slice already set in the
\r
644 request._slice = obj.slice
\r
645 self.form = ReservationChangeForm
\r
647 if getattr(request, "_refresh", False):
\r
648 self.form = ReservationAddRefreshForm
\r
650 self.form = ReservationAddForm
\r
651 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
\r
653 def get_readonly_fields(self, request, obj=None):
654 if (obj is not None):
\r
655 # Prevent slice from being changed after the reservation has been
\r
661 # register a signal that caches the user's credentials when they log in
662 def cache_credentials(sender, user, request, **kwds):
663 auth = {'username': request.POST['username'],
664 'password': request.POST['password']}
665 request.session['auth'] = auth
666 user_logged_in.connect(cache_credentials)
668 # Now register the new UserAdmin...
669 admin.site.register(User, UserAdmin)
670 # ... and, since we're not using Django's builtin permissions,
671 # unregister the Group model from admin.
672 admin.site.unregister(Group)
674 #Do not show django evolution in the admin interface
675 from django_evolution.models import Version, Evolution
676 admin.site.unregister(Version)
677 admin.site.unregister(Evolution)
680 # When debugging it is often easier to see all the classes, but for regular use
681 # only the top-levels should be displayed
684 admin.site.register(Deployment, DeploymentAdmin)
685 admin.site.register(Site, SiteAdmin)
686 admin.site.register(Slice, SliceAdmin)
687 #admin.site.register(Subnet)
691 admin.site.register(Node, NodeAdmin)
692 admin.site.register(SliceMembership, SliceMembershipAdmin)
693 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
694 admin.site.register(Role, RoleAdmin)
695 admin.site.register(Sliver, SliverAdmin)
696 admin.site.register(ServiceClass, ServiceClassAdmin)
697 admin.site.register(Reservation, ReservationAdmin)
698 admin.site.register(Image, ImageAdmin)