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 auth = request.session.get('auth', {})
70 auth['tenant'] = request.user.site.login_base
71 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
74 def delete_model(self, request, obj):
75 auth = request.session.get('auth', {})
76 auth['tenant'] = request.user.site.login_base
77 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
80 class RoleAdmin(OSModelAdmin):
82 ('Role', {'fields': ['role_type']})
84 list_display = ('role_type',)
87 class DeploymentNetworkAdminForm(forms.ModelForm):
88 sites = forms.ModelMultipleChoiceField(
89 queryset=Site.objects.all(),
91 widget=FilteredSelectMultiple(
92 verbose_name=('Sites'), is_stacked=False
96 model = DeploymentNetwork
98 def __init__(self, *args, **kwargs):
99 super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
101 if self.instance and self.instance.pk:
102 self.fields['sites'].initial = self.instance.sites.all()
104 def save(self, commit=True):
105 deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
107 deploymentNetwork.save()
109 if deploymentNetwork.pk:
110 deploymentNetwork.sites = self.cleaned_data['sites']
113 return deploymentNetwork
115 class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
116 form = DeploymentNetworkAdminForm
117 inlines = [NodeInline,]
119 def get_formsets(self, request, obj=None):
120 for inline in self.get_inline_instances(request, obj):
121 # hide MyInline in the add view
124 # give inline object access to driver and caller
125 client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
126 inline.model.driver = OpenStackDriver(client=client)
127 inline.model.caller = request.user
128 yield inline.get_formset(request, obj)
130 class SiteAdmin(OSModelAdmin):
132 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
133 ('Location', {'fields': ['latitude', 'longitude']}),
134 ('Deployment Networks', {'fields': ['deployments']})
136 list_display = ('name', 'login_base','site_url', 'enabled')
137 filter_horizontal = ('deployments',)
138 inlines = [NodeInline,]
139 search_fields = ['name']
141 def get_formsets(self, request, obj=None):
142 for inline in self.get_inline_instances(request, obj):
143 # hide MyInline in the add view
146 # give inline object access to driver and caller
147 auth = request.session.get('auth', {})
148 auth['tenant'] = request.user.site.login_base
149 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
150 yield inline.get_formset(request, obj)
152 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
154 (None, {'fields': ['user', 'site', 'role']})
156 list_display = ('user', 'site', 'role')
158 def save_model(self, request, obj, form, change):
159 # update openstack connection to use this site/tenant
160 auth = request.session.get('auth', {})
161 auth['tenant'] = obj.site.login_base
162 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
165 def delete_model(self, request, obj):
166 # update openstack connection to use this site/tenant
167 auth = request.session.get('auth', {})
168 auth['tenant'] = obj.site.login_base
169 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
172 class KeyAdmin(OSModelAdmin):
174 ('Key', {'fields': ['name', 'key', 'type', 'blacklisted', 'user']})
176 list_display = ['name', 'key', 'type', 'blacklisted', 'user']
178 def get_queryset(self, request):
179 # get keys user is allowed to see
180 qs = super(KeyAdmin, self).get_queryset(request)
181 if request.user.is_superuser:
183 # users can only see their own keys
184 return qs.filter(user=request.user)
187 class SliceAdmin(OSModelAdmin):
188 fields = ['name', 'site', 'serviceClass', 'instantiation', 'description', 'slice_url']
189 list_display = ('name', 'site','serviceClass', 'slice_url', 'instantiation')
190 inlines = [SliverInline]
192 def get_formsets(self, request, obj=None):
193 for inline in self.get_inline_instances(request, obj):
194 # hide MyInline in the add view
197 # give inline object access to driver and caller
198 auth = request.session.get('auth', {})
199 auth['tenant'] = obj.name # meed to connect using slice's tenant
200 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
201 yield inline.get_formset(request, obj)
203 def get_queryset(self, request):
204 qs = super(SliceAdmin, self).get_queryset(request)
205 if request.user.is_superuser:
207 # users can only see slices at their site
208 return qs.filter(site=request.user.site)
210 class SliceMembershipAdmin(PlanetStackBaseAdmin):
212 (None, {'fields': ['user', 'slice', 'role']})
214 list_display = ('user', 'slice', 'role')
216 def save_model(self, request, obj, form, change):
217 # update openstack connection to use this site/tenant
218 auth = request.session.get('auth', {})
219 auth['tenant'] = obj.slice.name
220 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
223 def delete_model(self, request, obj):
224 # update openstack connection to use this site/tenant
225 auth = request.session.get('auth', {})
226 auth['tenant'] = obj.slice.name
227 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
231 class SubnetAdmin(PlanetStackBaseAdmin):
232 fields = ['cidr', 'ip_version', 'start', 'end', 'slice']
233 list_display = ('slice','cidr', 'start', 'end', 'ip_version')
235 def save_model(self, request, obj, form, change):
236 # update openstack connection to use this subnet's slice/tenant
237 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
238 obj.driver = OpenStackDriver(client=client)
239 obj.caller = request.user
242 def delete_model(self, request, obj):
243 # update openstack connection to use this subnet's slice/tenant
244 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
245 obj.driver = OpenStackDriver(client=client)
246 obj.caller = request.user
249 class ImageAdmin(admin.ModelAdmin):
250 fields = ['image_id', 'name', 'disk_format', 'container_format']
252 class NodeAdmin(admin.ModelAdmin):
253 list_display = ('name', 'site', 'deploymentNetwork')
254 list_filter = ('deploymentNetwork',)
257 class SliverForm(forms.ModelForm):
259 ip = forms.CharField(widget=PlainTextWidget)
260 instance_name = forms.CharField(widget=PlainTextWidget)
263 'ip': PlainTextWidget(),
264 'instance_name': PlainTextWidget(),
267 class SliverAdmin(PlanetStackBaseAdmin):
270 ('Sliver', {'fields': ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
272 list_display = ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
274 def save_model(self, request, obj, form, change):
275 # update openstack connection to use this sliver's slice/tenant
276 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
277 obj.driver = OpenStackDriver(client=client)
278 obj.caller = request.user
281 def delete_model(self, request, obj):
282 # update openstack connection to use this sliver's slice/tenant
283 client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
284 obj.driver = OpenStackDriver(client=client)
285 obj.caller = request.user
289 class UserCreationForm(forms.ModelForm):
290 """A form for creating new users. Includes all the required
291 fields, plus a repeated password."""
292 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
293 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
297 fields = ('email', 'firstname', 'lastname', 'phone', 'site')
299 def clean_password2(self):
300 # Check that the two password entries match
301 password1 = self.cleaned_data.get("password1")
302 password2 = self.cleaned_data.get("password2")
303 if password1 and password2 and password1 != password2:
304 raise forms.ValidationError("Passwords don't match")
307 def save(self, commit=True):
308 # Save the provided password in hashed format
309 user = super(UserCreationForm, self).save(commit=False)
310 user.password = self.cleaned_data["password1"]
311 #user.set_password(self.cleaned_data["password1"])
317 class UserChangeForm(forms.ModelForm):
318 """A form for updating users. Includes all the fields on
319 the user, but replaces the password field with admin's
320 password hash display field.
322 password = ReadOnlyPasswordHashField()
327 def clean_password(self):
328 # Regardless of what the user provides, return the initial value.
329 # This is done here, rather than on the field, because the
330 # field does not have access to the initial value
331 return self.initial["password"]
334 class PLUserAdmin(UserAdmin, OSModelAdmin):
338 # The forms to add and change user instances
339 form = UserChangeForm
340 add_form = UserCreationForm
342 # The fields to be used in displaying the User model.
343 # These override the definitions on the base UserAdmin
344 # that reference specific fields on auth.User.
345 list_display = ('email', 'site', 'firstname', 'lastname', 'last_login')
346 list_filter = ('site',)
348 (None, {'fields': ('email', 'password')}),
349 ('Personal info', {'fields': ('firstname','lastname','phone','site')}),
350 #('Important dates', {'fields': ('last_login',)}),
354 'classes': ('wide',),
355 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'password1', 'password2')}
358 search_fields = ('email',)
359 ordering = ('email',)
360 filter_horizontal = ()
362 # register a signal that caches the user's credentials when they log in
363 def cache_credentials(sender, user, request, **kwds):
364 auth = {'username': request.POST['username'],
365 'password': request.POST['password']}
366 request.session['auth'] = auth
367 user_logged_in.connect(cache_credentials)
369 # Now register the new UserAdmin...
370 admin.site.register(PLUser, PLUserAdmin)
371 # ... and, since we're not using Django's builtin permissions,
372 # unregister the Group model from admin.
373 admin.site.unregister(Group)
375 admin.site.register(Site, SiteAdmin)
376 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
377 admin.site.register(Slice, SliceAdmin)
378 admin.site.register(SliceMembership, SliceMembershipAdmin)
379 admin.site.register(Subnet, SubnetAdmin)
380 admin.site.register(Image, ImageAdmin)
381 admin.site.register(Node, NodeAdmin)
382 admin.site.register(Sliver, SliverAdmin)
383 admin.site.register(Key, KeyAdmin)
384 admin.site.register(Role, RoleAdmin)
385 admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)