blob: 76810f6c2d2846dd11c82a4eab3ed2fc53143a31 [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
Siobhan Tullyd3515752013-06-21 16:34:53 -040018class PlStackTabularInline(admin.TabularInline):
19 exclude = ['enacted']
20
21class ReadonlyTabularInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -040022 can_delete = False
23 extra = 0
24 editable_fields = []
25
26 def get_readonly_fields(self, request, obj=None):
27 fields = []
28 for field in self.model._meta.get_all_field_names():
29 if (not field == 'id'):
30 if (field not in self.editable_fields):
31 fields.append(field)
32 return fields
33
34 def has_add_permission(self, request):
35 return False
36
Siobhan Tullyde5450d2013-06-21 11:35:33 -040037class TagInline(generic.GenericTabularInline):
38 model = Tag
39 exclude = ['enacted']
40 extra = 1
41
Siobhan Tullyd3515752013-06-21 16:34:53 -040042class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -040043 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -040044 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040045 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -040046 #readonly_fields = ['ip', 'instance_name', 'image']
47 readonly_fields = ['ip', 'instance_name']
Tony Mackc2835a92013-05-28 09:18:49 -040048
Siobhan Tullyd3515752013-06-21 16:34:53 -040049class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -040050 model = Site
51 extra = 0
52
Siobhan Tullyd3515752013-06-21 16:34:53 -040053class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -040054 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -040055 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -040056 extra = 0
57
Siobhan Tullyd3515752013-06-21 16:34:53 -040058class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -040059 model = Slice
60 extra = 0
61
Siobhan Tullyd3515752013-06-21 16:34:53 -040062class RoleInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -040063 model = Role
64 extra = 0
65
Siobhan Tullyd3515752013-06-21 16:34:53 -040066class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -040067 model = Node
68 extra = 0
69
Siobhan Tullyd3515752013-06-21 16:34:53 -040070class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040071 model = SitePrivilege
72 extra = 0
73
Tony Mackc2835a92013-05-28 09:18:49 -040074 def formfield_for_foreignkey(self, db_field, request, **kwargs):
75 if db_field.name == 'site':
76 if not request.user.is_admin:
77 # only show sites where user is an admin or pi
78 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
79 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
80 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
81 sites = Site.objects.filter(login_base__in=login_bases)
82 kwargs['queryset'] = sites
83
84 if db_field.name == 'user':
85 if not request.user.is_admin:
86 # only show users from sites where caller has admin or pi role
87 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
88 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
89 sites = [site_privilege.site for site_privilege in site_privileges]
90 site_privileges = SitePrivilege.objects.filter(site__in=sites)
91 emails = [site_privilege.user.email for site_privilege in site_privileges]
92 users = User.objects.filter(email__in=emails)
93 kwargs['queryset'] = users
94 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
95
Siobhan Tullyd3515752013-06-21 16:34:53 -040096class SliceMembershipInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040097 model = SliceMembership
98 extra = 0
Tony Mack2bd5b412013-06-11 21:05:06 -040099 fields = ('user', 'role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400100
Tony Mackc2835a92013-05-28 09:18:49 -0400101 def formfield_for_foreignkey(self, db_field, request, **kwargs):
102 if db_field.name == 'slice':
103 if not request.user.is_admin:
104 # only show slices at 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 slices = Slice.objects.filter(site__in=sites)
109 kwargs['queryset'] = slices
110 if db_field.name == 'user':
111 if not request.user.is_admin:
112 # only show users from sites where caller has admin or pi role
113 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
114 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
115 sites = [site_privilege.site for site_privilege in site_privileges]
116 site_privileges = SitePrivilege.objects.filter(site__in=sites)
117 emails = [site_privilege.user.email for site_privilege in site_privileges]
118 users = User.objects.filter(email__in=emails)
119 kwargs['queryset'] = list(users)
120
121 return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
122
Siobhan Tullyd3515752013-06-21 16:34:53 -0400123class SliceTagInline(PlStackTabularInline):
Scott Baker307e06f2013-05-21 17:25:56 -0700124 model = SliceTag
125 extra = 0
126
Tony Mack5e71a662013-05-03 23:30:41 -0400127class PlainTextWidget(forms.HiddenInput):
128 input_type = 'hidden'
129
130 def render(self, name, value, attrs=None):
131 if value is None:
132 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400133 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400134
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400135class PlanetStackBaseAdmin(admin.ModelAdmin):
136 save_on_top = False
Siobhan Tullyd3515752013-06-21 16:34:53 -0400137 exclude = ['enacted']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400138
Tony Mack0553f282013-06-10 22:54:50 -0400139class RoleAdmin(PlanetStackBaseAdmin):
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400140 fieldsets = [
141 ('Role', {'fields': ['role_type']})
142 ]
143 list_display = ('role_type',)
Tony Mackfdd4d802013-04-27 13:02:33 -0400144
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400145class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400146 sites = forms.ModelMultipleChoiceField(
147 queryset=Site.objects.all(),
148 required=False,
149 widget=FilteredSelectMultiple(
150 verbose_name=('Sites'), is_stacked=False
151 )
152 )
153 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400154 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400155
156 def __init__(self, *args, **kwargs):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400157 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400158
159 if self.instance and self.instance.pk:
160 self.fields['sites'].initial = self.instance.sites.all()
161
162 def save(self, commit=True):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400163 deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400164 if commit:
165 deploymentNetwork.save()
166
167 if deploymentNetwork.pk:
168 deploymentNetwork.sites = self.cleaned_data['sites']
169 self.save_m2m()
170
171 return deploymentNetwork
172
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400173class DeploymentAdmin(PlanetStackBaseAdmin):
174 form = DeploymentAdminForm
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400175 inlines = [NodeInline,SliverInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400176
Tony Mack5cd13202013-05-01 21:48:38 -0400177 def get_formsets(self, request, obj=None):
178 for inline in self.get_inline_instances(request, obj):
179 # hide MyInline in the add view
180 if obj is None:
181 continue
182 # give inline object access to driver and caller
Tony Macked163d72013-05-02 20:05:42 -0400183 auth = request.session.get('auth', {})
Siobhan Tully73291342013-05-10 10:50:08 -0400184 if request.user.site:
185 auth['tenant'] = request.user.site.login_base
Tony Macked163d72013-05-02 20:05:42 -0400186 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400187 yield inline.get_formset(request, obj)
188
Tony Mack0553f282013-06-10 22:54:50 -0400189class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400190 fieldsets = [
191 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
192 ('Location', {'fields': ['latitude', 'longitude']}),
193 ('Deployment Networks', {'fields': ['deployments']})
194 ]
195 list_display = ('name', 'login_base','site_url', 'enabled')
196 filter_horizontal = ('deployments',)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400197 inlines = [TagInline, NodeInline, UserInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400198 search_fields = ['name']
199
Tony Mack04062832013-05-10 08:22:44 -0400200 def queryset(self, request):
201 # admins can see all keys. Users can only see sites they belong to.
202 qs = super(SiteAdmin, self).queryset(request)
203 if not request.user.is_admin:
204 valid_sites = [request.user.site.login_base]
205 roles = request.user.get_roles()
206 for tenant_list in roles.values():
207 valid_sites.extend(tenant_list)
208 qs = qs.filter(login_base__in=valid_sites)
209 return qs
210
Tony Mack5cd13202013-05-01 21:48:38 -0400211 def get_formsets(self, request, obj=None):
212 for inline in self.get_inline_instances(request, obj):
213 # hide MyInline in the add view
214 if obj is None:
215 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400216 if isinstance(inline, SliceInline):
217 inline.model.caller = request.user
218 yield inline.get_formset(request, obj)
219
220 def get_formsets(self, request, obj=None):
221 for inline in self.get_inline_instances(request, obj):
222 # hide MyInline in the add view
223 if obj is None:
224 continue
225 if isinstance(inline, SliverInline):
226 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400227 yield inline.get_formset(request, obj)
228
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400229class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400230 fieldsets = [
231 (None, {'fields': ['user', 'site', 'role']})
232 ]
233 list_display = ('user', 'site', 'role')
234
Tony Mackc2835a92013-05-28 09:18:49 -0400235 def formfield_for_foreignkey(self, db_field, request, **kwargs):
236 if db_field.name == 'site':
237 if not request.user.is_admin:
238 # only show sites where user is an admin or pi
239 sites = set()
240 for site_privilege in SitePrivilege.objects.filer(user=request.user):
241 if site_privilege.role.role_type in ['admin', 'pi']:
242 sites.add(site_privilege.site)
243 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
244
245 if db_field.name == 'user':
246 if not request.user.is_admin:
247 # only show users from sites where caller has admin or pi role
248 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
249 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
250 sites = [site_privilege.site for site_privilege in site_privileges]
251 site_privileges = SitePrivilege.objects.filter(site__in=sites)
252 emails = [site_privilege.user.email for site_privilege in site_privileges]
253 users = User.objects.filter(email__in=emails)
254 kwargs['queryset'] = users
255
256 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
257
Tony Mack04062832013-05-10 08:22:44 -0400258 def queryset(self, request):
259 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400260 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400261 qs = super(SitePrivilegeAdmin, self).queryset(request)
262 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400263 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
264 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
265 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
266 sites = Site.objects.filter(login_base__in=login_bases)
267 qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400268 return qs
269
Tony Mack2bd5b412013-06-11 21:05:06 -0400270class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400271 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
272 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400273 inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400274
Tony Mackc2835a92013-05-28 09:18:49 -0400275 def formfield_for_foreignkey(self, db_field, request, **kwargs):
276 if db_field.name == 'site':
277 if not request.user.is_admin:
278 # only show sites where user is a pi or admin
279 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
280 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
281 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
282 sites = Site.objects.filter(login_base__in=login_bases)
283 kwargs['queryset'] = sites
284
285 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
286
Tony Mack04062832013-05-10 08:22:44 -0400287 def queryset(self, request):
288 # admins can see all keys. Users can only see slices they belong to.
289 qs = super(SliceAdmin, self).queryset(request)
290 if not request.user.is_admin:
291 valid_slices = []
292 roles = request.user.get_roles()
293 for tenant_list in roles.values():
294 valid_slices.extend(tenant_list)
295 qs = qs.filter(name__in=valid_slices)
296 return qs
297
Tony Mack79748612013-05-01 14:52:03 -0400298 def get_formsets(self, request, obj=None):
299 for inline in self.get_inline_instances(request, obj):
300 # hide MyInline in the add view
301 if obj is None:
302 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400303 if isinstance(inline, SliverInline):
304 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400305 yield inline.get_formset(request, obj)
306
Tony Mackfdd4d802013-04-27 13:02:33 -0400307 def get_queryset(self, request):
308 qs = super(SliceAdmin, self).get_queryset(request)
309 if request.user.is_superuser:
310 return qs
311 # users can only see slices at their site
Tony Mack2bd5b412013-06-11 21:05:06 -0400312 return qs.filter(site=request.user.site)
313
314 def save_model(self, request, obj, form, change):
315 # update openstack connection to use this site/tenant
316 obj.caller = request.user
317 obj.save()
Tony Mackfdd4d802013-04-27 13:02:33 -0400318
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400319class SliceMembershipAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400320 fieldsets = [
321 (None, {'fields': ['user', 'slice', 'role']})
322 ]
323 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400324
Tony Mackc2835a92013-05-28 09:18:49 -0400325 def formfield_for_foreignkey(self, db_field, request, **kwargs):
326 if db_field.name == 'slice':
327 if not request.user.is_admin:
328 # only show slices at sites where caller has admin or pi role
329 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
330 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
331 sites = [site_privilege.site for site_privilege in site_privileges]
332 slices = Slice.objects.filter(site__in=sites)
333 kwargs['queryset'] = slices
334
335 if db_field.name == 'user':
336 if not request.user.is_admin:
337 # only show users from sites where caller has admin or pi role
338 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
339 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
340 sites = [site_privilege.site for site_privilege in site_privileges]
341 site_privileges = SitePrivilege.objects.filter(site__in=sites)
342 emails = [site_privilege.user.email for site_privilege in site_privileges]
343 users = User.objects.filter(email__in=emails)
344 kwargs['queryset'] = users
345
346 return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
347
Tony Mack04062832013-05-10 08:22:44 -0400348 def queryset(self, request):
349 # admins can see all memberships. Users can only see memberships of
350 # slices where they have the admin role.
351 qs = super(SliceMembershipAdmin, self).queryset(request)
352 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400353 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
354 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
355 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
356 sites = Site.objects.filter(login_base__in=login_bases)
357 slices = Slice.objects.filter(site__in=sites)
358 qs = qs.filter(slice__in=slices)
Tony Mack04062832013-05-10 08:22:44 -0400359 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400360
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400361 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400362 # update openstack connection to use this site/tenant
363 auth = request.session.get('auth', {})
364 auth['tenant'] = obj.slice.name
365 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400366 obj.save()
367
368 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400369 # update openstack connection to use this site/tenant
370 auth = request.session.get('auth', {})
371 auth['tenant'] = obj.slice.name
372 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400373 obj.delete()
374
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400375class ImageAdmin(admin.ModelAdmin):
376 fields = ['image_id', 'name', 'disk_format', 'container_format']
377
378class NodeAdmin(admin.ModelAdmin):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400379 list_display = ('name', 'site', 'deployment')
380 list_filter = ('deployment',)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400381 inlines = [TagInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400382
Tony Mackd90cdbf2013-04-16 22:48:40 -0400383class 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
Siobhan Tullyd3515752013-06-21 16:34:53 -0400393class ProjectAdmin(admin.ModelAdmin):
394 exclude = ['enacted']
395
396class TagAdmin(admin.ModelAdmin):
397 exclude = ['enacted']
398
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400399class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400400 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400401 fieldsets = [
Tony Mack10082022013-05-06 17:15:00 -0400402 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
Tony Mackcdec0902013-04-15 00:38:49 -0400403 ]
Tony Mack10082022013-05-06 17:15:00 -0400404 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400405 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400406
Tony Mackc2835a92013-05-28 09:18:49 -0400407 def formfield_for_foreignkey(self, db_field, request, **kwargs):
408 if db_field.name == 'slice':
409 if not request.user.is_admin:
410 slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)])
411 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
412
413 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
414
Tony Mack04062832013-05-10 08:22:44 -0400415 def queryset(self, request):
416 # admins can see all slivers. Users can only see slivers of
417 # the slices they belong to.
418 qs = super(SliverAdmin, self).queryset(request)
419 if not request.user.is_admin:
420 tenants = []
421 roles = request.user.get_roles()
422 for tenant_list in roles.values():
423 tenants.extend(tenant_list)
424 valid_slices = Slice.objects.filter(name__in=tenants)
425 qs = qs.filter(slice__in=valid_slices)
426 return qs
427
Tony Mack1d6b85f2013-05-07 18:49:14 -0400428 def get_formsets(self, request, obj=None):
429 # make some fields read only if we are updating an existing record
430 if obj == None:
431 #self.readonly_fields = ('ip', 'instance_name')
432 self.readonly_fields = ()
433 else:
Tony Mack1e889462013-05-10 21:34:54 -0400434 self.readonly_fields = ()
435 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400436
437 for inline in self.get_inline_instances(request, obj):
438 # hide MyInline in the add view
439 if obj is None:
440 continue
441 # give inline object access to driver and caller
442 auth = request.session.get('auth', {})
443 auth['tenant'] = obj.name # meed to connect using slice's tenant
444 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
445 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400446
447 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400448 # update openstack connection to use this site/tenant
449 auth = request.session.get('auth', {})
450 auth['tenant'] = obj.slice.name
451 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackb0d97422013-06-10 09:57:45 -0400452 obj.creator = request.user
Tony Mack53106f32013-04-27 16:43:01 -0400453 obj.save()
454
455 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400456 # update openstack connection to use this site/tenant
457 auth = request.session.get('auth', {})
458 auth['tenant'] = obj.slice.name
459 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400460 obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400461
Siobhan Tully53437282013-04-26 19:30:27 -0400462class UserCreationForm(forms.ModelForm):
463 """A form for creating new users. Includes all the required
464 fields, plus a repeated password."""
465 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
466 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
467
468 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400469 model = User
Tony Mackb0d97422013-06-10 09:57:45 -0400470 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site')
Siobhan Tully53437282013-04-26 19:30:27 -0400471
472 def clean_password2(self):
473 # Check that the two password entries match
474 password1 = self.cleaned_data.get("password1")
475 password2 = self.cleaned_data.get("password2")
476 if password1 and password2 and password1 != password2:
477 raise forms.ValidationError("Passwords don't match")
478 return password2
479
480 def save(self, commit=True):
481 # Save the provided password in hashed format
482 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400483 user.password = self.cleaned_data["password1"]
484 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400485 if commit:
486 user.save()
487 return user
488
Siobhan Tully53437282013-04-26 19:30:27 -0400489class UserChangeForm(forms.ModelForm):
490 """A form for updating users. Includes all the fields on
491 the user, but replaces the password field with admin's
492 password hash display field.
493 """
494 password = ReadOnlyPasswordHashField()
495
496 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400497 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400498
499 def clean_password(self):
500 # Regardless of what the user provides, return the initial value.
501 # This is done here, rather than on the field, because the
502 # field does not have access to the initial value
503 return self.initial["password"]
504
Tony Mack2bd5b412013-06-11 21:05:06 -0400505class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400506 class Meta:
507 app_label = "core"
508
509 # The forms to add and change user instances
510 form = UserChangeForm
511 add_form = UserCreationForm
512
513 # The fields to be used in displaying the User model.
514 # These override the definitions on the base UserAdmin
515 # that reference specific fields on auth.User.
Tony Mack416c0f22013-05-09 16:59:09 -0400516 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tully53437282013-04-26 19:30:27 -0400517 list_filter = ('site',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400518 inlines = [SitePrivilegeInline, SliceMembershipInline]
Siobhan Tully53437282013-04-26 19:30:27 -0400519 fieldsets = (
Scott Baker9266e6b2013-05-19 15:54:48 -0700520 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
Tony Mackb0d97422013-06-10 09:57:45 -0400521 ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}),
Siobhan Tully53437282013-04-26 19:30:27 -0400522 #('Important dates', {'fields': ('last_login',)}),
523 )
524 add_fieldsets = (
525 (None, {
526 'classes': ('wide',),
Tony Mackb0d97422013-06-10 09:57:45 -0400527 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')}
Siobhan Tully53437282013-04-26 19:30:27 -0400528 ),
529 )
530 search_fields = ('email',)
531 ordering = ('email',)
532 filter_horizontal = ()
533
Tony Mackc2835a92013-05-28 09:18:49 -0400534 def formfield_for_foreignkey(self, db_field, request, **kwargs):
535 if db_field.name == 'site':
536 if not request.user.is_admin:
537 # show sites where caller is an admin or pi
538 sites = []
539 for site_privilege in SitePrivilege.objects.filer(user=request.user):
540 if site_privilege.role.role_type in ['admin', 'pi']:
541 sites.append(site_privilege.site.login_base)
542 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
543
544 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
545
Scott Baker3de3e372013-05-10 16:50:44 -0700546class ServiceResourceInline(admin.TabularInline):
547 model = ServiceResource
548 extra = 0
549
550class ServiceClassAdmin(admin.ModelAdmin):
551 list_display = ('name', 'commitment', 'membershipFee')
552 inlines = [ServiceResourceInline]
553
Scott Baker133c9212013-05-17 09:09:11 -0700554class ReservedResourceInline(admin.TabularInline):
555 model = ReservedResource
556 extra = 0
557
558 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
559 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
560
561 if db_field.name == 'resource':
562 # restrict resources to those that the slice's service class allows
563 if request._slice is not None:
564 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
565 if len(field.queryset) > 0:
566 field.initial = field.queryset.all()[0]
567 else:
568 field.queryset = field.queryset.none()
569 elif db_field.name == 'sliver':
570 # restrict slivers to those that belong to the slice
571 if request._slice is not None:
572 field.queryset = field.queryset.filter(slice = request._slice)
573 else:
574 field.queryset = field.queryset.none()
575
576 return field
577
578class ReservationChangeForm(forms.ModelForm):
579 class Meta:
580 model = Reservation
581
582class ReservationAddForm(forms.ModelForm):
583 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
584 refresh = forms.CharField(widget=forms.HiddenInput())
585
586 class Media:
587 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
588
589 def clean_slice(self):
590 slice = self.cleaned_data.get("slice")
591 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
592 if len(x) == 0:
593 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
594 return slice
595
596 class Meta:
597 model = Reservation
598
599class ReservationAddRefreshForm(ReservationAddForm):
600 """ This form is displayed when the Reservation Form receives an update
601 from the Slice dropdown onChange handler. It doesn't validate the
602 data and doesn't save the data. This will cause the form to be
603 redrawn.
604 """
605
Scott Baker8737e5f2013-05-17 09:35:32 -0700606 """ don't validate anything other than slice """
607 dont_validate_fields = ("startTime", "duration")
608
Scott Baker133c9212013-05-17 09:09:11 -0700609 def full_clean(self):
610 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -0700611
612 for fieldname in self.dont_validate_fields:
613 if fieldname in self._errors:
614 del self._errors[fieldname]
615
Scott Baker133c9212013-05-17 09:09:11 -0700616 return result
617
618 """ don't save anything """
619 def is_valid(self):
620 return False
621
622class ReservationAdmin(admin.ModelAdmin):
623 list_display = ('startTime', 'duration')
624 inlines = [ReservedResourceInline]
625 form = ReservationAddForm
626
627 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -0700628 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -0700629 request._refresh = False
630 request._slice = None
631 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -0700632 # "refresh" will be set to "1" if the form was submitted due to
633 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -0700634 if request.POST.get("refresh","1") == "1":
635 request._refresh = True
636 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -0700637
638 # Keep track of the slice that was selected, so the
639 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -0700640 request._slice = request.POST.get("slice",None)
641 if (request._slice is not None):
642 request._slice = Slice.objects.get(id=request._slice)
643
644 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
645 return result
646
Scott Bakeracd45142013-05-19 16:19:16 -0700647 def changelist_view(self, request, extra_context = None):
648 timezone.activate(request.user.timezone)
649 return super(ReservationAdmin, self).changelist_view(request, extra_context)
650
Scott Baker133c9212013-05-17 09:09:11 -0700651 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -0400652 request._obj_ = obj
653 if obj is not None:
654 # For changes, set request._slice to the slice already set in the
655 # object.
656 request._slice = obj.slice
657 self.form = ReservationChangeForm
658 else:
659 if getattr(request, "_refresh", False):
660 self.form = ReservationAddRefreshForm
661 else:
662 self.form = ReservationAddForm
663 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
664
Scott Baker133c9212013-05-17 09:09:11 -0700665 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -0400666 if (obj is not None):
667 # Prevent slice from being changed after the reservation has been
668 # created.
669 return ['slice']
670 else:
Scott Baker133c9212013-05-17 09:09:11 -0700671 return []
Scott Baker3de3e372013-05-10 16:50:44 -0700672
Tony Mack31c2b8f2013-04-26 20:01:42 -0400673# register a signal that caches the user's credentials when they log in
674def cache_credentials(sender, user, request, **kwds):
675 auth = {'username': request.POST['username'],
676 'password': request.POST['password']}
677 request.session['auth'] = auth
678user_logged_in.connect(cache_credentials)
679
Siobhan Tully53437282013-04-26 19:30:27 -0400680# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -0400681admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -0400682# ... and, since we're not using Django's builtin permissions,
683# unregister the Group model from admin.
684admin.site.unregister(Group)
685
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400686#Do not show django evolution in the admin interface
687from django_evolution.models import Version, Evolution
688admin.site.unregister(Version)
689admin.site.unregister(Evolution)
690
691
692# When debugging it is often easier to see all the classes, but for regular use
693# only the top-levels should be displayed
694showAll = False
695
696admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400697admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400698admin.site.register(Slice, SliceAdmin)
Siobhan Tullyd3515752013-06-21 16:34:53 -0400699admin.site.register(Project, ProjectAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400700
701if showAll:
Siobhan Tullyd3515752013-06-21 16:34:53 -0400702 admin.site.register(Tag, TagAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400703 admin.site.register(Node, NodeAdmin)
704 admin.site.register(SliceMembership, SliceMembershipAdmin)
705 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
706 admin.site.register(Role, RoleAdmin)
707 admin.site.register(Sliver, SliverAdmin)
708 admin.site.register(ServiceClass, ServiceClassAdmin)
709 admin.site.register(Reservation, ReservationAdmin)
710 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -0400711