added isntance_name to sliver page
[plstackapi.git] / plstackapi / core / admin.py
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
6
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 
15
16
17 class ReadonlyTabularInline(admin.TabularInline):
18     can_delete = False
19     extra = 0
20     editable_fields = []
21
22     def get_readonly_fields(self, request, obj=None):
23         fields = []
24         for field in self.model._meta.get_all_field_names():
25             if (not field == 'id'):
26                 if (field not in self.editable_fields):
27                     fields.append(field)
28         return fields
29
30     def has_add_permission(self, request):
31         return False
32
33 class SliverInline(admin.TabularInline):
34     model = Sliver
35     fields = ['ip', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
36     extra = 0
37
38 class SiteInline(admin.TabularInline):
39     model = Site
40     extra = 0
41
42 class SliceInline(admin.TabularInline):
43     model = Slice
44     extra = 0
45
46 class UserInline(admin.TabularInline):
47     model = PLUser
48     extra = 0
49
50 class RoleInline(admin.TabularInline):
51     model = Role
52     extra = 0 
53
54 class NodeInline(admin.TabularInline):
55     model = Node
56     extra = 0
57
58 class PlainTextWidget(forms.Widget):
59     def render(self, _name, value, attrs):
60         return mark_safe(value) if value is not None else ''
61
62 class PlanetStackBaseAdmin(admin.ModelAdmin):
63     save_on_top = False
64
65 class OSModelAdmin(PlanetStackBaseAdmin):
66     """Attach client connection to openstack on delete() and save()"""
67
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)
72         obj.save()
73
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)
78         obj.delete() 
79
80 class RoleAdmin(OSModelAdmin):
81     fieldsets = [
82         ('Role', {'fields': ['role_type']})
83     ]
84     list_display = ('role_type',)
85
86
87 class DeploymentNetworkAdminForm(forms.ModelForm):
88     sites = forms.ModelMultipleChoiceField(
89         queryset=Site.objects.all(),
90         required=False,
91         widget=FilteredSelectMultiple(
92             verbose_name=('Sites'), is_stacked=False
93         )
94     )
95     class Meta:
96         model = DeploymentNetwork
97
98     def __init__(self, *args, **kwargs):
99         super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
100
101         if self.instance and self.instance.pk:
102             self.fields['sites'].initial = self.instance.sites.all()
103
104     def save(self, commit=True):
105         deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
106         if commit:
107             deploymentNetwork.save()
108
109         if deploymentNetwork.pk:
110             deploymentNetwork.sites = self.cleaned_data['sites']
111             self.save_m2m()
112
113         return deploymentNetwork
114
115 class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
116     form = DeploymentNetworkAdminForm
117     inlines = [NodeInline,]
118
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
122             if obj is None:
123                 continue
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)
129
130 class SiteAdmin(OSModelAdmin):
131     fieldsets = [
132         (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
133         ('Location', {'fields': ['latitude', 'longitude']}),
134         ('Deployment Networks', {'fields': ['deployments']})
135     ]
136     list_display = ('name', 'login_base','site_url', 'enabled')
137     filter_horizontal = ('deployments',)
138     inlines = [NodeInline,]
139     search_fields = ['name']
140
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
144             if obj is None:
145                 continue
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)
151
152 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
153     fieldsets = [
154         (None, {'fields': ['user', 'site', 'role']})
155     ]
156     list_display = ('user', 'site', 'role')
157
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)
163         obj.save()
164
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)
170         obj.delete()
171
172 class KeyAdmin(OSModelAdmin):
173     fieldsets = [
174         ('Key', {'fields': ['name', 'key', 'type', 'blacklisted', 'user']})
175     ]
176     list_display = ['name', 'key', 'type', 'blacklisted', 'user']
177
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:
182             return qs
183         # users can only see their own keys
184         return qs.filter(user=request.user)  
185         
186
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]
191
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
195             if obj is None:
196                 continue
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)
202
203     def get_queryset(self, request):
204         qs = super(SliceAdmin, self).get_queryset(request)
205         if request.user.is_superuser:
206             return qs
207         # users can only see slices at their site
208         return qs.filter(site=request.user.site) 
209
210 class SliceMembershipAdmin(PlanetStackBaseAdmin):
211     fieldsets = [
212         (None, {'fields': ['user', 'slice', 'role']})
213     ]
214     list_display = ('user', 'slice', 'role')
215
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)
221         obj.save()
222
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)
228         obj.delete()
229
230
231 class SubnetAdmin(PlanetStackBaseAdmin):
232     fields = ['cidr', 'ip_version', 'start', 'end', 'slice']
233     list_display = ('slice','cidr', 'start', 'end', 'ip_version')
234
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
240         obj.save()
241
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
247         obj.delete()
248
249 class ImageAdmin(admin.ModelAdmin):
250     fields = ['image_id', 'name', 'disk_format', 'container_format']
251
252 class NodeAdmin(admin.ModelAdmin):
253     list_display = ('name', 'site', 'deploymentNetwork')
254     list_filter = ('deploymentNetwork',)
255
256
257 class SliverForm(forms.ModelForm):
258     class Meta:
259         ip = forms.CharField(widget=PlainTextWidget)
260         instance_name = forms.CharField(widget=PlainTextWidget)
261         model = Sliver
262         widgets = {
263             'ip': PlainTextWidget(),
264             'instance_name': PlainTextWidget(),
265         }
266
267 class SliverAdmin(PlanetStackBaseAdmin):
268     form = SliverForm
269     fieldsets = [
270         ('Sliver', {'fields': ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
271     ]
272     list_display = ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
273
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
279         obj.save()
280
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
286         obj.delete()
287      
288
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)
294
295     class Meta:
296         model = PLUser
297         fields = ('email', 'firstname', 'lastname', 'phone', 'site')
298
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")
305         return password2
306
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"])
312         if commit:
313             user.save()
314         return user
315
316
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.
321     """
322     password = ReadOnlyPasswordHashField()
323
324     class Meta:
325         model = PLUser
326
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"]
332
333
334 class PLUserAdmin(UserAdmin, OSModelAdmin):
335     class Meta:
336         app_label = "core"
337
338     # The forms to add and change user instances
339     form = UserChangeForm
340     add_form = UserCreationForm
341
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',)
347     fieldsets = (
348         (None, {'fields': ('email', 'password')}),
349         ('Personal info', {'fields': ('firstname','lastname','phone','site')}),
350         #('Important dates', {'fields': ('last_login',)}),
351     )
352     add_fieldsets = (
353         (None, {
354             'classes': ('wide',),
355             'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'password1', 'password2')}
356         ),
357     )
358     search_fields = ('email',)
359     ordering = ('email',)
360     filter_horizontal = ()
361
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)
368
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)
374
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)
386