blob: aafa6e52e02d70e49ed896a2968baf2d9611c155 [file] [log] [blame]
Siobhan Tully30fd4292013-05-10 08:59:56 -04001from core.models import Site
2from core.models import *
3from openstack.manager import OpenStackManager
Tony Macke59a7c82013-04-27 11:08:10 -04004
Tony Mack7130ac32013-03-22 21:58:00 -04005from django.contrib import admin
Siobhan Tully53437282013-04-26 19:30:27 -04006from django.contrib.auth.models import Group
Siobhan Tully4bc09f22013-04-10 21:15:21 -04007from django import forms
Tony Mackd90cdbf2013-04-16 22:48:40 -04008from django.utils.safestring import mark_safe
Tony Mack7130ac32013-03-22 21:58:00 -04009from django.contrib.auth.admin import UserAdmin
Siobhan Tully4bc09f22013-04-10 21:15:21 -040010from django.contrib.admin.widgets import FilteredSelectMultiple
Siobhan Tully53437282013-04-26 19:30:27 -040011from django.contrib.auth.forms import ReadOnlyPasswordHashField
Scott Bakeracd45142013-05-19 16:19:16 -070012from django.contrib.auth.signals import user_logged_in
13from django.utils import timezone
Siobhan Tullybf1153a2013-05-27 20:53:48 -040014import django_evolution
Tony Mack7130ac32013-03-22 21:58:00 -040015
Siobhan Tully4bc09f22013-04-10 21:15:21 -040016
17class 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
33class SliverInline(admin.TabularInline):
34 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -040035 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040036 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -040037 #readonly_fields = ['ip', 'instance_name', 'image']
38 readonly_fields = ['ip', 'instance_name']
Tony Mackc2835a92013-05-28 09:18:49 -040039
Siobhan Tully4bc09f22013-04-10 21:15:21 -040040
41class SiteInline(admin.TabularInline):
42 model = Site
43 extra = 0
44
Siobhan Tully30fd4292013-05-10 08:59:56 -040045class UserInline(admin.TabularInline):
46 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -040047 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -040048 extra = 0
49
Tony Mack00d361f2013-04-28 10:28:42 -040050class SliceInline(admin.TabularInline):
51 model = Slice
52 extra = 0
53
Tony Mack00d361f2013-04-28 10:28:42 -040054class RoleInline(admin.TabularInline):
55 model = Role
56 extra = 0
57
Siobhan Tully4bc09f22013-04-10 21:15:21 -040058class NodeInline(admin.TabularInline):
59 model = Node
60 extra = 0
61
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040062class SitePrivilegeInline(admin.TabularInline):
63 model = SitePrivilege
64 extra = 0
65
Tony Mackc2835a92013-05-28 09:18:49 -040066 def formfield_for_foreignkey(self, db_field, request, **kwargs):
67 if db_field.name == 'site':
68 if not request.user.is_admin:
69 # only show sites where user is an admin or pi
70 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
71 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
72 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
73 sites = Site.objects.filter(login_base__in=login_bases)
74 kwargs['queryset'] = sites
75
76 if db_field.name == 'user':
77 if not request.user.is_admin:
78 # only show users from sites where caller has admin or pi role
79 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
80 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
81 sites = [site_privilege.site for site_privilege in site_privileges]
82 site_privileges = SitePrivilege.objects.filter(site__in=sites)
83 emails = [site_privilege.user.email for site_privilege in site_privileges]
84 users = User.objects.filter(email__in=emails)
85 kwargs['queryset'] = users
86 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
87
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040088class SliceMembershipInline(admin.TabularInline):
89 model = SliceMembership
90 extra = 0
Tony Mack2bd5b412013-06-11 21:05:06 -040091 fields = ('user', 'role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040092
Tony Mackc2835a92013-05-28 09:18:49 -040093 def formfield_for_foreignkey(self, db_field, request, **kwargs):
94 if db_field.name == 'slice':
95 if not request.user.is_admin:
96 # only show slices at sites where caller has admin or pi role
97 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
98 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
99 sites = [site_privilege.site for site_privilege in site_privileges]
100 slices = Slice.objects.filter(site__in=sites)
101 kwargs['queryset'] = slices
102 if db_field.name == 'user':
103 if not request.user.is_admin:
104 # only show users from sites where caller has admin or pi role
105 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
106 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
107 sites = [site_privilege.site for site_privilege in site_privileges]
108 site_privileges = SitePrivilege.objects.filter(site__in=sites)
109 emails = [site_privilege.user.email for site_privilege in site_privileges]
110 users = User.objects.filter(email__in=emails)
111 kwargs['queryset'] = list(users)
112
113 return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
114
Scott Baker307e06f2013-05-21 17:25:56 -0700115class SliceTagInline(admin.TabularInline):
116 model = SliceTag
117 extra = 0
118
Tony Mack5e71a662013-05-03 23:30:41 -0400119class PlainTextWidget(forms.HiddenInput):
120 input_type = 'hidden'
121
122 def render(self, name, value, attrs=None):
123 if value is None:
124 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400125 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400126
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400127class PlanetStackBaseAdmin(admin.ModelAdmin):
128 save_on_top = False
129
Tony Mack0553f282013-06-10 22:54:50 -0400130class RoleAdmin(PlanetStackBaseAdmin):
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400131 fieldsets = [
132 ('Role', {'fields': ['role_type']})
133 ]
134 list_display = ('role_type',)
Tony Mackfdd4d802013-04-27 13:02:33 -0400135
Tony Mack02755d42013-05-02 00:00:10 -0400136
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400137class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400138 sites = forms.ModelMultipleChoiceField(
139 queryset=Site.objects.all(),
140 required=False,
141 widget=FilteredSelectMultiple(
142 verbose_name=('Sites'), is_stacked=False
143 )
144 )
145 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400146 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400147
148 def __init__(self, *args, **kwargs):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400149 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400150
151 if self.instance and self.instance.pk:
152 self.fields['sites'].initial = self.instance.sites.all()
153
154 def save(self, commit=True):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400155 deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400156 if commit:
157 deploymentNetwork.save()
158
159 if deploymentNetwork.pk:
160 deploymentNetwork.sites = self.cleaned_data['sites']
161 self.save_m2m()
162
163 return deploymentNetwork
164
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400165class DeploymentAdmin(PlanetStackBaseAdmin):
166 form = DeploymentAdminForm
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400167 inlines = [NodeInline,SliverInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400168
Tony Mack5cd13202013-05-01 21:48:38 -0400169 def get_formsets(self, request, obj=None):
170 for inline in self.get_inline_instances(request, obj):
171 # hide MyInline in the add view
172 if obj is None:
173 continue
174 # give inline object access to driver and caller
Tony Macked163d72013-05-02 20:05:42 -0400175 auth = request.session.get('auth', {})
Siobhan Tully73291342013-05-10 10:50:08 -0400176 if request.user.site:
177 auth['tenant'] = request.user.site.login_base
Tony Macked163d72013-05-02 20:05:42 -0400178 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400179 yield inline.get_formset(request, obj)
180
Tony Mack0553f282013-06-10 22:54:50 -0400181class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400182 fieldsets = [
183 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
184 ('Location', {'fields': ['latitude', 'longitude']}),
185 ('Deployment Networks', {'fields': ['deployments']})
186 ]
187 list_display = ('name', 'login_base','site_url', 'enabled')
188 filter_horizontal = ('deployments',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400189 inlines = [NodeInline, UserInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400190 search_fields = ['name']
191
Tony Mack04062832013-05-10 08:22:44 -0400192 def queryset(self, request):
193 # admins can see all keys. Users can only see sites they belong to.
194 qs = super(SiteAdmin, self).queryset(request)
195 if not request.user.is_admin:
196 valid_sites = [request.user.site.login_base]
197 roles = request.user.get_roles()
198 for tenant_list in roles.values():
199 valid_sites.extend(tenant_list)
200 qs = qs.filter(login_base__in=valid_sites)
201 return qs
202
Tony Mack5cd13202013-05-01 21:48:38 -0400203 def get_formsets(self, request, obj=None):
204 for inline in self.get_inline_instances(request, obj):
205 # hide MyInline in the add view
206 if obj is None:
207 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400208 if isinstance(inline, SliceInline):
209 inline.model.caller = request.user
210 yield inline.get_formset(request, obj)
211
212 def get_formsets(self, request, obj=None):
213 for inline in self.get_inline_instances(request, obj):
214 # hide MyInline in the add view
215 if obj is None:
216 continue
217 if isinstance(inline, SliverInline):
218 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400219 yield inline.get_formset(request, obj)
220
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400221class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400222 fieldsets = [
223 (None, {'fields': ['user', 'site', 'role']})
224 ]
225 list_display = ('user', 'site', 'role')
226
Tony Mackc2835a92013-05-28 09:18:49 -0400227 def formfield_for_foreignkey(self, db_field, request, **kwargs):
228 if db_field.name == 'site':
229 if not request.user.is_admin:
230 # only show sites where user is an admin or pi
231 sites = set()
232 for site_privilege in SitePrivilege.objects.filer(user=request.user):
233 if site_privilege.role.role_type in ['admin', 'pi']:
234 sites.add(site_privilege.site)
235 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
236
237 if db_field.name == 'user':
238 if not request.user.is_admin:
239 # only show users from sites where caller has admin or pi role
240 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
241 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
242 sites = [site_privilege.site for site_privilege in site_privileges]
243 site_privileges = SitePrivilege.objects.filter(site__in=sites)
244 emails = [site_privilege.user.email for site_privilege in site_privileges]
245 users = User.objects.filter(email__in=emails)
246 kwargs['queryset'] = users
247
248 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
249
Tony Mack04062832013-05-10 08:22:44 -0400250 def queryset(self, request):
251 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400252 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400253 qs = super(SitePrivilegeAdmin, self).queryset(request)
254 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400255 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
256 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
257 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
258 sites = Site.objects.filter(login_base__in=login_bases)
259 qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400260 return qs
261
Tony Mack2bd5b412013-06-11 21:05:06 -0400262class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400263 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
264 list_display = ('name', 'site','serviceClass', 'slice_url')
Scott Baker307e06f2013-05-21 17:25:56 -0700265 inlines = [SliverInline, SliceMembershipInline, SliceTagInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400266
Tony Mackc2835a92013-05-28 09:18:49 -0400267 def formfield_for_foreignkey(self, db_field, request, **kwargs):
268 if db_field.name == 'site':
269 if not request.user.is_admin:
270 # only show sites where user is a pi or admin
271 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
272 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
273 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
274 sites = Site.objects.filter(login_base__in=login_bases)
275 kwargs['queryset'] = sites
276
277 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
278
Tony Mack04062832013-05-10 08:22:44 -0400279 def queryset(self, request):
280 # admins can see all keys. Users can only see slices they belong to.
281 qs = super(SliceAdmin, self).queryset(request)
282 if not request.user.is_admin:
283 valid_slices = []
284 roles = request.user.get_roles()
285 for tenant_list in roles.values():
286 valid_slices.extend(tenant_list)
287 qs = qs.filter(name__in=valid_slices)
288 return qs
289
Tony Mack79748612013-05-01 14:52:03 -0400290 def get_formsets(self, request, obj=None):
291 for inline in self.get_inline_instances(request, obj):
292 # hide MyInline in the add view
293 if obj is None:
294 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400295 if isinstance(inline, SliverInline):
296 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400297 yield inline.get_formset(request, obj)
298
Tony Mackfdd4d802013-04-27 13:02:33 -0400299 def get_queryset(self, request):
300 qs = super(SliceAdmin, self).get_queryset(request)
301 if request.user.is_superuser:
302 return qs
303 # users can only see slices at their site
Tony Mack2bd5b412013-06-11 21:05:06 -0400304 return qs.filter(site=request.user.site)
305
306 def save_model(self, request, obj, form, change):
307 # update openstack connection to use this site/tenant
308 obj.caller = request.user
309 obj.save()
Tony Mackfdd4d802013-04-27 13:02:33 -0400310
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400311class SliceMembershipAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400312 fieldsets = [
313 (None, {'fields': ['user', 'slice', 'role']})
314 ]
315 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400316
Tony Mackc2835a92013-05-28 09:18:49 -0400317 def formfield_for_foreignkey(self, db_field, request, **kwargs):
318 if db_field.name == 'slice':
319 if not request.user.is_admin:
320 # only show slices at sites where caller has admin or pi role
321 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
322 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
323 sites = [site_privilege.site for site_privilege in site_privileges]
324 slices = Slice.objects.filter(site__in=sites)
325 kwargs['queryset'] = slices
326
327 if db_field.name == 'user':
328 if not request.user.is_admin:
329 # only show users from sites where caller has admin or pi role
330 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
331 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
332 sites = [site_privilege.site for site_privilege in site_privileges]
333 site_privileges = SitePrivilege.objects.filter(site__in=sites)
334 emails = [site_privilege.user.email for site_privilege in site_privileges]
335 users = User.objects.filter(email__in=emails)
336 kwargs['queryset'] = users
337
338 return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
339
Tony Mack04062832013-05-10 08:22:44 -0400340 def queryset(self, request):
341 # admins can see all memberships. Users can only see memberships of
342 # slices where they have the admin role.
343 qs = super(SliceMembershipAdmin, self).queryset(request)
344 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400345 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
346 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
347 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
348 sites = Site.objects.filter(login_base__in=login_bases)
349 slices = Slice.objects.filter(site__in=sites)
350 qs = qs.filter(slice__in=slices)
Tony Mack04062832013-05-10 08:22:44 -0400351 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400352
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400353 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400354 # update openstack connection to use this site/tenant
355 auth = request.session.get('auth', {})
356 auth['tenant'] = obj.slice.name
357 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400358 obj.save()
359
360 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400361 # update openstack connection to use this site/tenant
362 auth = request.session.get('auth', {})
363 auth['tenant'] = obj.slice.name
364 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400365 obj.delete()
366
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400367
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400368class ImageAdmin(admin.ModelAdmin):
369 fields = ['image_id', 'name', 'disk_format', 'container_format']
370
371class NodeAdmin(admin.ModelAdmin):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400372 list_display = ('name', 'site', 'deployment')
373 list_filter = ('deployment',)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400374
Tony Mackd90cdbf2013-04-16 22:48:40 -0400375
376class SliverForm(forms.ModelForm):
377 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400378 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400379 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400380 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400381 widgets = {
382 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400383 'instance_name': PlainTextWidget(),
Siobhan Tully53437282013-04-26 19:30:27 -0400384 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400385
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400386class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400387 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400388 fieldsets = [
Tony Mack10082022013-05-06 17:15:00 -0400389 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
Tony Mackcdec0902013-04-15 00:38:49 -0400390 ]
Tony Mack10082022013-05-06 17:15:00 -0400391 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Tony Mack53106f32013-04-27 16:43:01 -0400392
Tony Mackc2835a92013-05-28 09:18:49 -0400393 def formfield_for_foreignkey(self, db_field, request, **kwargs):
394 if db_field.name == 'slice':
395 if not request.user.is_admin:
396 slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)])
397 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
398
399 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
400
Tony Mack04062832013-05-10 08:22:44 -0400401 def queryset(self, request):
402 # admins can see all slivers. Users can only see slivers of
403 # the slices they belong to.
404 qs = super(SliverAdmin, self).queryset(request)
405 if not request.user.is_admin:
406 tenants = []
407 roles = request.user.get_roles()
408 for tenant_list in roles.values():
409 tenants.extend(tenant_list)
410 valid_slices = Slice.objects.filter(name__in=tenants)
411 qs = qs.filter(slice__in=valid_slices)
412 return qs
413
Tony Mack1d6b85f2013-05-07 18:49:14 -0400414 def get_formsets(self, request, obj=None):
415 # make some fields read only if we are updating an existing record
416 if obj == None:
417 #self.readonly_fields = ('ip', 'instance_name')
418 self.readonly_fields = ()
419 else:
Tony Mack1e889462013-05-10 21:34:54 -0400420 self.readonly_fields = ()
421 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400422
423 for inline in self.get_inline_instances(request, obj):
424 # hide MyInline in the add view
425 if obj is None:
426 continue
427 # give inline object access to driver and caller
428 auth = request.session.get('auth', {})
429 auth['tenant'] = obj.name # meed to connect using slice's tenant
430 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
431 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400432
433 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400434 # update openstack connection to use this site/tenant
435 auth = request.session.get('auth', {})
436 auth['tenant'] = obj.slice.name
437 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackb0d97422013-06-10 09:57:45 -0400438 obj.creator = request.user
Tony Mack53106f32013-04-27 16:43:01 -0400439 obj.save()
440
441 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400442 # update openstack connection to use this site/tenant
443 auth = request.session.get('auth', {})
444 auth['tenant'] = obj.slice.name
445 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400446 obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400447
Siobhan Tully53437282013-04-26 19:30:27 -0400448class UserCreationForm(forms.ModelForm):
449 """A form for creating new users. Includes all the required
450 fields, plus a repeated password."""
451 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
452 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
453
454 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400455 model = User
Tony Mackb0d97422013-06-10 09:57:45 -0400456 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site')
Siobhan Tully53437282013-04-26 19:30:27 -0400457
458 def clean_password2(self):
459 # Check that the two password entries match
460 password1 = self.cleaned_data.get("password1")
461 password2 = self.cleaned_data.get("password2")
462 if password1 and password2 and password1 != password2:
463 raise forms.ValidationError("Passwords don't match")
464 return password2
465
466 def save(self, commit=True):
467 # Save the provided password in hashed format
468 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400469 user.password = self.cleaned_data["password1"]
470 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400471 if commit:
472 user.save()
473 return user
474
475
476class UserChangeForm(forms.ModelForm):
477 """A form for updating users. Includes all the fields on
478 the user, but replaces the password field with admin's
479 password hash display field.
480 """
481 password = ReadOnlyPasswordHashField()
482
483 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400484 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400485
486 def clean_password(self):
487 # Regardless of what the user provides, return the initial value.
488 # This is done here, rather than on the field, because the
489 # field does not have access to the initial value
490 return self.initial["password"]
491
492
Tony Mack2bd5b412013-06-11 21:05:06 -0400493class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400494 class Meta:
495 app_label = "core"
496
497 # The forms to add and change user instances
498 form = UserChangeForm
499 add_form = UserCreationForm
500
501 # The fields to be used in displaying the User model.
502 # These override the definitions on the base UserAdmin
503 # that reference specific fields on auth.User.
Tony Mack416c0f22013-05-09 16:59:09 -0400504 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tully53437282013-04-26 19:30:27 -0400505 list_filter = ('site',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400506 inlines = [SitePrivilegeInline, SliceMembershipInline]
Siobhan Tully53437282013-04-26 19:30:27 -0400507 fieldsets = (
Scott Baker9266e6b2013-05-19 15:54:48 -0700508 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
Tony Mackb0d97422013-06-10 09:57:45 -0400509 ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}),
Siobhan Tully53437282013-04-26 19:30:27 -0400510 #('Important dates', {'fields': ('last_login',)}),
511 )
512 add_fieldsets = (
513 (None, {
514 'classes': ('wide',),
Tony Mackb0d97422013-06-10 09:57:45 -0400515 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')}
Siobhan Tully53437282013-04-26 19:30:27 -0400516 ),
517 )
518 search_fields = ('email',)
519 ordering = ('email',)
520 filter_horizontal = ()
521
Tony Mackc2835a92013-05-28 09:18:49 -0400522 def formfield_for_foreignkey(self, db_field, request, **kwargs):
523 if db_field.name == 'site':
524 if not request.user.is_admin:
525 # show sites where caller is an admin or pi
526 sites = []
527 for site_privilege in SitePrivilege.objects.filer(user=request.user):
528 if site_privilege.role.role_type in ['admin', 'pi']:
529 sites.append(site_privilege.site.login_base)
530 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
531
532 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
533
Scott Baker3de3e372013-05-10 16:50:44 -0700534class ServiceResourceInline(admin.TabularInline):
535 model = ServiceResource
536 extra = 0
537
538class ServiceClassAdmin(admin.ModelAdmin):
539 list_display = ('name', 'commitment', 'membershipFee')
540 inlines = [ServiceResourceInline]
541
Scott Baker133c9212013-05-17 09:09:11 -0700542class ReservedResourceInline(admin.TabularInline):
543 model = ReservedResource
544 extra = 0
545
546 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
547 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
548
549 if db_field.name == 'resource':
550 # restrict resources to those that the slice's service class allows
551 if request._slice is not None:
552 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
553 if len(field.queryset) > 0:
554 field.initial = field.queryset.all()[0]
555 else:
556 field.queryset = field.queryset.none()
557 elif db_field.name == 'sliver':
558 # restrict slivers to those that belong to the slice
559 if request._slice is not None:
560 field.queryset = field.queryset.filter(slice = request._slice)
561 else:
562 field.queryset = field.queryset.none()
563
564 return field
565
566class ReservationChangeForm(forms.ModelForm):
567 class Meta:
568 model = Reservation
569
570class ReservationAddForm(forms.ModelForm):
571 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
572 refresh = forms.CharField(widget=forms.HiddenInput())
573
574 class Media:
575 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
576
577 def clean_slice(self):
578 slice = self.cleaned_data.get("slice")
579 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
580 if len(x) == 0:
581 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
582 return slice
583
584 class Meta:
585 model = Reservation
586
587class ReservationAddRefreshForm(ReservationAddForm):
588 """ This form is displayed when the Reservation Form receives an update
589 from the Slice dropdown onChange handler. It doesn't validate the
590 data and doesn't save the data. This will cause the form to be
591 redrawn.
592 """
593
Scott Baker8737e5f2013-05-17 09:35:32 -0700594 """ don't validate anything other than slice """
595 dont_validate_fields = ("startTime", "duration")
596
Scott Baker133c9212013-05-17 09:09:11 -0700597 def full_clean(self):
598 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -0700599
600 for fieldname in self.dont_validate_fields:
601 if fieldname in self._errors:
602 del self._errors[fieldname]
603
Scott Baker133c9212013-05-17 09:09:11 -0700604 return result
605
606 """ don't save anything """
607 def is_valid(self):
608 return False
609
610class ReservationAdmin(admin.ModelAdmin):
611 list_display = ('startTime', 'duration')
612 inlines = [ReservedResourceInline]
613 form = ReservationAddForm
614
615 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -0700616 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -0700617 request._refresh = False
618 request._slice = None
619 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -0700620 # "refresh" will be set to "1" if the form was submitted due to
621 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -0700622 if request.POST.get("refresh","1") == "1":
623 request._refresh = True
624 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -0700625
626 # Keep track of the slice that was selected, so the
627 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -0700628 request._slice = request.POST.get("slice",None)
629 if (request._slice is not None):
630 request._slice = Slice.objects.get(id=request._slice)
631
632 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
633 return result
634
Scott Bakeracd45142013-05-19 16:19:16 -0700635 def changelist_view(self, request, extra_context = None):
636 timezone.activate(request.user.timezone)
637 return super(ReservationAdmin, self).changelist_view(request, extra_context)
638
Scott Baker133c9212013-05-17 09:09:11 -0700639 def get_form(self, request, obj=None, **kwargs):
640 request._obj_ = obj
641 if obj is not None:
Scott Baker8737e5f2013-05-17 09:35:32 -0700642 # For changes, set request._slice to the slice already set in the
643 # object.
Scott Baker133c9212013-05-17 09:09:11 -0700644 request._slice = obj.slice
645 self.form = ReservationChangeForm
646 else:
647 if getattr(request, "_refresh", False):
648 self.form = ReservationAddRefreshForm
649 else:
650 self.form = ReservationAddForm
651 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
652
653 def get_readonly_fields(self, request, obj=None):
654 if (obj is not None):
655 # Prevent slice from being changed after the reservation has been
656 # created.
657 return ['slice']
658 else:
659 return []
Scott Baker3de3e372013-05-10 16:50:44 -0700660
Tony Mack31c2b8f2013-04-26 20:01:42 -0400661# register a signal that caches the user's credentials when they log in
662def cache_credentials(sender, user, request, **kwds):
663 auth = {'username': request.POST['username'],
664 'password': request.POST['password']}
665 request.session['auth'] = auth
666user_logged_in.connect(cache_credentials)
667
Siobhan Tully53437282013-04-26 19:30:27 -0400668# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -0400669admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -0400670# ... and, since we're not using Django's builtin permissions,
671# unregister the Group model from admin.
672admin.site.unregister(Group)
673
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400674#Do not show django evolution in the admin interface
675from django_evolution.models import Version, Evolution
676admin.site.unregister(Version)
677admin.site.unregister(Evolution)
678
679
680# When debugging it is often easier to see all the classes, but for regular use
681# only the top-levels should be displayed
682showAll = False
683
684admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400685admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400686admin.site.register(Slice, SliceAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400687#admin.site.register(Subnet)
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400688
689
690if showAll:
691 admin.site.register(Node, NodeAdmin)
692 admin.site.register(SliceMembership, SliceMembershipAdmin)
693 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
694 admin.site.register(Role, RoleAdmin)
695 admin.site.register(Sliver, SliverAdmin)
696 admin.site.register(ServiceClass, ServiceClassAdmin)
697 admin.site.register(Reservation, ReservationAdmin)
698 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -0400699