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
92 def formfield_for_foreignkey(self, db_field, request, **kwargs):
93 if db_field.name == 'slice':
94 if not request.user.is_admin:
95 # only show slices at sites where caller has admin or pi role
96 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
97 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
98 sites = [site_privilege.site for site_privilege in site_privileges]
99 slices = Slice.objects.filter(site__in=sites)
100 kwargs['queryset'] = slices
101 if db_field.name == 'user':
102 if not request.user.is_admin:
103 # only show users from sites where caller has admin or pi role
104 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
105 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
106 sites = [site_privilege.site for site_privilege in site_privileges]
107 site_privileges = SitePrivilege.objects.filter(site__in=sites)
108 emails = [site_privilege.user.email for site_privilege in site_privileges]
109 users = User.objects.filter(email__in=emails)
110 kwargs['queryset'] = list(users)
112 return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
114 class SliceTagInline(admin.TabularInline):
118 class PlainTextWidget(forms.HiddenInput):
119 input_type = 'hidden'
121 def render(self, name, value, attrs=None):
124 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
126 class PlanetStackBaseAdmin(admin.ModelAdmin):
129 class OSModelAdmin(PlanetStackBaseAdmin):
130 """Attach client connection to openstack on delete() and save()"""
132 def save_model(self, request, obj, form, change):
133 if request.user.site:
134 auth = request.session.get('auth', {})
135 auth['tenant'] = request.user.site.login_base
136 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
139 def delete_model(self, request, obj):
140 if request.user.site:
141 auth = request.session.get('auth', {})
142 auth['tenant'] = request.user.site.login_base
143 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
146 class RoleAdmin(OSModelAdmin):
148 ('Role', {'fields': ['role_type']})
150 list_display = ('role_type',)
153 class DeploymentAdminForm(forms.ModelForm):
154 sites = forms.ModelMultipleChoiceField(
155 queryset=Site.objects.all(),
157 widget=FilteredSelectMultiple(
158 verbose_name=('Sites'), is_stacked=False
164 def __init__(self, *args, **kwargs):
165 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
167 if self.instance and self.instance.pk:
168 self.fields['sites'].initial = self.instance.sites.all()
170 def save(self, commit=True):
171 deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
173 deploymentNetwork.save()
175 if deploymentNetwork.pk:
176 deploymentNetwork.sites = self.cleaned_data['sites']
179 return deploymentNetwork
181 class DeploymentAdmin(PlanetStackBaseAdmin):
182 form = DeploymentAdminForm
183 inlines = [NodeInline,SliverInline]
185 def get_formsets(self, request, obj=None):
186 for inline in self.get_inline_instances(request, obj):
187 # hide MyInline in the add view
190 # give inline object access to driver and caller
191 auth = request.session.get('auth', {})
192 if request.user.site:
193 auth['tenant'] = request.user.site.login_base
194 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
195 yield inline.get_formset(request, obj)
197 class SiteAdmin(OSModelAdmin):
199 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
200 ('Location', {'fields': ['latitude', 'longitude']}),
201 ('Deployment Networks', {'fields': ['deployments']})
203 list_display = ('name', 'login_base','site_url', 'enabled')
204 filter_horizontal = ('deployments',)
205 inlines = [NodeInline, UserInline, SitePrivilegeInline]
206 search_fields = ['name']
208 def queryset(self, request):
209 # admins can see all keys. Users can only see sites they belong to.
210 qs = super(SiteAdmin, self).queryset(request)
211 if not request.user.is_admin:
212 valid_sites = [request.user.site.login_base]
213 roles = request.user.get_roles()
214 for tenant_list in roles.values():
215 valid_sites.extend(tenant_list)
216 qs = qs.filter(login_base__in=valid_sites)
219 def get_formsets(self, request, obj=None):
220 for inline in self.get_inline_instances(request, obj):
221 # hide MyInline in the add view
224 # give inline object access to driver and caller
225 auth = request.session.get('auth', {})
226 #auth['tenant'] = request.user.site.login_base
227 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
228 yield inline.get_formset(request, obj)
230 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
232 (None, {'fields': ['user', 'site', 'role']})
234 list_display = ('user', 'site', 'role')
236 def formfield_for_foreignkey(self, db_field, request, **kwargs):
237 if db_field.name == 'site':
238 if not request.user.is_admin:
239 # only show sites where user is an admin or pi
241 for site_privilege in SitePrivilege.objects.filer(user=request.user):
242 if site_privilege.role.role_type in ['admin', 'pi']:
243 sites.add(site_privilege.site)
244 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
246 if db_field.name == 'user':
247 if not request.user.is_admin:
248 # only show users from sites where caller has admin or pi role
249 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
250 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
251 sites = [site_privilege.site for site_privilege in site_privileges]
252 site_privileges = SitePrivilege.objects.filter(site__in=sites)
253 emails = [site_privilege.user.email for site_privilege in site_privileges]
254 users = User.objects.filter(email__in=emails)
255 kwargs['queryset'] = users
257 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
259 def queryset(self, request):
260 # admins can see all privileges. Users can only see privileges at sites
261 # where they have the admin role or pi role.
262 qs = super(SitePrivilegeAdmin, self).queryset(request)
263 if not request.user.is_admin:
264 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
265 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
266 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
267 sites = Site.objects.filter(login_base__in=login_bases)
268 qs = qs.filter(site__in=sites)
271 def save_model(self, request, obj, form, change):
272 # update openstack connection to use this site/tenant
273 auth = request.session.get('auth', {})
274 #auth['tenant'] = obj.site.login_base
275 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
278 def delete_model(self, request, obj):
279 # update openstack connection to use this site/tenant
280 auth = request.session.get('auth', {})
281 #auth['tenant'] = obj.site.login_base
282 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
285 class SliceAdmin(OSModelAdmin):
286 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
287 list_display = ('name', 'site','serviceClass', 'slice_url')
288 inlines = [SliverInline, SliceMembershipInline, SliceTagInline]
290 def formfield_for_foreignkey(self, db_field, request, **kwargs):
291 if db_field.name == 'site':
292 if not request.user.is_admin:
293 # only show sites where user is a pi or admin
294 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
295 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
296 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
297 sites = Site.objects.filter(login_base__in=login_bases)
298 kwargs['queryset'] = sites
300 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
302 def queryset(self, request):
303 # admins can see all keys. Users can only see slices they belong to.
304 qs = super(SliceAdmin, self).queryset(request)
305 if not request.user.is_admin:
307 roles = request.user.get_roles()
308 for tenant_list in roles.values():
309 valid_slices.extend(tenant_list)
310 qs = qs.filter(name__in=valid_slices)
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 # give inline object access to driver and caller
319 auth = request.session.get('auth', {})
320 auth['tenant'] = obj.name # meed to connect using slice's tenant
321 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
322 inline.model.creator = request.user
323 yield inline.get_formset(request, obj)
325 def get_queryset(self, request):
326 qs = super(SliceAdmin, self).get_queryset(request)
327 if request.user.is_superuser:
329 # users can only see slices at their site
330 return qs.filter(site=request.user.site)
332 class SliceMembershipAdmin(PlanetStackBaseAdmin):
334 (None, {'fields': ['user', 'slice', 'role']})
336 list_display = ('user', 'slice', 'role')
338 def formfield_for_foreignkey(self, db_field, request, **kwargs):
339 if db_field.name == 'slice':
340 if not request.user.is_admin:
341 # only show slices at sites where caller has admin or pi role
342 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
343 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
344 sites = [site_privilege.site for site_privilege in site_privileges]
345 slices = Slice.objects.filter(site__in=sites)
346 kwargs['queryset'] = slices
348 if db_field.name == 'user':
349 if not request.user.is_admin:
350 # only show users from sites where caller has admin or pi role
351 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
352 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
353 sites = [site_privilege.site for site_privilege in site_privileges]
354 site_privileges = SitePrivilege.objects.filter(site__in=sites)
355 emails = [site_privilege.user.email for site_privilege in site_privileges]
356 users = User.objects.filter(email__in=emails)
357 kwargs['queryset'] = users
359 return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
361 def queryset(self, request):
362 # admins can see all memberships. Users can only see memberships of
363 # slices where they have the admin role.
364 qs = super(SliceMembershipAdmin, self).queryset(request)
365 if not request.user.is_admin:
366 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
367 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
368 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
369 sites = Site.objects.filter(login_base__in=login_bases)
370 slices = Slice.objects.filter(site__in=sites)
371 qs = qs.filter(slice__in=slices)
374 def save_model(self, request, obj, form, change):
375 # update openstack connection to use this site/tenant
376 auth = request.session.get('auth', {})
377 auth['tenant'] = obj.slice.name
378 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
381 def delete_model(self, request, obj):
382 # update openstack connection to use this site/tenant
383 auth = request.session.get('auth', {})
384 auth['tenant'] = obj.slice.name
385 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
389 class ImageAdmin(admin.ModelAdmin):
390 fields = ['image_id', 'name', 'disk_format', 'container_format']
392 class NodeAdmin(admin.ModelAdmin):
393 list_display = ('name', 'site', 'deployment')
394 list_filter = ('deployment',)
397 class SliverForm(forms.ModelForm):
400 ip = forms.CharField(widget=PlainTextWidget)
401 instance_name = forms.CharField(widget=PlainTextWidget)
403 'ip': PlainTextWidget(),
404 'instance_name': PlainTextWidget(),
407 class SliverAdmin(PlanetStackBaseAdmin):
410 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
412 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
414 def formfield_for_foreignkey(self, db_field, request, **kwargs):
415 if db_field.name == 'slice':
416 if not request.user.is_admin:
417 slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)])
418 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
420 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
422 def queryset(self, request):
423 # admins can see all slivers. Users can only see slivers of
424 # the slices they belong to.
425 qs = super(SliverAdmin, self).queryset(request)
426 if not request.user.is_admin:
428 roles = request.user.get_roles()
429 for tenant_list in roles.values():
430 tenants.extend(tenant_list)
431 valid_slices = Slice.objects.filter(name__in=tenants)
432 qs = qs.filter(slice__in=valid_slices)
435 def get_formsets(self, request, obj=None):
436 # make some fields read only if we are updating an existing record
438 #self.readonly_fields = ('ip', 'instance_name')
439 self.readonly_fields = ()
441 self.readonly_fields = ()
442 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
444 for inline in self.get_inline_instances(request, obj):
445 # hide MyInline in the add view
448 # give inline object access to driver and caller
449 auth = request.session.get('auth', {})
450 auth['tenant'] = obj.name # meed to connect using slice's tenant
451 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
452 yield inline.get_formset(request, obj)
454 def save_model(self, request, obj, form, change):
455 # update openstack connection to use this site/tenant
456 auth = request.session.get('auth', {})
457 auth['tenant'] = obj.slice.name
458 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
459 obj.creator = request.user
462 def delete_model(self, request, obj):
463 # update openstack connection to use this site/tenant
464 auth = request.session.get('auth', {})
465 auth['tenant'] = obj.slice.name
466 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
469 class UserCreationForm(forms.ModelForm):
470 """A form for creating new users. Includes all the required
471 fields, plus a repeated password."""
472 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
473 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
477 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site')
479 def clean_password2(self):
480 # Check that the two password entries match
481 password1 = self.cleaned_data.get("password1")
482 password2 = self.cleaned_data.get("password2")
483 if password1 and password2 and password1 != password2:
484 raise forms.ValidationError("Passwords don't match")
487 def save(self, commit=True):
488 # Save the provided password in hashed format
489 user = super(UserCreationForm, self).save(commit=False)
490 user.password = self.cleaned_data["password1"]
491 #user.set_password(self.cleaned_data["password1"])
497 class UserChangeForm(forms.ModelForm):
498 """A form for updating users. Includes all the fields on
499 the user, but replaces the password field with admin's
500 password hash display field.
502 password = ReadOnlyPasswordHashField()
507 def clean_password(self):
508 # Regardless of what the user provides, return the initial value.
509 # This is done here, rather than on the field, because the
510 # field does not have access to the initial value
511 return self.initial["password"]
514 class UserAdmin(UserAdmin, OSModelAdmin):
518 # The forms to add and change user instances
519 form = UserChangeForm
520 add_form = UserCreationForm
522 # The fields to be used in displaying the User model.
523 # These override the definitions on the base UserAdmin
524 # that reference specific fields on auth.User.
525 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
526 list_filter = ('site',)
527 inlines = [SitePrivilegeInline, SliceMembershipInline]
529 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
530 ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}),
531 #('Important dates', {'fields': ('last_login',)}),
535 'classes': ('wide',),
536 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')}
539 search_fields = ('email',)
540 ordering = ('email',)
541 filter_horizontal = ()
543 def formfield_for_foreignkey(self, db_field, request, **kwargs):
544 if db_field.name == 'site':
545 if not request.user.is_admin:
546 # show sites where caller is an admin or pi
548 for site_privilege in SitePrivilege.objects.filer(user=request.user):
549 if site_privilege.role.role_type in ['admin', 'pi']:
550 sites.append(site_privilege.site.login_base)
551 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
553 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
555 class ServiceResourceInline(admin.TabularInline):
556 model = ServiceResource
559 class ServiceClassAdmin(admin.ModelAdmin):
560 list_display = ('name', 'commitment', 'membershipFee')
561 inlines = [ServiceResourceInline]
563 class ReservedResourceInline(admin.TabularInline):
564 model = ReservedResource
567 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
568 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
570 if db_field.name == 'resource':
571 # restrict resources to those that the slice's service class allows
572 if request._slice is not None:
573 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
574 if len(field.queryset) > 0:
575 field.initial = field.queryset.all()[0]
577 field.queryset = field.queryset.none()
\r
578 elif db_field.name == 'sliver':
\r
579 # restrict slivers to those that belong to the slice
\r
580 if request._slice is not None:
\r
581 field.queryset = field.queryset.filter(slice = request._slice)
583 field.queryset = field.queryset.none()
\r
587 class ReservationChangeForm(forms.ModelForm):
591 class ReservationAddForm(forms.ModelForm):
592 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
593 refresh = forms.CharField(widget=forms.HiddenInput())
596 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
598 def clean_slice(self):
599 slice = self.cleaned_data.get("slice")
600 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
602 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
608 class ReservationAddRefreshForm(ReservationAddForm):
609 """ This form is displayed when the Reservation Form receives an update
610 from the Slice dropdown onChange handler. It doesn't validate the
611 data and doesn't save the data. This will cause the form to be
615 """ don't validate anything other than slice """
616 dont_validate_fields = ("startTime", "duration")
618 def full_clean(self):
619 result = super(ReservationAddForm, self).full_clean()
621 for fieldname in self.dont_validate_fields:
622 if fieldname in self._errors:
623 del self._errors[fieldname]
627 """ don't save anything """
631 class ReservationAdmin(admin.ModelAdmin):
632 list_display = ('startTime', 'duration')
633 inlines = [ReservedResourceInline]
634 form = ReservationAddForm
636 def add_view(self, request, form_url='', extra_context=None):
637 timezone.activate(request.user.timezone)
638 request._refresh = False
639 request._slice = None
640 if request.method == 'POST':
641 # "refresh" will be set to "1" if the form was submitted due to
642 # a change in the Slice dropdown.
643 if request.POST.get("refresh","1") == "1":
644 request._refresh = True
645 request.POST["refresh"] = "0"
647 # Keep track of the slice that was selected, so the
648 # reservedResource inline can filter items for the slice.
649 request._slice = request.POST.get("slice",None)
650 if (request._slice is not None):
651 request._slice = Slice.objects.get(id=request._slice)
653 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
656 def changelist_view(self, request, extra_context = None):
657 timezone.activate(request.user.timezone)
658 return super(ReservationAdmin, self).changelist_view(request, extra_context)
660 def get_form(self, request, obj=None, **kwargs):
661 request._obj_ = obj
\r
662 if obj is not None:
\r
663 # For changes, set request._slice to the slice already set in the
\r
665 request._slice = obj.slice
\r
666 self.form = ReservationChangeForm
\r
668 if getattr(request, "_refresh", False):
\r
669 self.form = ReservationAddRefreshForm
\r
671 self.form = ReservationAddForm
\r
672 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
\r
674 def get_readonly_fields(self, request, obj=None):
675 if (obj is not None):
\r
676 # Prevent slice from being changed after the reservation has been
\r
682 # register a signal that caches the user's credentials when they log in
683 def cache_credentials(sender, user, request, **kwds):
684 auth = {'username': request.POST['username'],
685 'password': request.POST['password']}
686 request.session['auth'] = auth
687 user_logged_in.connect(cache_credentials)
689 # Now register the new UserAdmin...
690 admin.site.register(User, UserAdmin)
691 # ... and, since we're not using Django's builtin permissions,
692 # unregister the Group model from admin.
693 admin.site.unregister(Group)
695 #Do not show django evolution in the admin interface
696 from django_evolution.models import Version, Evolution
697 admin.site.unregister(Version)
698 admin.site.unregister(Evolution)
701 # When debugging it is often easier to see all the classes, but for regular use
702 # only the top-levels should be displayed
705 admin.site.register(Deployment, DeploymentAdmin)
706 admin.site.register(Site, SiteAdmin)
707 admin.site.register(Slice, SliceAdmin)
708 #admin.site.register(Subnet)
712 admin.site.register(Node, NodeAdmin)
713 admin.site.register(SliceMembership, SliceMembershipAdmin)
714 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
715 admin.site.register(Role, RoleAdmin)
716 admin.site.register(Sliver, SliverAdmin)
717 admin.site.register(ServiceClass, ServiceClassAdmin)
718 admin.site.register(Reservation, ReservationAdmin)
719 admin.site.register(Image, ImageAdmin)