Added in serviceClass to Slice, and numberCores to Sliver, adjusted admin.py accordingly
[plstackapi.git] / plstackapi / core / admin.py
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
5
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 
14
15
16 class ReadonlyTabularInline(admin.TabularInline):
17     can_delete = False
18     extra = 0
19     editable_fields = []
20
21     def get_readonly_fields(self, request, obj=None):
22         fields = []
23         for field in self.model._meta.get_all_field_names():
24             if (not field == 'id'):
25                 if (field not in self.editable_fields):
26                     fields.append(field)
27         return fields
28
29     def has_add_permission(self, request):
30         return False
31
32 class SliverInline(admin.TabularInline):
33     model = Sliver
34     fields = ['ip', 'name', 'slice', 'flavor', 'image', 'key', 'node', 'deploymentNetwork']
35     extra = 0
36
37 class SiteInline(admin.TabularInline):
38     model = Site
39     extra = 0
40
41 class SliceInline(admin.TabularInline):
42     model = Slice
43     extra = 0
44
45 class UserInline(admin.TabularInline):
46     model = PLUser
47     extra = 0
48
49 class RoleInline(admin.TabularInline):
50     model = Role
51     extra = 0 
52
53 class NodeInline(admin.TabularInline):
54     model = Node
55     extra = 0
56
57 class PlainTextWidget(forms.Widget):
58     def render(self, _name, value, attrs):
59         return mark_safe(value) if value is not None else ''
60
61 class PlanetStackBaseAdmin(admin.ModelAdmin):
62     save_on_top = False
63
64 class OSModelAdmin(PlanetStackBaseAdmin):
65     """Attach client connection to openstack on delete() and save()""" 
66     def save_model(self, request, obj, form, change):
67         client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
68         obj.driver = OpenStackDriver(client=client)
69         obj.caller = request.user
70         obj.save()
71
72     def delete_model(self, request, obj):
73         client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
74         obj.driver = OpenStackDriver(client=client)
75         obj.caller = request.user
76         obj.delete()
77
78 class RoleAdmin(OSModelAdmin):
79     fieldsets = [
80         ('Role', {'fields': ['role_type']})
81     ]
82     list_display = ('role_type',)
83
84 class DeploymentNetworkAdminForm(forms.ModelForm):
85     sites = forms.ModelMultipleChoiceField(
86         queryset=Site.objects.all(),
87         required=False,
88         widget=FilteredSelectMultiple(
89             verbose_name=('Sites'), is_stacked=False
90         )
91     )
92     class Meta:
93         model = DeploymentNetwork
94
95     def __init__(self, *args, **kwargs):
96         super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
97
98         if self.instance and self.instance.pk:
99             self.fields['sites'].initial = self.instance.sites.all()
100
101     def save(self, commit=True):
102         deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
103         if commit:
104             deploymentNetwork.save()
105
106         if deploymentNetwork.pk:
107             deploymentNetwork.sites = self.cleaned_data['sites']
108             self.save_m2m()
109
110         return deploymentNetwork
111
112 class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
113     form = DeploymentNetworkAdminForm
114     inlines = [NodeInline,]
115
116 class SiteAdmin(OSModelAdmin):
117     fieldsets = [
118         (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
119         ('Location', {'fields': ['latitude', 'longitude']}),
120         ('Deployment Networks', {'fields': ['deployments']})
121     ]
122     list_display = ('name', 'login_base','site_url', 'enabled')
123     filter_horizontal = ('deployments',)
124     inlines = [NodeInline,]
125     search_fields = ['name']
126
127 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
128     fieldsets = [
129         (None, {'fields': ['user', 'site', 'role']})
130     ]
131     list_display = ('user', 'site', 'role')
132
133     def save_model(self, request, obj, form, change):
134         # update openstack connection to use this site/tenant   
135         client = OpenStackClient(tenant=obj.site.login_base, **request.session.get('auth', {}))
136         obj.driver = OpenStackDriver(client=client)
137         obj.caller = request.user
138         obj.save()
139
140     def delete_model(self, request, obj):
141         # update openstack connection to use this site/tenant   
142         client = OpenStackClient(tenant=obj.site.login_base, **request.session.get('auth', {}))
143         obj.driver = OpenStackDriver(client=client)
144         obj.caller = request.user
145         obj.delete()
146
147 class KeyAdmin(OSModelAdmin):
148     fieldsets = [
149         ('Key', {'fields': ['name', 'key', 'type', 'blacklisted', 'user']})
150     ]
151     list_display = ['name', 'key', 'type', 'blacklisted', 'user']
152
153     def get_queryset(self, request):
154         # get keys user is allowed to see
155         qs = super(KeyAdmin, self).get_queryset(request)
156         if request.user.is_superuser:
157             return qs
158         # users can only see their own keys
159         return qs.filter(user=request.user)  
160         
161
162 class SliceAdmin(OSModelAdmin):
163     fields = ['name', 'site', 'instantiation', 'description', 'slice_url']
164     list_display = ('name', 'site','slice_url', 'instantiation')
165     inlines = [SliverInline]
166
167     def get_queryset(self, request):
168         qs = super(SliceAdmin, self).get_queryset(request)
169         if request.user.is_superuser:
170             return qs
171         # users can only see slices at their site
172         return qs.filter(site=request.user.site) 
173
174 class SliceMembershipAdmin(PlanetStackBaseAdmin):
175     fieldsets = [
176         (None, {'fields': ['user', 'slice', 'role']})
177     ]
178     list_display = ('user', 'slice', 'role')
179
180     def save_model(self, request, obj, form, change):
181         # update openstack connection to use this slice/tenant
182         client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
183         obj.driver = OpenStackDriver(client=client)
184         obj.caller = request.user
185         obj.save()
186
187     def delete_model(self, request, obj):
188         # update openstack connection to use this slice/tenant
189         client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
190         obj.driver = OpenStackDriver(client=client)
191         obj.caller = request.user
192         obj.delete()
193
194 class SubnetAdmin(PlanetStackBaseAdmin):
195     fields = ['cidr', 'ip_version', 'start', 'end', 'slice']
196     list_display = ('slice','cidr', 'start', 'end', 'ip_version')
197
198     def save_model(self, request, obj, form, change):
199         # update openstack connection to use this subnet's slice/tenant
200         client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
201         obj.driver = OpenStackDriver(client=client)
202         obj.caller = request.user
203         obj.save()
204
205     def delete_model(self, request, obj):
206         # update openstack connection to use this subnet's slice/tenant
207         client = OpenStackClient(tenant=obj.slice.name, **request.session.get('auth', {}))
208         obj.driver = OpenStackDriver(client=client)
209         obj.caller = request.user
210         obj.delete()
211
212 class ImageAdmin(admin.ModelAdmin):
213     fields = ['image_id', 'name', 'disk_format', 'container_format']
214
215 class NodeAdmin(admin.ModelAdmin):
216     list_display = ('name', 'site', 'deploymentNetwork')
217     list_filter = ('deploymentNetwork',)
218
219
220 class SliverForm(forms.ModelForm):
221     class Meta:
222         ip = forms.CharField(widget=PlainTextWidget)
223         model = Sliver
224         widgets = {
225             'ip': PlainTextWidget(),
226         }
227
228 class SliverAdmin(PlanetStackBaseAdmin):
229     form = SliverForm
230     fieldsets = [
231         ('Sliver', {'fields': ['ip', 'name', 'slice', 'numberCores', 'flavor', 'image', 'key', 'node', 'deploymentNetwork']})
232     ]
233     list_display = ['ip', 'name', 'slice', 'flavor', 'image', 'key', 'node', 'deploymentNetwork']
234
235     def save_model(self, request, obj, form, change):
236         # update openstack connection to use this sliver'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 sliver'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
250 class UserCreationForm(forms.ModelForm):
251     """A form for creating new users. Includes all the required
252     fields, plus a repeated password."""
253     password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
254     password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
255
256     class Meta:
257         model = PLUser
258         fields = ('email', 'firstname', 'lastname', 'phone', 'site')
259
260     def clean_password2(self):
261         # Check that the two password entries match
262         password1 = self.cleaned_data.get("password1")
263         password2 = self.cleaned_data.get("password2")
264         if password1 and password2 and password1 != password2:
265             raise forms.ValidationError("Passwords don't match")
266         return password2
267
268     def save(self, commit=True):
269         # Save the provided password in hashed format
270         user = super(UserCreationForm, self).save(commit=False)
271         user.set_password(self.cleaned_data["password1"])
272         if commit:
273             user.save()
274         return user
275
276
277 class UserChangeForm(forms.ModelForm):
278     """A form for updating users. Includes all the fields on
279     the user, but replaces the password field with admin's
280     password hash display field.
281     """
282     password = ReadOnlyPasswordHashField()
283
284     class Meta:
285         model = PLUser
286
287     def clean_password(self):
288         # Regardless of what the user provides, return the initial value.
289         # This is done here, rather than on the field, because the
290         # field does not have access to the initial value
291         return self.initial["password"]
292
293
294 class PLUserAdmin(UserAdmin, OSModelAdmin):
295     class Meta:
296         app_label = "core"
297
298     # The forms to add and change user instances
299     form = UserChangeForm
300     add_form = UserCreationForm
301
302     # The fields to be used in displaying the User model.
303     # These override the definitions on the base UserAdmin
304     # that reference specific fields on auth.User.
305     list_display = ('email', 'site', 'firstname', 'lastname', 'last_login')
306     list_filter = ('site',)
307     fieldsets = (
308         (None, {'fields': ('email', 'password')}),
309         ('Personal info', {'fields': ('firstname','lastname','phone','site')}),
310         #('Important dates', {'fields': ('last_login',)}),
311     )
312     add_fieldsets = (
313         (None, {
314             'classes': ('wide',),
315             'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'password1', 'password2')}
316         ),
317     )
318     search_fields = ('email',)
319     ordering = ('email',)
320     filter_horizontal = ()
321
322 # register a signal that caches the user's credentials when they log in
323 def cache_credentials(sender, user, request, **kwds):
324     auth = {'username': request.POST['username'],
325             'password': request.POST['password']}
326     request.session['auth'] = auth
327 user_logged_in.connect(cache_credentials)
328
329 # Now register the new UserAdmin...
330 admin.site.register(PLUser, PLUserAdmin)
331 # ... and, since we're not using Django's builtin permissions,
332 # unregister the Group model from admin.
333 admin.site.unregister(Group)
334
335 admin.site.register(Site, SiteAdmin)
336 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
337 admin.site.register(Slice, SliceAdmin)
338 admin.site.register(SliceMembership, SliceMembershipAdmin)
339 admin.site.register(Subnet, SubnetAdmin)
340 admin.site.register(Image, ImageAdmin)
341 admin.site.register(Node, NodeAdmin)
342 admin.site.register(Sliver, SliverAdmin)
343 admin.site.register(Flavor)
344 admin.site.register(Key, KeyAdmin)
345 admin.site.register(Role, RoleAdmin)
346 admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)
347