1 from plstackapi.core.models import Site
2 from plstackapi.core.models import *
3 from plstackapi.openstack.manager import OpenStackManager
4 from plstackapi.openstack.driver import OpenStackDriver
5 from plstackapi.openstack.client import OpenStackClient
7 from django.contrib import admin
8 from django.contrib.auth.models import Group
9 from django import forms
10 from django.utils.safestring import mark_safe
11 from django.contrib.auth.admin import UserAdmin
12 from django.contrib.admin.widgets import FilteredSelectMultiple
13 from django.contrib.auth.forms import ReadOnlyPasswordHashField
14 from django.contrib.auth.signals import user_logged_in
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', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
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.Widget):
59 def render(self, _name, value, attrs):
60 return mark_safe(value) if value is not None else ''
62 class PlanetStackBaseAdmin(admin.ModelAdmin):
65 class OSModelAdmin(PlanetStackBaseAdmin):
66 """Attach client connection to openstack on delete() and save()"""
68 def save_model(self, request, obj, form, change):
69 client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
70 obj.driver = OpenStackDriver(client=client)
71 obj.caller = request.user
74 def delete_model(self, request, obj):
75 client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
76 obj.driver = OpenStackDriver(client=client)
77 obj.caller = request.user
80 class RoleAdmin(PlanetStackBaseAdmin):
82 ('Role', {'fields': ['role_type']})
84 list_display = ('role_type',)
86 def save_model(self, request, obj, form, change):
87 auth = request.session.get('auth', {})
88 auth['tenant'] = request.user.site.login_base
89 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
92 def delete_model(self, request, obj):
93 auth = request.session.get('auth', {})
94 auth['tenant'] = request.user.site.login_base
95 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
98 class DeploymentNetworkAdminForm(forms.ModelForm):
99 sites = forms.ModelMultipleChoiceField(
100 queryset=Site.objects.all(),
102 widget=FilteredSelectMultiple(
103 verbose_name=('Sites'), is_stacked=False
107 model = DeploymentNetwork
109 def __init__(self, *args, **kwargs):
110 super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
112 if self.instance and self.instance.pk:
113 self.fields['sites'].initial = self.instance.sites.all()
115 def save(self, commit=True):
116 deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
118 deploymentNetwork.save()
120 if deploymentNetwork.pk:
121 deploymentNetwork.sites = self.cleaned_data['sites']
124 return deploymentNetwork
126 class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
127 form = DeploymentNetworkAdminForm
128 inlines = [NodeInline,]
130 def get_formsets(self, request, obj=None):
131 for inline in self.get_inline_instances(request, obj):
132 # hide MyInline in the add view
135 # give inline object access to driver and caller
136 client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
137 inline.model.driver = OpenStackDriver(client=client)
138 inline.model.caller = request.user
139 yield inline.get_formset(request, obj)
141 class SiteAdmin(OSModelAdmin):
143 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
144 ('Location', {'fields': ['latitude', 'longitude']}),
145 ('Deployment Networks', {'fields': ['deployments']})
147 list_display = ('name', 'login_base','site_url', 'enabled')
148 filter_horizontal = ('deployments',)
149 inlines = [NodeInline,]
150 search_fields = ['name']
152 def get_formsets(self, request, obj=None):
153 for inline in self.get_inline_instances(request, obj):
154 # hide MyInline in the add view
157 # give inline object access to driver and caller
158 client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
159 inline.model.driver = OpenStackDriver(client=client)
160 inline.model.caller = request.user
161 yield inline.get_formset(request, obj)
163 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
165 (None, {'fields': ['user', 'site', 'role']})
167 list_display = ('user', 'site', 'role')
169 def save_model(self, request, obj, form, change):
170 # update openstack connection to use this site/tenant
171 client = OpenStackClient(tenant=obj.site.login_base, **request.session.get('auth', {}))
172 obj.driver = OpenStackDriver(client=client)
173 obj.caller = request.user
176 def delete_model(self, request, obj):
177 # update openstack connection to use this site/tenant
178 client = OpenStackClient(tenant=obj.site.login_base, **request.session.get('auth', {}))
179 obj.driver = OpenStackDriver(client=client)
180 obj.caller = request.user
183 class KeyAdmin(OSModelAdmin):
185 ('Key', {'fields': ['name', 'key', 'type', 'blacklisted', 'user']})
187 list_display = ['name', 'key', 'type', 'blacklisted', 'user']
189 def get_queryset(self, request):
190 # get keys user is allowed to see
191 qs = super(KeyAdmin, self).get_queryset(request)
192 if request.user.is_superuser:
194 # users can only see their own keys
195 return qs.filter(user=request.user)
198 class SliceAdmin(OSModelAdmin):
199 fields = ['name', 'site', 'serviceClass', 'instantiation', 'description', 'slice_url']
200 list_display = ('name', 'site','serviceClass', 'slice_url', 'instantiation')
201 inlines = [SliverInline]
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 # give inline object access to driver and caller
209 client = OpenStackClient(tenant=obj.name, **request.session.get('auth', {}))
210 inline.model.driver = OpenStackDriver(client=client)
211 inline.model.caller = request.user
212 yield inline.get_formset(request, obj)
214 def get_queryset(self, request):
215 qs = super(SliceAdmin, self).get_queryset(request)
216 if request.user.is_superuser:
218 # users can only see slices at their site
219 return qs.filter(site=request.user.site)
221 class SliceMembershipAdmin(PlanetStackBaseAdmin):
223 (None, {'fields': ['user', 'slice', 'role']})
225 list_display = ('user', 'slice', 'role')
227 def save_model(self, request, obj, form, change):
228 # update openstack connection to use this slice/tenant
229 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
230 obj.driver = OpenStackDriver(client=client)
231 obj.caller = request.user
234 def delete_model(self, request, obj):
235 # update openstack connection to use this slice/tenant
236 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
237 obj.driver = OpenStackDriver(client=client)
238 obj.caller = request.user
241 class SubnetAdmin(PlanetStackBaseAdmin):
242 fields = ['cidr', 'ip_version', 'start', 'end', 'slice']
243 list_display = ('slice','cidr', 'start', 'end', 'ip_version')
245 def save_model(self, request, obj, form, change):
246 # update openstack connection to use this subnet's slice/tenant
247 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
248 obj.driver = OpenStackDriver(client=client)
249 obj.caller = request.user
252 def delete_model(self, request, obj):
253 # update openstack connection to use this subnet's slice/tenant
254 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
255 obj.driver = OpenStackDriver(client=client)
256 obj.caller = request.user
259 class ImageAdmin(admin.ModelAdmin):
260 fields = ['image_id', 'name', 'disk_format', 'container_format']
262 class NodeAdmin(admin.ModelAdmin):
263 list_display = ('name', 'site', 'deploymentNetwork')
264 list_filter = ('deploymentNetwork',)
267 class SliverForm(forms.ModelForm):
269 ip = forms.CharField(widget=PlainTextWidget)
272 'ip': PlainTextWidget(),
275 class SliverAdmin(PlanetStackBaseAdmin):
278 ('Sliver', {'fields': ['ip', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
280 list_display = ['ip', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
282 def save_model(self, request, obj, form, change):
283 # update openstack connection to use this sliver's slice/tenant
284 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
285 obj.driver = OpenStackDriver(client=client)
286 obj.caller = request.user
289 def delete_model(self, request, obj):
290 # update openstack connection to use this sliver's slice/tenant
291 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
292 obj.driver = OpenStackDriver(client=client)
293 obj.caller = request.user
297 class UserCreationForm(forms.ModelForm):
298 """A form for creating new users. Includes all the required
299 fields, plus a repeated password."""
300 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
301 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
305 fields = ('email', 'firstname', 'lastname', 'phone', 'site')
307 def clean_password2(self):
308 # Check that the two password entries match
309 password1 = self.cleaned_data.get("password1")
310 password2 = self.cleaned_data.get("password2")
311 if password1 and password2 and password1 != password2:
312 raise forms.ValidationError("Passwords don't match")
315 def save(self, commit=True):
316 # Save the provided password in hashed format
317 user = super(UserCreationForm, self).save(commit=False)
318 user.password = self.cleaned_data["password1"]
319 #user.set_password(self.cleaned_data["password1"])
325 class UserChangeForm(forms.ModelForm):
326 """A form for updating users. Includes all the fields on
327 the user, but replaces the password field with admin's
328 password hash display field.
330 password = ReadOnlyPasswordHashField()
335 def clean_password(self):
336 # Regardless of what the user provides, return the initial value.
337 # This is done here, rather than on the field, because the
338 # field does not have access to the initial value
339 return self.initial["password"]
342 class PLUserAdmin(UserAdmin, OSModelAdmin):
346 # The forms to add and change user instances
347 form = UserChangeForm
348 add_form = UserCreationForm
350 # The fields to be used in displaying the User model.
351 # These override the definitions on the base UserAdmin
352 # that reference specific fields on auth.User.
353 list_display = ('email', 'site', 'firstname', 'lastname', 'last_login')
354 list_filter = ('site',)
356 (None, {'fields': ('email', 'password')}),
357 ('Personal info', {'fields': ('firstname','lastname','phone','site')}),
358 #('Important dates', {'fields': ('last_login',)}),
362 'classes': ('wide',),
363 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'password1', 'password2')}
366 search_fields = ('email',)
367 ordering = ('email',)
368 filter_horizontal = ()
370 # register a signal that caches the user's credentials when they log in
371 def cache_credentials(sender, user, request, **kwds):
372 auth = {'username': request.POST['username'],
373 'password': request.POST['password']}
374 request.session['auth'] = auth
375 user_logged_in.connect(cache_credentials)
377 # Now register the new UserAdmin...
378 admin.site.register(PLUser, PLUserAdmin)
379 # ... and, since we're not using Django's builtin permissions,
380 # unregister the Group model from admin.
381 admin.site.unregister(Group)
383 admin.site.register(Site, SiteAdmin)
384 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
385 admin.site.register(Slice, SliceAdmin)
386 admin.site.register(SliceMembership, SliceMembershipAdmin)
387 admin.site.register(Subnet, SubnetAdmin)
388 admin.site.register(Image, ImageAdmin)
389 admin.site.register(Node, NodeAdmin)
390 admin.site.register(Sliver, SliverAdmin)
391 admin.site.register(Key, KeyAdmin)
392 admin.site.register(Role, RoleAdmin)
393 admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)