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
16 import django_evolution
18 class ReadonlyTabularInline(admin.TabularInline):
23 def get_readonly_fields(self, request, obj=None):
25 for field in self.model._meta.get_all_field_names():
26 if (not field == 'id'):
27 if (field not in self.editable_fields):
31 def has_add_permission(self, request):
34 class TagInline(generic.GenericTabularInline):
39 class SliverInline(admin.TabularInline):
41 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
43 #readonly_fields = ['ip', 'instance_name', 'image']
44 readonly_fields = ['ip', 'instance_name']
47 class SiteInline(admin.TabularInline):
51 class UserInline(admin.TabularInline):
53 fields = ['email', 'firstname', 'lastname']
56 class SliceInline(admin.TabularInline):
60 class RoleInline(admin.TabularInline):
64 class NodeInline(admin.TabularInline):
68 class SitePrivilegeInline(admin.TabularInline):
72 def formfield_for_foreignkey(self, db_field, request, **kwargs):
73 if db_field.name == 'site':
74 if not request.user.is_admin:
75 # only show sites where user is an admin or pi
76 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
77 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
78 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
79 sites = Site.objects.filter(login_base__in=login_bases)
80 kwargs['queryset'] = sites
82 if db_field.name == 'user':
83 if not request.user.is_admin:
84 # only show users from sites where caller has admin or pi role
85 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
86 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
87 sites = [site_privilege.site for site_privilege in site_privileges]
88 site_privileges = SitePrivilege.objects.filter(site__in=sites)
89 emails = [site_privilege.user.email for site_privilege in site_privileges]
90 users = User.objects.filter(email__in=emails)
91 kwargs['queryset'] = users
92 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
94 class SliceMembershipInline(admin.TabularInline):
95 model = SliceMembership
97 fields = ('user', 'role')
99 def formfield_for_foreignkey(self, db_field, request, **kwargs):
100 if db_field.name == 'slice':
101 if not request.user.is_admin:
102 # only show slices at sites where caller has admin or pi role
103 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
104 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
105 sites = [site_privilege.site for site_privilege in site_privileges]
106 slices = Slice.objects.filter(site__in=sites)
107 kwargs['queryset'] = slices
108 if db_field.name == 'user':
109 if not request.user.is_admin:
110 # only show users from sites where caller has admin or pi role
111 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
112 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
113 sites = [site_privilege.site for site_privilege in site_privileges]
114 site_privileges = SitePrivilege.objects.filter(site__in=sites)
115 emails = [site_privilege.user.email for site_privilege in site_privileges]
116 users = User.objects.filter(email__in=emails)
117 kwargs['queryset'] = list(users)
119 return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
121 class SliceTagInline(admin.TabularInline):
125 class PlainTextWidget(forms.HiddenInput):
126 input_type = 'hidden'
128 def render(self, name, value, attrs=None):
131 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
133 class PlanetStackBaseAdmin(admin.ModelAdmin):
136 class RoleAdmin(PlanetStackBaseAdmin):
138 ('Role', {'fields': ['role_type']})
140 list_display = ('role_type',)
143 class DeploymentAdminForm(forms.ModelForm):
144 sites = forms.ModelMultipleChoiceField(
145 queryset=Site.objects.all(),
147 widget=FilteredSelectMultiple(
148 verbose_name=('Sites'), is_stacked=False
154 def __init__(self, *args, **kwargs):
155 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
157 if self.instance and self.instance.pk:
158 self.fields['sites'].initial = self.instance.sites.all()
160 def save(self, commit=True):
161 deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
163 deploymentNetwork.save()
165 if deploymentNetwork.pk:
166 deploymentNetwork.sites = self.cleaned_data['sites']
169 return deploymentNetwork
171 class DeploymentAdmin(PlanetStackBaseAdmin):
172 form = DeploymentAdminForm
173 inlines = [NodeInline,SliverInline]
175 def get_formsets(self, request, obj=None):
176 for inline in self.get_inline_instances(request, obj):
177 # hide MyInline in the add view
180 # give inline object access to driver and caller
181 auth = request.session.get('auth', {})
182 if request.user.site:
183 auth['tenant'] = request.user.site.login_base
184 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
185 yield inline.get_formset(request, obj)
187 class SiteAdmin(PlanetStackBaseAdmin):
189 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
190 ('Location', {'fields': ['latitude', 'longitude']}),
191 ('Deployment Networks', {'fields': ['deployments']})
193 list_display = ('name', 'login_base','site_url', 'enabled')
194 filter_horizontal = ('deployments',)
195 inlines = [TagInline, NodeInline, UserInline, SitePrivilegeInline]
196 search_fields = ['name']
198 def queryset(self, request):
199 # admins can see all keys. Users can only see sites they belong to.
200 qs = super(SiteAdmin, self).queryset(request)
201 if not request.user.is_admin:
202 valid_sites = [request.user.site.login_base]
203 roles = request.user.get_roles()
204 for tenant_list in roles.values():
205 valid_sites.extend(tenant_list)
206 qs = qs.filter(login_base__in=valid_sites)
209 def get_formsets(self, request, obj=None):
210 for inline in self.get_inline_instances(request, obj):
211 # hide MyInline in the add view
214 if isinstance(inline, SliceInline):
215 inline.model.caller = request.user
216 yield inline.get_formset(request, obj)
218 def get_formsets(self, request, obj=None):
219 for inline in self.get_inline_instances(request, obj):
220 # hide MyInline in the add view
223 if isinstance(inline, SliverInline):
224 inline.model.caller = request.user
225 yield inline.get_formset(request, obj)
227 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
229 (None, {'fields': ['user', 'site', 'role']})
231 list_display = ('user', 'site', 'role')
233 def formfield_for_foreignkey(self, db_field, request, **kwargs):
234 if db_field.name == 'site':
235 if not request.user.is_admin:
236 # only show sites where user is an admin or pi
238 for site_privilege in SitePrivilege.objects.filer(user=request.user):
239 if site_privilege.role.role_type in ['admin', 'pi']:
240 sites.add(site_privilege.site)
241 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
243 if db_field.name == 'user':
244 if not request.user.is_admin:
245 # only show users from sites where caller has admin or pi role
246 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
247 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
248 sites = [site_privilege.site for site_privilege in site_privileges]
249 site_privileges = SitePrivilege.objects.filter(site__in=sites)
250 emails = [site_privilege.user.email for site_privilege in site_privileges]
251 users = User.objects.filter(email__in=emails)
252 kwargs['queryset'] = users
254 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
256 def queryset(self, request):
257 # admins can see all privileges. Users can only see privileges at sites
258 # where they have the admin role or pi role.
259 qs = super(SitePrivilegeAdmin, self).queryset(request)
260 if not request.user.is_admin:
261 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
262 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
263 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
264 sites = Site.objects.filter(login_base__in=login_bases)
265 qs = qs.filter(site__in=sites)
268 class SliceAdmin(PlanetStackBaseAdmin):
269 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
270 list_display = ('name', 'site','serviceClass', 'slice_url')
271 inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline]
273 def formfield_for_foreignkey(self, db_field, request, **kwargs):
274 if db_field.name == 'site':
275 if not request.user.is_admin:
276 # only show sites where user is a pi or admin
277 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
278 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
279 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
280 sites = Site.objects.filter(login_base__in=login_bases)
281 kwargs['queryset'] = sites
283 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
285 def queryset(self, request):
286 # admins can see all keys. Users can only see slices they belong to.
287 qs = super(SliceAdmin, self).queryset(request)
288 if not request.user.is_admin:
290 roles = request.user.get_roles()
291 for tenant_list in roles.values():
292 valid_slices.extend(tenant_list)
293 qs = qs.filter(name__in=valid_slices)
296 def get_formsets(self, request, obj=None):
297 for inline in self.get_inline_instances(request, obj):
298 # hide MyInline in the add view
301 if isinstance(inline, SliverInline):
302 inline.model.caller = request.user
303 yield inline.get_formset(request, obj)
305 def get_queryset(self, request):
306 qs = super(SliceAdmin, self).get_queryset(request)
307 if request.user.is_superuser:
309 # users can only see slices at their site
310 return qs.filter(site=request.user.site)
312 def save_model(self, request, obj, form, change):
313 # update openstack connection to use this site/tenant
314 obj.caller = request.user
317 class SliceMembershipAdmin(PlanetStackBaseAdmin):
319 (None, {'fields': ['user', 'slice', 'role']})
321 list_display = ('user', 'slice', 'role')
323 def formfield_for_foreignkey(self, db_field, request, **kwargs):
324 if db_field.name == 'slice':
325 if not request.user.is_admin:
326 # only show slices at sites where caller has admin or pi role
327 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
328 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
329 sites = [site_privilege.site for site_privilege in site_privileges]
330 slices = Slice.objects.filter(site__in=sites)
331 kwargs['queryset'] = slices
333 if db_field.name == 'user':
334 if not request.user.is_admin:
335 # only show users from sites where caller has admin or pi role
336 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
337 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
338 sites = [site_privilege.site for site_privilege in site_privileges]
339 site_privileges = SitePrivilege.objects.filter(site__in=sites)
340 emails = [site_privilege.user.email for site_privilege in site_privileges]
341 users = User.objects.filter(email__in=emails)
342 kwargs['queryset'] = users
344 return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
346 def queryset(self, request):
347 # admins can see all memberships. Users can only see memberships of
348 # slices where they have the admin role.
349 qs = super(SliceMembershipAdmin, self).queryset(request)
350 if not request.user.is_admin:
351 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
352 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
353 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
354 sites = Site.objects.filter(login_base__in=login_bases)
355 slices = Slice.objects.filter(site__in=sites)
356 qs = qs.filter(slice__in=slices)
359 def save_model(self, request, obj, form, change):
360 # update openstack connection to use this site/tenant
361 auth = request.session.get('auth', {})
362 auth['tenant'] = obj.slice.name
363 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
366 def delete_model(self, request, obj):
367 # update openstack connection to use this site/tenant
368 auth = request.session.get('auth', {})
369 auth['tenant'] = obj.slice.name
370 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
374 class ImageAdmin(admin.ModelAdmin):
375 fields = ['image_id', 'name', 'disk_format', 'container_format']
377 class NodeAdmin(admin.ModelAdmin):
378 list_display = ('name', 'site', 'deployment')
379 list_filter = ('deployment',)
380 inlines = [TagInline]
383 class SliverForm(forms.ModelForm):
386 ip = forms.CharField(widget=PlainTextWidget)
387 instance_name = forms.CharField(widget=PlainTextWidget)
389 'ip': PlainTextWidget(),
390 'instance_name': PlainTextWidget(),
393 class SliverAdmin(PlanetStackBaseAdmin):
396 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
398 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
399 inlines = [TagInline]
401 def formfield_for_foreignkey(self, db_field, request, **kwargs):
402 if db_field.name == 'slice':
403 if not request.user.is_admin:
404 slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)])
405 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
407 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
409 def queryset(self, request):
410 # admins can see all slivers. Users can only see slivers of
411 # the slices they belong to.
412 qs = super(SliverAdmin, self).queryset(request)
413 if not request.user.is_admin:
415 roles = request.user.get_roles()
416 for tenant_list in roles.values():
417 tenants.extend(tenant_list)
418 valid_slices = Slice.objects.filter(name__in=tenants)
419 qs = qs.filter(slice__in=valid_slices)
422 def get_formsets(self, request, obj=None):
423 # make some fields read only if we are updating an existing record
425 #self.readonly_fields = ('ip', 'instance_name')
426 self.readonly_fields = ()
428 self.readonly_fields = ()
429 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
431 for inline in self.get_inline_instances(request, obj):
432 # hide MyInline in the add view
435 # give inline object access to driver and caller
436 auth = request.session.get('auth', {})
437 auth['tenant'] = obj.name # meed to connect using slice's tenant
438 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
439 yield inline.get_formset(request, obj)
441 def save_model(self, request, obj, form, change):
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)
446 obj.creator = request.user
449 def delete_model(self, request, obj):
450 # update openstack connection to use this site/tenant
451 auth = request.session.get('auth', {})
452 auth['tenant'] = obj.slice.name
453 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
456 class UserCreationForm(forms.ModelForm):
457 """A form for creating new users. Includes all the required
458 fields, plus a repeated password."""
459 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
460 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
464 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site')
466 def clean_password2(self):
467 # Check that the two password entries match
468 password1 = self.cleaned_data.get("password1")
469 password2 = self.cleaned_data.get("password2")
470 if password1 and password2 and password1 != password2:
471 raise forms.ValidationError("Passwords don't match")
474 def save(self, commit=True):
475 # Save the provided password in hashed format
476 user = super(UserCreationForm, self).save(commit=False)
477 user.password = self.cleaned_data["password1"]
478 #user.set_password(self.cleaned_data["password1"])
484 class UserChangeForm(forms.ModelForm):
485 """A form for updating users. Includes all the fields on
486 the user, but replaces the password field with admin's
487 password hash display field.
489 password = ReadOnlyPasswordHashField()
494 def clean_password(self):
495 # Regardless of what the user provides, return the initial value.
496 # This is done here, rather than on the field, because the
497 # field does not have access to the initial value
498 return self.initial["password"]
501 class UserAdmin(UserAdmin):
505 # The forms to add and change user instances
506 form = UserChangeForm
507 add_form = UserCreationForm
509 # The fields to be used in displaying the User model.
510 # These override the definitions on the base UserAdmin
511 # that reference specific fields on auth.User.
512 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
513 list_filter = ('site',)
514 inlines = [SitePrivilegeInline, SliceMembershipInline]
516 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
517 ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}),
518 #('Important dates', {'fields': ('last_login',)}),
522 'classes': ('wide',),
523 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')}
526 search_fields = ('email',)
527 ordering = ('email',)
528 filter_horizontal = ()
530 def formfield_for_foreignkey(self, db_field, request, **kwargs):
531 if db_field.name == 'site':
532 if not request.user.is_admin:
533 # show sites where caller is an admin or pi
535 for site_privilege in SitePrivilege.objects.filer(user=request.user):
536 if site_privilege.role.role_type in ['admin', 'pi']:
537 sites.append(site_privilege.site.login_base)
538 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
540 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
542 class ServiceResourceInline(admin.TabularInline):
543 model = ServiceResource
546 class ServiceClassAdmin(admin.ModelAdmin):
547 list_display = ('name', 'commitment', 'membershipFee')
548 inlines = [ServiceResourceInline]
550 class ReservedResourceInline(admin.TabularInline):
551 model = ReservedResource
554 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
555 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
557 if db_field.name == 'resource':
558 # restrict resources to those that the slice's service class allows
559 if request._slice is not None:
560 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
561 if len(field.queryset) > 0:
562 field.initial = field.queryset.all()[0]
564 field.queryset = field.queryset.none()
\r
565 elif db_field.name == 'sliver':
\r
566 # restrict slivers to those that belong to the slice
\r
567 if request._slice is not None:
\r
568 field.queryset = field.queryset.filter(slice = request._slice)
570 field.queryset = field.queryset.none()
\r
574 class ReservationChangeForm(forms.ModelForm):
578 class ReservationAddForm(forms.ModelForm):
579 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
580 refresh = forms.CharField(widget=forms.HiddenInput())
583 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
585 def clean_slice(self):
586 slice = self.cleaned_data.get("slice")
587 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
589 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
595 class ReservationAddRefreshForm(ReservationAddForm):
596 """ This form is displayed when the Reservation Form receives an update
597 from the Slice dropdown onChange handler. It doesn't validate the
598 data and doesn't save the data. This will cause the form to be
602 """ don't validate anything other than slice """
603 dont_validate_fields = ("startTime", "duration")
605 def full_clean(self):
606 result = super(ReservationAddForm, self).full_clean()
608 for fieldname in self.dont_validate_fields:
609 if fieldname in self._errors:
610 del self._errors[fieldname]
614 """ don't save anything """
618 class ReservationAdmin(admin.ModelAdmin):
619 list_display = ('startTime', 'duration')
620 inlines = [ReservedResourceInline]
621 form = ReservationAddForm
623 def add_view(self, request, form_url='', extra_context=None):
624 timezone.activate(request.user.timezone)
625 request._refresh = False
626 request._slice = None
627 if request.method == 'POST':
628 # "refresh" will be set to "1" if the form was submitted due to
629 # a change in the Slice dropdown.
630 if request.POST.get("refresh","1") == "1":
631 request._refresh = True
632 request.POST["refresh"] = "0"
634 # Keep track of the slice that was selected, so the
635 # reservedResource inline can filter items for the slice.
636 request._slice = request.POST.get("slice",None)
637 if (request._slice is not None):
638 request._slice = Slice.objects.get(id=request._slice)
640 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
643 def changelist_view(self, request, extra_context = None):
644 timezone.activate(request.user.timezone)
645 return super(ReservationAdmin, self).changelist_view(request, extra_context)
647 def get_form(self, request, obj=None, **kwargs):
648 request._obj_ = obj
\r
649 if obj is not None:
\r
650 # For changes, set request._slice to the slice already set in the
\r
652 request._slice = obj.slice
\r
653 self.form = ReservationChangeForm
\r
655 if getattr(request, "_refresh", False):
\r
656 self.form = ReservationAddRefreshForm
\r
658 self.form = ReservationAddForm
\r
659 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
\r
661 def get_readonly_fields(self, request, obj=None):
662 if (obj is not None):
\r
663 # Prevent slice from being changed after the reservation has been
\r
669 # register a signal that caches the user's credentials when they log in
670 def cache_credentials(sender, user, request, **kwds):
671 auth = {'username': request.POST['username'],
672 'password': request.POST['password']}
673 request.session['auth'] = auth
674 user_logged_in.connect(cache_credentials)
676 # Now register the new UserAdmin...
677 admin.site.register(User, UserAdmin)
678 # ... and, since we're not using Django's builtin permissions,
679 # unregister the Group model from admin.
680 admin.site.unregister(Group)
682 #Do not show django evolution in the admin interface
683 from django_evolution.models import Version, Evolution
684 admin.site.unregister(Version)
685 admin.site.unregister(Evolution)
688 # When debugging it is often easier to see all the classes, but for regular use
689 # only the top-levels should be displayed
692 admin.site.register(Deployment, DeploymentAdmin)
693 admin.site.register(Site, SiteAdmin)
694 admin.site.register(Slice, SliceAdmin)
697 admin.site.register(Tag)
698 admin.site.register(Node, NodeAdmin)
699 admin.site.register(SliceMembership, SliceMembershipAdmin)
700 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
701 admin.site.register(Role, RoleAdmin)
702 admin.site.register(Sliver, SliverAdmin)
703 admin.site.register(ServiceClass, ServiceClassAdmin)
704 admin.site.register(Reservation, ReservationAdmin)
705 admin.site.register(Image, ImageAdmin)