blob: d947c6e494b59b5ae53dc1593063ac8a25e18d91 [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 Tullyde5450d2013-06-21 11:35:33 -040014from django.contrib.contenttypes import generic
Tony Mack7130ac32013-03-22 21:58:00 -040015
Siobhan Tullyde5450d2013-06-21 11:35:33 -040016import django_evolution
Siobhan Tully4bc09f22013-04-10 21:15:21 -040017
18class ReadonlyTabularInline(admin.TabularInline):
19 can_delete = False
20 extra = 0
21 editable_fields = []
22
23 def get_readonly_fields(self, request, obj=None):
24 fields = []
25 for field in self.model._meta.get_all_field_names():
26 if (not field == 'id'):
27 if (field not in self.editable_fields):
28 fields.append(field)
29 return fields
30
31 def has_add_permission(self, request):
32 return False
33
Siobhan Tullyde5450d2013-06-21 11:35:33 -040034class TagInline(generic.GenericTabularInline):
35 model = Tag
36 exclude = ['enacted']
37 extra = 1
38
Siobhan Tully4bc09f22013-04-10 21:15:21 -040039class SliverInline(admin.TabularInline):
40 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -040041 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040042 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -040043 #readonly_fields = ['ip', 'instance_name', 'image']
44 readonly_fields = ['ip', 'instance_name']
Tony Mackc2835a92013-05-28 09:18:49 -040045
Siobhan Tully4bc09f22013-04-10 21:15:21 -040046
47class SiteInline(admin.TabularInline):
48 model = Site
49 extra = 0
50
Siobhan Tully30fd4292013-05-10 08:59:56 -040051class UserInline(admin.TabularInline):
52 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -040053 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -040054 extra = 0
55
Tony Mack00d361f2013-04-28 10:28:42 -040056class SliceInline(admin.TabularInline):
57 model = Slice
58 extra = 0
59
Tony Mack00d361f2013-04-28 10:28:42 -040060class RoleInline(admin.TabularInline):
61 model = Role
62 extra = 0
63
Siobhan Tully4bc09f22013-04-10 21:15:21 -040064class NodeInline(admin.TabularInline):
65 model = Node
66 extra = 0
67
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040068class SitePrivilegeInline(admin.TabularInline):
69 model = SitePrivilege
70 extra = 0
71
Tony Mackc2835a92013-05-28 09:18:49 -040072 def formfield_for_foreignkey(self, db_field, request, **kwargs):
73 if db_field.name == 'site':
74 if not request.user.is_admin:
75 # only show sites where user is an admin or pi
76 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
77 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
78 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
79 sites = Site.objects.filter(login_base__in=login_bases)
80 kwargs['queryset'] = sites
81
82 if db_field.name == 'user':
83 if not request.user.is_admin:
84 # only show users from sites where caller has admin or pi role
85 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
86 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
87 sites = [site_privilege.site for site_privilege in site_privileges]
88 site_privileges = SitePrivilege.objects.filter(site__in=sites)
89 emails = [site_privilege.user.email for site_privilege in site_privileges]
90 users = User.objects.filter(email__in=emails)
91 kwargs['queryset'] = users
92 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
93
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040094class SliceMembershipInline(admin.TabularInline):
95 model = SliceMembership
96 extra = 0
Tony Mack2bd5b412013-06-11 21:05:06 -040097 fields = ('user', 'role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040098
Tony Mackc2835a92013-05-28 09:18:49 -040099 def formfield_for_foreignkey(self, db_field, request, **kwargs):
100 if db_field.name == 'slice':
101 if not request.user.is_admin:
102 # only show slices at sites where caller has admin or pi role
103 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
104 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
105 sites = [site_privilege.site for site_privilege in site_privileges]
106 slices = Slice.objects.filter(site__in=sites)
107 kwargs['queryset'] = slices
108 if db_field.name == 'user':
109 if not request.user.is_admin:
110 # only show users from sites where caller has admin or pi role
111 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
112 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
113 sites = [site_privilege.site for site_privilege in site_privileges]
114 site_privileges = SitePrivilege.objects.filter(site__in=sites)
115 emails = [site_privilege.user.email for site_privilege in site_privileges]
116 users = User.objects.filter(email__in=emails)
117 kwargs['queryset'] = list(users)
118
119 return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
120
Scott Baker307e06f2013-05-21 17:25:56 -0700121class SliceTagInline(admin.TabularInline):
122 model = SliceTag
123 extra = 0
124
Tony Mack5e71a662013-05-03 23:30:41 -0400125class PlainTextWidget(forms.HiddenInput):
126 input_type = 'hidden'
127
128 def render(self, name, value, attrs=None):
129 if value is None:
130 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400131 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400132
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400133class PlanetStackBaseAdmin(admin.ModelAdmin):
134 save_on_top = False
135
Tony Mack0553f282013-06-10 22:54:50 -0400136class RoleAdmin(PlanetStackBaseAdmin):
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400137 fieldsets = [
138 ('Role', {'fields': ['role_type']})
139 ]
140 list_display = ('role_type',)
Tony Mackfdd4d802013-04-27 13:02:33 -0400141
Tony Mack02755d42013-05-02 00:00:10 -0400142
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400143class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400144 sites = forms.ModelMultipleChoiceField(
145 queryset=Site.objects.all(),
146 required=False,
147 widget=FilteredSelectMultiple(
148 verbose_name=('Sites'), is_stacked=False
149 )
150 )
151 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400152 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400153
154 def __init__(self, *args, **kwargs):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400155 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400156
157 if self.instance and self.instance.pk:
158 self.fields['sites'].initial = self.instance.sites.all()
159
160 def save(self, commit=True):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400161 deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400162 if commit:
163 deploymentNetwork.save()
164
165 if deploymentNetwork.pk:
166 deploymentNetwork.sites = self.cleaned_data['sites']
167 self.save_m2m()
168
169 return deploymentNetwork
170
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400171class DeploymentAdmin(PlanetStackBaseAdmin):
172 form = DeploymentAdminForm
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400173 inlines = [NodeInline,SliverInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400174
Tony Mack5cd13202013-05-01 21:48:38 -0400175 def get_formsets(self, request, obj=None):
176 for inline in self.get_inline_instances(request, obj):
177 # hide MyInline in the add view
178 if obj is None:
179 continue
180 # give inline object access to driver and caller
Tony Macked163d72013-05-02 20:05:42 -0400181 auth = request.session.get('auth', {})
Siobhan Tully73291342013-05-10 10:50:08 -0400182 if request.user.site:
183 auth['tenant'] = request.user.site.login_base
Tony Macked163d72013-05-02 20:05:42 -0400184 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400185 yield inline.get_formset(request, obj)
186
Tony Mack0553f282013-06-10 22:54:50 -0400187class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400188 fieldsets = [
189 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
190 ('Location', {'fields': ['latitude', 'longitude']}),
191 ('Deployment Networks', {'fields': ['deployments']})
192 ]
193 list_display = ('name', 'login_base','site_url', 'enabled')
194 filter_horizontal = ('deployments',)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400195 inlines = [TagInline, NodeInline, UserInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400196 search_fields = ['name']
197
Tony Mack04062832013-05-10 08:22:44 -0400198 def queryset(self, request):
199 # admins can see all keys. Users can only see sites they belong to.
200 qs = super(SiteAdmin, self).queryset(request)
201 if not request.user.is_admin:
202 valid_sites = [request.user.site.login_base]
203 roles = request.user.get_roles()
204 for tenant_list in roles.values():
205 valid_sites.extend(tenant_list)
206 qs = qs.filter(login_base__in=valid_sites)
207 return qs
208
Tony Mack5cd13202013-05-01 21:48:38 -0400209 def get_formsets(self, request, obj=None):
210 for inline in self.get_inline_instances(request, obj):
211 # hide MyInline in the add view
212 if obj is None:
213 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400214 if isinstance(inline, SliceInline):
215 inline.model.caller = request.user
216 yield inline.get_formset(request, obj)
217
218 def get_formsets(self, request, obj=None):
219 for inline in self.get_inline_instances(request, obj):
220 # hide MyInline in the add view
221 if obj is None:
222 continue
223 if isinstance(inline, SliverInline):
224 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400225 yield inline.get_formset(request, obj)
226
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400227class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400228 fieldsets = [
229 (None, {'fields': ['user', 'site', 'role']})
230 ]
231 list_display = ('user', 'site', 'role')
232
Tony Mackc2835a92013-05-28 09:18:49 -0400233 def formfield_for_foreignkey(self, db_field, request, **kwargs):
234 if db_field.name == 'site':
235 if not request.user.is_admin:
236 # only show sites where user is an admin or pi
237 sites = set()
238 for site_privilege in SitePrivilege.objects.filer(user=request.user):
239 if site_privilege.role.role_type in ['admin', 'pi']:
240 sites.add(site_privilege.site)
241 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
242
243 if db_field.name == 'user':
244 if not request.user.is_admin:
245 # only show users from sites where caller has admin or pi role
246 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
247 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
248 sites = [site_privilege.site for site_privilege in site_privileges]
249 site_privileges = SitePrivilege.objects.filter(site__in=sites)
250 emails = [site_privilege.user.email for site_privilege in site_privileges]
251 users = User.objects.filter(email__in=emails)
252 kwargs['queryset'] = users
253
254 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
255
Tony Mack04062832013-05-10 08:22:44 -0400256 def queryset(self, request):
257 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400258 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400259 qs = super(SitePrivilegeAdmin, self).queryset(request)
260 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400261 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
262 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
263 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
264 sites = Site.objects.filter(login_base__in=login_bases)
265 qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400266 return qs
267
Tony Mack2bd5b412013-06-11 21:05:06 -0400268class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400269 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
270 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400271 inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400272
Tony Mackc2835a92013-05-28 09:18:49 -0400273 def formfield_for_foreignkey(self, db_field, request, **kwargs):
274 if db_field.name == 'site':
275 if not request.user.is_admin:
276 # only show sites where user is a pi or admin
277 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
278 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
279 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
280 sites = Site.objects.filter(login_base__in=login_bases)
281 kwargs['queryset'] = sites
282
283 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
284
Tony Mack04062832013-05-10 08:22:44 -0400285 def queryset(self, request):
286 # admins can see all keys. Users can only see slices they belong to.
287 qs = super(SliceAdmin, self).queryset(request)
288 if not request.user.is_admin:
289 valid_slices = []
290 roles = request.user.get_roles()
291 for tenant_list in roles.values():
292 valid_slices.extend(tenant_list)
293 qs = qs.filter(name__in=valid_slices)
294 return qs
295
Tony Mack79748612013-05-01 14:52:03 -0400296 def get_formsets(self, request, obj=None):
297 for inline in self.get_inline_instances(request, obj):
298 # hide MyInline in the add view
299 if obj is None:
300 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400301 if isinstance(inline, SliverInline):
302 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400303 yield inline.get_formset(request, obj)
304
Tony Mackfdd4d802013-04-27 13:02:33 -0400305 def get_queryset(self, request):
306 qs = super(SliceAdmin, self).get_queryset(request)
307 if request.user.is_superuser:
308 return qs
309 # users can only see slices at their site
Tony Mack2bd5b412013-06-11 21:05:06 -0400310 return qs.filter(site=request.user.site)
311
312 def save_model(self, request, obj, form, change):
313 # update openstack connection to use this site/tenant
314 obj.caller = request.user
315 obj.save()
Tony Mackfdd4d802013-04-27 13:02:33 -0400316
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400317class SliceMembershipAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400318 fieldsets = [
319 (None, {'fields': ['user', 'slice', 'role']})
320 ]
321 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400322
Tony Mackc2835a92013-05-28 09:18:49 -0400323 def formfield_for_foreignkey(self, db_field, request, **kwargs):
324 if db_field.name == 'slice':
325 if not request.user.is_admin:
326 # only show slices at sites where caller has admin or pi role
327 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
328 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
329 sites = [site_privilege.site for site_privilege in site_privileges]
330 slices = Slice.objects.filter(site__in=sites)
331 kwargs['queryset'] = slices
332
333 if db_field.name == 'user':
334 if not request.user.is_admin:
335 # only show users from sites where caller has admin or pi role
336 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
337 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
338 sites = [site_privilege.site for site_privilege in site_privileges]
339 site_privileges = SitePrivilege.objects.filter(site__in=sites)
340 emails = [site_privilege.user.email for site_privilege in site_privileges]
341 users = User.objects.filter(email__in=emails)
342 kwargs['queryset'] = users
343
344 return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
345
Tony Mack04062832013-05-10 08:22:44 -0400346 def queryset(self, request):
347 # admins can see all memberships. Users can only see memberships of
348 # slices where they have the admin role.
349 qs = super(SliceMembershipAdmin, self).queryset(request)
350 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400351 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
352 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
353 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
354 sites = Site.objects.filter(login_base__in=login_bases)
355 slices = Slice.objects.filter(site__in=sites)
356 qs = qs.filter(slice__in=slices)
Tony Mack04062832013-05-10 08:22:44 -0400357 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400358
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400359 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400360 # update openstack connection to use this site/tenant
361 auth = request.session.get('auth', {})
362 auth['tenant'] = obj.slice.name
363 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400364 obj.save()
365
366 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400367 # update openstack connection to use this site/tenant
368 auth = request.session.get('auth', {})
369 auth['tenant'] = obj.slice.name
370 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400371 obj.delete()
372
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400373
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400374class ImageAdmin(admin.ModelAdmin):
375 fields = ['image_id', 'name', 'disk_format', 'container_format']
376
377class NodeAdmin(admin.ModelAdmin):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400378 list_display = ('name', 'site', 'deployment')
379 list_filter = ('deployment',)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400380 inlines = [TagInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400381
Tony Mackd90cdbf2013-04-16 22:48:40 -0400382
383class SliverForm(forms.ModelForm):
384 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400385 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400386 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400387 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400388 widgets = {
389 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400390 'instance_name': PlainTextWidget(),
Siobhan Tully53437282013-04-26 19:30:27 -0400391 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400392
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400393class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400394 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400395 fieldsets = [
Tony Mack10082022013-05-06 17:15:00 -0400396 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
Tony Mackcdec0902013-04-15 00:38:49 -0400397 ]
Tony Mack10082022013-05-06 17:15:00 -0400398 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400399 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400400
Tony Mackc2835a92013-05-28 09:18:49 -0400401 def formfield_for_foreignkey(self, db_field, request, **kwargs):
402 if db_field.name == 'slice':
403 if not request.user.is_admin:
404 slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)])
405 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
406
407 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
408
Tony Mack04062832013-05-10 08:22:44 -0400409 def queryset(self, request):
410 # admins can see all slivers. Users can only see slivers of
411 # the slices they belong to.
412 qs = super(SliverAdmin, self).queryset(request)
413 if not request.user.is_admin:
414 tenants = []
415 roles = request.user.get_roles()
416 for tenant_list in roles.values():
417 tenants.extend(tenant_list)
418 valid_slices = Slice.objects.filter(name__in=tenants)
419 qs = qs.filter(slice__in=valid_slices)
420 return qs
421
Tony Mack1d6b85f2013-05-07 18:49:14 -0400422 def get_formsets(self, request, obj=None):
423 # make some fields read only if we are updating an existing record
424 if obj == None:
425 #self.readonly_fields = ('ip', 'instance_name')
426 self.readonly_fields = ()
427 else:
Tony Mack1e889462013-05-10 21:34:54 -0400428 self.readonly_fields = ()
429 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400430
431 for inline in self.get_inline_instances(request, obj):
432 # hide MyInline in the add view
433 if obj is None:
434 continue
435 # give inline object access to driver and caller
436 auth = request.session.get('auth', {})
437 auth['tenant'] = obj.name # meed to connect using slice's tenant
438 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
439 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400440
441 def save_model(self, request, obj, form, change):
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 Mackb0d97422013-06-10 09:57:45 -0400446 obj.creator = request.user
Tony Mack53106f32013-04-27 16:43:01 -0400447 obj.save()
448
449 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400450 # update openstack connection to use this site/tenant
451 auth = request.session.get('auth', {})
452 auth['tenant'] = obj.slice.name
453 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400454 obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400455
Siobhan Tully53437282013-04-26 19:30:27 -0400456class UserCreationForm(forms.ModelForm):
457 """A form for creating new users. Includes all the required
458 fields, plus a repeated password."""
459 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
460 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
461
462 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400463 model = User
Tony Mackb0d97422013-06-10 09:57:45 -0400464 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site')
Siobhan Tully53437282013-04-26 19:30:27 -0400465
466 def clean_password2(self):
467 # Check that the two password entries match
468 password1 = self.cleaned_data.get("password1")
469 password2 = self.cleaned_data.get("password2")
470 if password1 and password2 and password1 != password2:
471 raise forms.ValidationError("Passwords don't match")
472 return password2
473
474 def save(self, commit=True):
475 # Save the provided password in hashed format
476 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400477 user.password = self.cleaned_data["password1"]
478 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400479 if commit:
480 user.save()
481 return user
482
483
484class UserChangeForm(forms.ModelForm):
485 """A form for updating users. Includes all the fields on
486 the user, but replaces the password field with admin's
487 password hash display field.
488 """
489 password = ReadOnlyPasswordHashField()
490
491 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400492 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400493
494 def clean_password(self):
495 # Regardless of what the user provides, return the initial value.
496 # This is done here, rather than on the field, because the
497 # field does not have access to the initial value
498 return self.initial["password"]
499
500
Tony Mack2bd5b412013-06-11 21:05:06 -0400501class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400502 class Meta:
503 app_label = "core"
504
505 # The forms to add and change user instances
506 form = UserChangeForm
507 add_form = UserCreationForm
508
509 # The fields to be used in displaying the User model.
510 # These override the definitions on the base UserAdmin
511 # that reference specific fields on auth.User.
Tony Mack416c0f22013-05-09 16:59:09 -0400512 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tully53437282013-04-26 19:30:27 -0400513 list_filter = ('site',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400514 inlines = [SitePrivilegeInline, SliceMembershipInline]
Siobhan Tully53437282013-04-26 19:30:27 -0400515 fieldsets = (
Scott Baker9266e6b2013-05-19 15:54:48 -0700516 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
Tony Mackb0d97422013-06-10 09:57:45 -0400517 ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}),
Siobhan Tully53437282013-04-26 19:30:27 -0400518 #('Important dates', {'fields': ('last_login',)}),
519 )
520 add_fieldsets = (
521 (None, {
522 'classes': ('wide',),
Tony Mackb0d97422013-06-10 09:57:45 -0400523 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')}
Siobhan Tully53437282013-04-26 19:30:27 -0400524 ),
525 )
526 search_fields = ('email',)
527 ordering = ('email',)
528 filter_horizontal = ()
529
Tony Mackc2835a92013-05-28 09:18:49 -0400530 def formfield_for_foreignkey(self, db_field, request, **kwargs):
531 if db_field.name == 'site':
532 if not request.user.is_admin:
533 # show sites where caller is an admin or pi
534 sites = []
535 for site_privilege in SitePrivilege.objects.filer(user=request.user):
536 if site_privilege.role.role_type in ['admin', 'pi']:
537 sites.append(site_privilege.site.login_base)
538 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
539
540 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
541
Scott Baker3de3e372013-05-10 16:50:44 -0700542class ServiceResourceInline(admin.TabularInline):
543 model = ServiceResource
544 extra = 0
545
546class ServiceClassAdmin(admin.ModelAdmin):
547 list_display = ('name', 'commitment', 'membershipFee')
548 inlines = [ServiceResourceInline]
549
Scott Baker133c9212013-05-17 09:09:11 -0700550class ReservedResourceInline(admin.TabularInline):
551 model = ReservedResource
552 extra = 0
553
554 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
555 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
556
557 if db_field.name == 'resource':
558 # restrict resources to those that the slice's service class allows
559 if request._slice is not None:
560 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
561 if len(field.queryset) > 0:
562 field.initial = field.queryset.all()[0]
563 else:
564 field.queryset = field.queryset.none()
565 elif db_field.name == 'sliver':
566 # restrict slivers to those that belong to the slice
567 if request._slice is not None:
568 field.queryset = field.queryset.filter(slice = request._slice)
569 else:
570 field.queryset = field.queryset.none()
571
572 return field
573
574class ReservationChangeForm(forms.ModelForm):
575 class Meta:
576 model = Reservation
577
578class ReservationAddForm(forms.ModelForm):
579 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
580 refresh = forms.CharField(widget=forms.HiddenInput())
581
582 class Media:
583 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
584
585 def clean_slice(self):
586 slice = self.cleaned_data.get("slice")
587 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
588 if len(x) == 0:
589 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
590 return slice
591
592 class Meta:
593 model = Reservation
594
595class ReservationAddRefreshForm(ReservationAddForm):
596 """ This form is displayed when the Reservation Form receives an update
597 from the Slice dropdown onChange handler. It doesn't validate the
598 data and doesn't save the data. This will cause the form to be
599 redrawn.
600 """
601
Scott Baker8737e5f2013-05-17 09:35:32 -0700602 """ don't validate anything other than slice """
603 dont_validate_fields = ("startTime", "duration")
604
Scott Baker133c9212013-05-17 09:09:11 -0700605 def full_clean(self):
606 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -0700607
608 for fieldname in self.dont_validate_fields:
609 if fieldname in self._errors:
610 del self._errors[fieldname]
611
Scott Baker133c9212013-05-17 09:09:11 -0700612 return result
613
614 """ don't save anything """
615 def is_valid(self):
616 return False
617
618class ReservationAdmin(admin.ModelAdmin):
619 list_display = ('startTime', 'duration')
620 inlines = [ReservedResourceInline]
621 form = ReservationAddForm
622
623 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -0700624 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -0700625 request._refresh = False
626 request._slice = None
627 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -0700628 # "refresh" will be set to "1" if the form was submitted due to
629 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -0700630 if request.POST.get("refresh","1") == "1":
631 request._refresh = True
632 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -0700633
634 # Keep track of the slice that was selected, so the
635 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -0700636 request._slice = request.POST.get("slice",None)
637 if (request._slice is not None):
638 request._slice = Slice.objects.get(id=request._slice)
639
640 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
641 return result
642
Scott Bakeracd45142013-05-19 16:19:16 -0700643 def changelist_view(self, request, extra_context = None):
644 timezone.activate(request.user.timezone)
645 return super(ReservationAdmin, self).changelist_view(request, extra_context)
646
Scott Baker133c9212013-05-17 09:09:11 -0700647 def get_form(self, request, obj=None, **kwargs):
648 request._obj_ = obj
649 if obj is not None:
Scott Baker8737e5f2013-05-17 09:35:32 -0700650 # For changes, set request._slice to the slice already set in the
651 # object.
Scott Baker133c9212013-05-17 09:09:11 -0700652 request._slice = obj.slice
653 self.form = ReservationChangeForm
654 else:
655 if getattr(request, "_refresh", False):
656 self.form = ReservationAddRefreshForm
657 else:
658 self.form = ReservationAddForm
659 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
660
661 def get_readonly_fields(self, request, obj=None):
662 if (obj is not None):
663 # Prevent slice from being changed after the reservation has been
664 # created.
665 return ['slice']
666 else:
667 return []
Scott Baker3de3e372013-05-10 16:50:44 -0700668
Tony Mack31c2b8f2013-04-26 20:01:42 -0400669# register a signal that caches the user's credentials when they log in
670def cache_credentials(sender, user, request, **kwds):
671 auth = {'username': request.POST['username'],
672 'password': request.POST['password']}
673 request.session['auth'] = auth
674user_logged_in.connect(cache_credentials)
675
Siobhan Tully53437282013-04-26 19:30:27 -0400676# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -0400677admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -0400678# ... and, since we're not using Django's builtin permissions,
679# unregister the Group model from admin.
680admin.site.unregister(Group)
681
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400682#Do not show django evolution in the admin interface
683from django_evolution.models import Version, Evolution
684admin.site.unregister(Version)
685admin.site.unregister(Evolution)
686
687
688# When debugging it is often easier to see all the classes, but for regular use
689# only the top-levels should be displayed
690showAll = False
691
692admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400693admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400694admin.site.register(Slice, SliceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400695
696if showAll:
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400697 admin.site.register(Tag)
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400698 admin.site.register(Node, NodeAdmin)
699 admin.site.register(SliceMembership, SliceMembershipAdmin)
700 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
701 admin.site.register(Role, RoleAdmin)
702 admin.site.register(Sliver, SliverAdmin)
703 admin.site.register(ServiceClass, ServiceClassAdmin)
704 admin.site.register(Reservation, ReservationAdmin)
705 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -0400706