1 from plstackapi.core.models import Site
2 from plstackapi.core.models import *
3 from plstackapi.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
15 class ReadonlyTabularInline(admin.TabularInline):
20 def get_readonly_fields(self, request, obj=None):
22 for field in self.model._meta.get_all_field_names():
23 if (not field == 'id'):
24 if (field not in self.editable_fields):
28 def has_add_permission(self, request):
31 class SliverInline(admin.TabularInline):
33 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
35 #readonly_fields = ['ip', 'instance_name', 'image']
36 readonly_fields = ['ip', 'instance_name']
38 class SiteInline(admin.TabularInline):
42 class SliceInline(admin.TabularInline):
46 class UserInline(admin.TabularInline):
50 class RoleInline(admin.TabularInline):
54 class NodeInline(admin.TabularInline):
58 class PlainTextWidget(forms.HiddenInput):
61 def render(self, name, value, attrs=None):
64 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
66 class PlanetStackBaseAdmin(admin.ModelAdmin):
69 class OSModelAdmin(PlanetStackBaseAdmin):
70 """Attach client connection to openstack on delete() and save()"""
72 def save_model(self, request, obj, form, change):
74 auth = request.session.get('auth', {})
75 auth['tenant'] = request.user.site.login_base
76 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
79 def delete_model(self, request, obj):
81 auth = request.session.get('auth', {})
82 auth['tenant'] = request.user.site.login_base
83 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
86 class RoleAdmin(OSModelAdmin):
88 ('Role', {'fields': ['role_type']})
90 list_display = ('role_type',)
93 class DeploymentNetworkAdminForm(forms.ModelForm):
94 sites = forms.ModelMultipleChoiceField(
95 queryset=Site.objects.all(),
97 widget=FilteredSelectMultiple(
98 verbose_name=('Sites'), is_stacked=False
102 model = DeploymentNetwork
104 def __init__(self, *args, **kwargs):
105 super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
107 if self.instance and self.instance.pk:
108 self.fields['sites'].initial = self.instance.sites.all()
110 def save(self, commit=True):
111 deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
113 deploymentNetwork.save()
115 if deploymentNetwork.pk:
116 deploymentNetwork.sites = self.cleaned_data['sites']
119 return deploymentNetwork
121 class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
122 form = DeploymentNetworkAdminForm
123 inlines = [NodeInline,]
125 def get_formsets(self, request, obj=None):
126 for inline in self.get_inline_instances(request, obj):
127 # hide MyInline in the add view
130 # give inline object access to driver and caller
131 auth = request.session.get('auth', {})
132 auth['tenant'] = request.user.site.login_base
133 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
134 yield inline.get_formset(request, obj)
136 class SiteAdmin(OSModelAdmin):
138 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
139 ('Location', {'fields': ['latitude', 'longitude']}),
140 ('Deployment Networks', {'fields': ['deployments']})
142 list_display = ('name', 'login_base','site_url', 'enabled')
143 filter_horizontal = ('deployments',)
144 inlines = [NodeInline,]
145 search_fields = ['name']
147 def get_formsets(self, request, obj=None):
148 for inline in self.get_inline_instances(request, obj):
149 # hide MyInline in the add view
152 # give inline object access to driver and caller
153 auth = request.session.get('auth', {})
154 auth['tenant'] = request.user.site.login_base
155 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
156 yield inline.get_formset(request, obj)
158 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
160 (None, {'fields': ['user', 'site', 'role']})
162 list_display = ('user', 'site', 'role')
164 def save_model(self, request, obj, form, change):
165 # update openstack connection to use this site/tenant
166 auth = request.session.get('auth', {})
167 auth['tenant'] = obj.site.login_base
168 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
171 def delete_model(self, request, obj):
172 # update openstack connection to use this site/tenant
173 auth = request.session.get('auth', {})
174 auth['tenant'] = obj.site.login_base
175 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
178 class KeyAdmin(OSModelAdmin):
180 ('Key', {'fields': ['key', 'type', 'blacklisted', 'user']})
182 list_display = ['key', 'type', 'blacklisted', 'user']
184 def get_queryset(self, request):
185 # get keys user is allowed to see
186 qs = super(KeyAdmin, self).get_queryset(request)
187 if request.user.is_superuser:
189 # users can only see their own keys
190 return qs.filter(user=request.user)
192 class SliceAdmin(OSModelAdmin):
193 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
194 list_display = ('name', 'site','serviceClass', 'slice_url')
195 inlines = [SliverInline]
197 def get_formsets(self, request, obj=None):
198 for inline in self.get_inline_instances(request, obj):
199 # hide MyInline in the add view
202 # give inline object access to driver and caller
203 auth = request.session.get('auth', {})
204 auth['tenant'] = obj.name # meed to connect using slice's tenant
205 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
206 yield inline.get_formset(request, obj)
208 def get_queryset(self, request):
209 qs = super(SliceAdmin, self).get_queryset(request)
210 if request.user.is_superuser:
212 # users can only see slices at their site
213 return qs.filter(site=request.user.site)
215 class SliceMembershipAdmin(PlanetStackBaseAdmin):
217 (None, {'fields': ['user', 'slice', 'role']})
219 list_display = ('user', 'slice', 'role')
221 def save_model(self, request, obj, form, change):
222 # update openstack connection to use this site/tenant
223 auth = request.session.get('auth', {})
224 auth['tenant'] = obj.slice.name
225 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
228 def delete_model(self, request, obj):
229 # update openstack connection to use this site/tenant
230 auth = request.session.get('auth', {})
231 auth['tenant'] = obj.slice.name
232 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
236 class ImageAdmin(admin.ModelAdmin):
237 fields = ['image_id', 'name', 'disk_format', 'container_format']
239 class NodeAdmin(admin.ModelAdmin):
240 list_display = ('name', 'site', 'deploymentNetwork')
241 list_filter = ('deploymentNetwork',)
244 class SliverForm(forms.ModelForm):
247 ip = forms.CharField(widget=PlainTextWidget)
248 instance_name = forms.CharField(widget=PlainTextWidget)
250 'ip': PlainTextWidget(),
251 'instance_name': PlainTextWidget(),
254 class SliverAdmin(PlanetStackBaseAdmin):
257 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
259 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
261 def get_formsets(self, request, obj=None):
262 # make some fields read only if we are updating an existing record
264 #self.readonly_fields = ('ip', 'instance_name')
265 self.readonly_fields = ()
267 self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
269 for inline in self.get_inline_instances(request, obj):
270 # hide MyInline in the add view
273 # give inline object access to driver and caller
274 auth = request.session.get('auth', {})
275 auth['tenant'] = obj.name # meed to connect using slice's tenant
276 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
277 yield inline.get_formset(request, obj)
279 def save_model(self, request, obj, form, change):
280 # update openstack connection to use this site/tenant
281 auth = request.session.get('auth', {})
282 auth['tenant'] = obj.slice.name
283 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
286 def delete_model(self, request, obj):
287 # update openstack connection to use this site/tenant
288 auth = request.session.get('auth', {})
289 auth['tenant'] = obj.slice.name
290 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
293 class UserCreationForm(forms.ModelForm):
294 """A form for creating new users. Includes all the required
295 fields, plus a repeated password."""
296 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
297 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
301 fields = ('email', 'firstname', 'lastname', 'phone', 'site')
303 def clean_password2(self):
304 # Check that the two password entries match
305 password1 = self.cleaned_data.get("password1")
306 password2 = self.cleaned_data.get("password2")
307 if password1 and password2 and password1 != password2:
308 raise forms.ValidationError("Passwords don't match")
311 def save(self, commit=True):
312 # Save the provided password in hashed format
313 user = super(UserCreationForm, self).save(commit=False)
314 user.password = self.cleaned_data["password1"]
315 #user.set_password(self.cleaned_data["password1"])
321 class UserChangeForm(forms.ModelForm):
322 """A form for updating users. Includes all the fields on
323 the user, but replaces the password field with admin's
324 password hash display field.
326 password = ReadOnlyPasswordHashField()
331 def clean_password(self):
332 # Regardless of what the user provides, return the initial value.
333 # This is done here, rather than on the field, because the
334 # field does not have access to the initial value
335 return self.initial["password"]
338 class PLUserAdmin(UserAdmin, OSModelAdmin):
342 # The forms to add and change user instances
343 form = UserChangeForm
344 add_form = UserCreationForm
346 # The fields to be used in displaying the User model.
347 # These override the definitions on the base UserAdmin
348 # that reference specific fields on auth.User.
349 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
350 list_filter = ('site',)
352 (None, {'fields': ('email', 'password')}),
353 ('Personal info', {'fields': ('firstname','lastname','phone', 'is_admin', 'site')}),
354 #('Important dates', {'fields': ('last_login',)}),
358 'classes': ('wide',),
359 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'is_admin', 'password1', 'password2')}
362 search_fields = ('email',)
363 ordering = ('email',)
364 filter_horizontal = ()
366 # register a signal that caches the user's credentials when they log in
367 def cache_credentials(sender, user, request, **kwds):
368 auth = {'username': request.POST['username'],
369 'password': request.POST['password']}
370 request.session['auth'] = auth
371 user_logged_in.connect(cache_credentials)
373 # Now register the new UserAdmin...
374 admin.site.register(PLUser, PLUserAdmin)
375 # ... and, since we're not using Django's builtin permissions,
376 # unregister the Group model from admin.
377 admin.site.unregister(Group)
379 admin.site.register(Site, SiteAdmin)
380 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
381 admin.site.register(Slice, SliceAdmin)
382 admin.site.register(SliceMembership, SliceMembershipAdmin)
383 admin.site.register(Node, NodeAdmin)
384 admin.site.register(Sliver, SliverAdmin)
385 admin.site.register(Key, KeyAdmin)
386 admin.site.register(Role, RoleAdmin)
387 admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)