1 from plstackapi.core.models import Site
2 from plstackapi.core.models import *
3 from plstackapi.openstack.driver import OpenStackDriver
4 from plstackapi.openstack.client import OpenStackClient
6 from django.contrib import admin
7 from django.contrib.auth.models import Group
8 from django import forms
9 from django.utils.safestring import mark_safe
10 from django.contrib.auth.admin import UserAdmin
11 from django.contrib.admin.widgets import FilteredSelectMultiple
12 from django.contrib.auth.forms import ReadOnlyPasswordHashField
13 from django.contrib.auth.signals import user_logged_in
16 class ReadonlyTabularInline(admin.TabularInline):
21 def get_readonly_fields(self, request, obj=None):
23 for field in self.model._meta.get_all_field_names():
24 if (not field == 'id'):
25 if (field not in self.editable_fields):
29 def has_add_permission(self, request):
32 class SliverInline(admin.TabularInline):
34 fields = ['ip', 'name', 'slice', 'image', 'key', 'node', 'deploymentNetwork']
37 class SiteInline(admin.TabularInline):
41 class SliceInline(admin.TabularInline):
45 class UserInline(admin.TabularInline):
49 class RoleInline(admin.TabularInline):
53 class NodeInline(admin.TabularInline):
57 class PlainTextWidget(forms.Widget):
58 def render(self, _name, value, attrs):
59 return mark_safe(value) if value is not None else ''
61 class PlanetStackBaseAdmin(admin.ModelAdmin):
64 class OSModelAdmin(PlanetStackBaseAdmin):
65 """Attach client connection to openstack on delete() and save()"""
67 def save_model(self, request, obj, form, change):
68 client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
69 obj.driver = OpenStackDriver(client=client)
70 obj.caller = request.user
73 def delete_model(self, request, obj):
74 client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
75 obj.driver = OpenStackDriver(client=client)
76 obj.caller = request.user
79 class RoleAdmin(OSModelAdmin):
81 ('Role', {'fields': ['role_type']})
83 list_display = ('role_type',)
85 class DeploymentNetworkAdminForm(forms.ModelForm):
86 sites = forms.ModelMultipleChoiceField(
87 queryset=Site.objects.all(),
89 widget=FilteredSelectMultiple(
90 verbose_name=('Sites'), is_stacked=False
94 model = DeploymentNetwork
96 def __init__(self, *args, **kwargs):
97 super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
99 if self.instance and self.instance.pk:
100 self.fields['sites'].initial = self.instance.sites.all()
102 def save(self, commit=True):
103 deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
105 deploymentNetwork.save()
107 if deploymentNetwork.pk:
108 deploymentNetwork.sites = self.cleaned_data['sites']
111 return deploymentNetwork
113 class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
114 form = DeploymentNetworkAdminForm
115 inlines = [NodeInline,]
117 def get_formsets(self, request, obj=None):
118 for inline in self.get_inline_instances(request, obj):
119 # hide MyInline in the add view
122 # give inline object access to driver and caller
123 client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
124 inline.model.driver = OpenStackDriver(client=client)
125 inline.model.caller = request.user
126 yield inline.get_formset(request, obj)
128 class SiteAdmin(OSModelAdmin):
130 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
131 ('Location', {'fields': ['latitude', 'longitude']}),
132 ('Deployment Networks', {'fields': ['deployments']})
134 list_display = ('name', 'login_base','site_url', 'enabled')
135 filter_horizontal = ('deployments',)
136 inlines = [NodeInline,]
137 search_fields = ['name']
139 def get_formsets(self, request, obj=None):
140 for inline in self.get_inline_instances(request, obj):
141 # hide MyInline in the add view
144 # give inline object access to driver and caller
145 client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
146 inline.model.driver = OpenStackDriver(client=client)
147 inline.model.caller = request.user
148 yield inline.get_formset(request, obj)
150 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
152 (None, {'fields': ['user', 'site', 'role']})
154 list_display = ('user', 'site', 'role')
156 def save_model(self, request, obj, form, change):
157 # update openstack connection to use this site/tenant
158 client = OpenStackClient(tenant=obj.site.login_base, **request.session.get('auth', {}))
159 obj.driver = OpenStackDriver(client=client)
160 obj.caller = request.user
163 def delete_model(self, request, obj):
164 # update openstack connection to use this site/tenant
165 client = OpenStackClient(tenant=obj.site.login_base, **request.session.get('auth', {}))
166 obj.driver = OpenStackDriver(client=client)
167 obj.caller = request.user
170 class KeyAdmin(OSModelAdmin):
172 ('Key', {'fields': ['name', 'key', 'type', 'blacklisted', 'user']})
174 list_display = ['name', 'key', 'type', 'blacklisted', 'user']
176 def get_queryset(self, request):
177 # get keys user is allowed to see
178 qs = super(KeyAdmin, self).get_queryset(request)
179 if request.user.is_superuser:
181 # users can only see their own keys
182 return qs.filter(user=request.user)
185 class SliceAdmin(OSModelAdmin):
186 fields = ['name', 'site', 'instantiation', 'description', 'slice_url']
187 list_display = ('name', 'site','slice_url', 'instantiation')
188 inlines = [SliverInline]
190 def get_formsets(self, request, obj=None):
191 for inline in self.get_inline_instances(request, obj):
192 # hide MyInline in the add view
195 # give inline object access to driver and caller
196 client = OpenStackClient(tenant=obj.name, **request.session.get('auth', {}))
197 inline.model.driver = OpenStackDriver(client=client)
198 inline.model.caller = request.user
199 yield inline.get_formset(request, obj)
201 def get_queryset(self, request):
202 qs = super(SliceAdmin, self).get_queryset(request)
203 if request.user.is_superuser:
205 # users can only see slices at their site
206 return qs.filter(site=request.user.site)
208 class SliceMembershipAdmin(PlanetStackBaseAdmin):
210 (None, {'fields': ['user', 'slice', 'role']})
212 list_display = ('user', 'slice', 'role')
214 def save_model(self, request, obj, form, change):
215 # update openstack connection to use this slice/tenant
216 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
217 obj.driver = OpenStackDriver(client=client)
218 obj.caller = request.user
221 def delete_model(self, request, obj):
222 # update openstack connection to use this slice/tenant
223 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
224 obj.driver = OpenStackDriver(client=client)
225 obj.caller = request.user
228 class SubnetAdmin(PlanetStackBaseAdmin):
229 fields = ['cidr', 'ip_version', 'start', 'end', 'slice']
230 list_display = ('slice','cidr', 'start', 'end', 'ip_version')
232 def save_model(self, request, obj, form, change):
233 # update openstack connection to use this subnet's slice/tenant
234 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
235 obj.driver = OpenStackDriver(client=client)
236 obj.caller = request.user
239 def delete_model(self, request, obj):
240 # update openstack connection to use this subnet's slice/tenant
241 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
242 obj.driver = OpenStackDriver(client=client)
243 obj.caller = request.user
246 class ImageAdmin(admin.ModelAdmin):
247 fields = ['image_id', 'name', 'disk_format', 'container_format']
249 class NodeAdmin(admin.ModelAdmin):
250 list_display = ('name', 'site', 'deploymentNetwork')
251 list_filter = ('deploymentNetwork',)
254 class SliverForm(forms.ModelForm):
256 ip = forms.CharField(widget=PlainTextWidget)
259 'ip': PlainTextWidget(),
262 class SliverAdmin(PlanetStackBaseAdmin):
265 ('Sliver', {'fields': ['ip', 'name', 'slice', 'image', 'key', 'node', 'deploymentNetwork']})
267 list_display = ['ip', 'name', 'slice', 'image', 'key', 'node', 'deploymentNetwork']
269 def save_model(self, request, obj, form, change):
270 # update openstack connection to use this sliver's slice/tenant
271 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
272 obj.driver = OpenStackDriver(client=client)
273 obj.caller = request.user
276 def delete_model(self, request, obj):
277 # update openstack connection to use this sliver's slice/tenant
278 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
279 obj.driver = OpenStackDriver(client=client)
280 obj.caller = request.user
284 class UserCreationForm(forms.ModelForm):
285 """A form for creating new users. Includes all the required
286 fields, plus a repeated password."""
287 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
288 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
292 fields = ('email', 'firstname', 'lastname', 'phone', 'site')
294 def clean_password2(self):
295 # Check that the two password entries match
296 password1 = self.cleaned_data.get("password1")
297 password2 = self.cleaned_data.get("password2")
298 if password1 and password2 and password1 != password2:
299 raise forms.ValidationError("Passwords don't match")
302 def save(self, commit=True):
303 # Save the provided password in hashed format
304 user = super(UserCreationForm, self).save(commit=False)
305 user.password = self.cleaned_data["password1"]
306 #user.set_password(self.cleaned_data["password1"])
312 class UserChangeForm(forms.ModelForm):
313 """A form for updating users. Includes all the fields on
314 the user, but replaces the password field with admin's
315 password hash display field.
317 password = ReadOnlyPasswordHashField()
322 def clean_password(self):
323 # Regardless of what the user provides, return the initial value.
324 # This is done here, rather than on the field, because the
325 # field does not have access to the initial value
326 return self.initial["password"]
329 class PLUserAdmin(UserAdmin, OSModelAdmin):
333 # The forms to add and change user instances
334 form = UserChangeForm
335 add_form = UserCreationForm
337 # The fields to be used in displaying the User model.
338 # These override the definitions on the base UserAdmin
339 # that reference specific fields on auth.User.
340 list_display = ('email', 'site', 'firstname', 'lastname', 'last_login')
341 list_filter = ('site',)
343 (None, {'fields': ('email', 'password')}),
344 ('Personal info', {'fields': ('firstname','lastname','phone','site')}),
345 #('Important dates', {'fields': ('last_login',)}),
349 'classes': ('wide',),
350 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'password1', 'password2')}
353 search_fields = ('email',)
354 ordering = ('email',)
355 filter_horizontal = ()
357 # register a signal that caches the user's credentials when they log in
358 def cache_credentials(sender, user, request, **kwds):
359 auth = {'username': request.POST['username'],
360 'password': request.POST['password']}
361 request.session['auth'] = auth
362 user_logged_in.connect(cache_credentials)
364 # Now register the new UserAdmin...
365 admin.site.register(PLUser, PLUserAdmin)
366 # ... and, since we're not using Django's builtin permissions,
367 # unregister the Group model from admin.
368 admin.site.unregister(Group)
370 admin.site.register(Site, SiteAdmin)
371 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
372 admin.site.register(Slice, SliceAdmin)
373 admin.site.register(SliceMembership, SliceMembershipAdmin)
374 admin.site.register(Subnet, SubnetAdmin)
375 admin.site.register(Image, ImageAdmin)
376 admin.site.register(Node, NodeAdmin)
377 admin.site.register(Sliver, SliverAdmin)
378 admin.site.register(Key, KeyAdmin)
379 admin.site.register(Role, RoleAdmin)
380 admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)