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