blob: 60a589cb9f564796b7e0feaf84da845d35179b27 [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 Tully567e3e62013-06-21 18:03:16 -040049
Siobhan Tullyd3515752013-06-21 16:34:53 -040050class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -040051 model = Site
52 extra = 0
53
Siobhan Tullyd3515752013-06-21 16:34:53 -040054class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -040055 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -040056 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -040057 extra = 0
58
Siobhan Tullyd3515752013-06-21 16:34:53 -040059class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -040060 model = Slice
61 extra = 0
62
Siobhan Tullyd3515752013-06-21 16:34:53 -040063class RoleInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -040064 model = Role
65 extra = 0
66
Siobhan Tullyd3515752013-06-21 16:34:53 -040067class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -040068 model = Node
69 extra = 0
70
Siobhan Tullyd3515752013-06-21 16:34:53 -040071class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040072 model = SitePrivilege
73 extra = 0
74
Tony Mackc2835a92013-05-28 09:18:49 -040075 def formfield_for_foreignkey(self, db_field, request, **kwargs):
76 if db_field.name == 'site':
77 if not request.user.is_admin:
78 # only show sites where user is an admin or pi
79 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
80 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
81 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
82 sites = Site.objects.filter(login_base__in=login_bases)
83 kwargs['queryset'] = sites
84
85 if db_field.name == 'user':
86 if not request.user.is_admin:
87 # only show users from sites where caller has admin or pi role
88 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
89 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
90 sites = [site_privilege.site for site_privilege in site_privileges]
91 site_privileges = SitePrivilege.objects.filter(site__in=sites)
92 emails = [site_privilege.user.email for site_privilege in site_privileges]
93 users = User.objects.filter(email__in=emails)
94 kwargs['queryset'] = users
95 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
96
Siobhan Tullyd3515752013-06-21 16:34:53 -040097class SliceMembershipInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040098 model = SliceMembership
99 extra = 0
Tony Mack2bd5b412013-06-11 21:05:06 -0400100 fields = ('user', 'role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400101
Tony Mackc2835a92013-05-28 09:18:49 -0400102 def formfield_for_foreignkey(self, db_field, request, **kwargs):
103 if db_field.name == 'slice':
104 if not request.user.is_admin:
105 # only show slices at sites where caller has admin or pi role
106 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
107 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
108 sites = [site_privilege.site for site_privilege in site_privileges]
109 slices = Slice.objects.filter(site__in=sites)
110 kwargs['queryset'] = slices
111 if db_field.name == 'user':
112 if not request.user.is_admin:
113 # only show users from sites where caller has admin or pi role
114 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
115 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
116 sites = [site_privilege.site for site_privilege in site_privileges]
117 site_privileges = SitePrivilege.objects.filter(site__in=sites)
118 emails = [site_privilege.user.email for site_privilege in site_privileges]
119 users = User.objects.filter(email__in=emails)
120 kwargs['queryset'] = list(users)
121
122 return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
123
Siobhan Tullyd3515752013-06-21 16:34:53 -0400124class SliceTagInline(PlStackTabularInline):
Scott Baker307e06f2013-05-21 17:25:56 -0700125 model = SliceTag
126 extra = 0
127
Tony Mack5e71a662013-05-03 23:30:41 -0400128class PlainTextWidget(forms.HiddenInput):
129 input_type = 'hidden'
130
131 def render(self, name, value, attrs=None):
132 if value is None:
133 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400134 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400135
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400136class PlanetStackBaseAdmin(admin.ModelAdmin):
137 save_on_top = False
Siobhan Tullyd3515752013-06-21 16:34:53 -0400138 exclude = ['enacted']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400139
Tony Mack0553f282013-06-10 22:54:50 -0400140class RoleAdmin(PlanetStackBaseAdmin):
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400141 fieldsets = [
142 ('Role', {'fields': ['role_type']})
143 ]
144 list_display = ('role_type',)
Tony Mackfdd4d802013-04-27 13:02:33 -0400145
Siobhan Tully567e3e62013-06-21 18:03:16 -0400146
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400147class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400148 sites = forms.ModelMultipleChoiceField(
149 queryset=Site.objects.all(),
150 required=False,
151 widget=FilteredSelectMultiple(
152 verbose_name=('Sites'), is_stacked=False
153 )
154 )
155 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400156 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400157
158 def __init__(self, *args, **kwargs):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400159 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400160
161 if self.instance and self.instance.pk:
162 self.fields['sites'].initial = self.instance.sites.all()
163
164 def save(self, commit=True):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400165 deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400166 if commit:
167 deploymentNetwork.save()
168
169 if deploymentNetwork.pk:
170 deploymentNetwork.sites = self.cleaned_data['sites']
171 self.save_m2m()
172
173 return deploymentNetwork
174
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400175class DeploymentAdmin(PlanetStackBaseAdmin):
176 form = DeploymentAdminForm
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400177 inlines = [NodeInline,SliverInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400178
Tony Mack5cd13202013-05-01 21:48:38 -0400179 def get_formsets(self, request, obj=None):
180 for inline in self.get_inline_instances(request, obj):
181 # hide MyInline in the add view
182 if obj is None:
183 continue
184 # give inline object access to driver and caller
Tony Macked163d72013-05-02 20:05:42 -0400185 auth = request.session.get('auth', {})
Siobhan Tully73291342013-05-10 10:50:08 -0400186 if request.user.site:
187 auth['tenant'] = request.user.site.login_base
Tony Macked163d72013-05-02 20:05:42 -0400188 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400189 yield inline.get_formset(request, obj)
190
Tony Mack0553f282013-06-10 22:54:50 -0400191class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400192 fieldsets = [
Siobhan Tully567e3e62013-06-21 18:03:16 -0400193 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'location']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400194 ('Deployment Networks', {'fields': ['deployments']})
195 ]
196 list_display = ('name', 'login_base','site_url', 'enabled')
197 filter_horizontal = ('deployments',)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400198 inlines = [TagInline, NodeInline, UserInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400199 search_fields = ['name']
200
Tony Mack04062832013-05-10 08:22:44 -0400201 def queryset(self, request):
202 # admins can see all keys. Users can only see sites they belong to.
203 qs = super(SiteAdmin, self).queryset(request)
204 if not request.user.is_admin:
205 valid_sites = [request.user.site.login_base]
206 roles = request.user.get_roles()
207 for tenant_list in roles.values():
208 valid_sites.extend(tenant_list)
209 qs = qs.filter(login_base__in=valid_sites)
210 return qs
211
Tony Mack5cd13202013-05-01 21:48:38 -0400212 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
Tony Mack2bd5b412013-06-11 21:05:06 -0400217 if isinstance(inline, SliceInline):
218 inline.model.caller = request.user
219 yield inline.get_formset(request, obj)
220
221 def get_formsets(self, request, obj=None):
222 for inline in self.get_inline_instances(request, obj):
223 # hide MyInline in the add view
224 if obj is None:
225 continue
226 if isinstance(inline, SliverInline):
227 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400228 yield inline.get_formset(request, obj)
229
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400230class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400231 fieldsets = [
232 (None, {'fields': ['user', 'site', 'role']})
233 ]
234 list_display = ('user', 'site', 'role')
235
Tony Mackc2835a92013-05-28 09:18:49 -0400236 def formfield_for_foreignkey(self, db_field, request, **kwargs):
237 if db_field.name == 'site':
238 if not request.user.is_admin:
239 # only show sites where user is an admin or pi
240 sites = set()
241 for site_privilege in SitePrivilege.objects.filer(user=request.user):
242 if site_privilege.role.role_type in ['admin', 'pi']:
243 sites.add(site_privilege.site)
244 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
245
246 if db_field.name == 'user':
247 if not request.user.is_admin:
248 # only show users from sites where caller has admin or pi role
249 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
250 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
251 sites = [site_privilege.site for site_privilege in site_privileges]
252 site_privileges = SitePrivilege.objects.filter(site__in=sites)
253 emails = [site_privilege.user.email for site_privilege in site_privileges]
254 users = User.objects.filter(email__in=emails)
255 kwargs['queryset'] = users
256
257 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
258
Tony Mack04062832013-05-10 08:22:44 -0400259 def queryset(self, request):
260 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400261 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400262 qs = super(SitePrivilegeAdmin, self).queryset(request)
263 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400264 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
265 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
266 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
267 sites = Site.objects.filter(login_base__in=login_bases)
268 qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400269 return qs
270
Tony Mack2bd5b412013-06-11 21:05:06 -0400271class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400272 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
273 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400274 inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400275
Tony Mackc2835a92013-05-28 09:18:49 -0400276 def formfield_for_foreignkey(self, db_field, request, **kwargs):
277 if db_field.name == 'site':
278 if not request.user.is_admin:
279 # only show sites where user is a pi or admin
280 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
281 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
282 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
283 sites = Site.objects.filter(login_base__in=login_bases)
284 kwargs['queryset'] = sites
285
286 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
287
Tony Mack04062832013-05-10 08:22:44 -0400288 def queryset(self, request):
289 # admins can see all keys. Users can only see slices they belong to.
290 qs = super(SliceAdmin, self).queryset(request)
291 if not request.user.is_admin:
292 valid_slices = []
293 roles = request.user.get_roles()
294 for tenant_list in roles.values():
295 valid_slices.extend(tenant_list)
296 qs = qs.filter(name__in=valid_slices)
297 return qs
298
Tony Mack79748612013-05-01 14:52:03 -0400299 def get_formsets(self, request, obj=None):
300 for inline in self.get_inline_instances(request, obj):
301 # hide MyInline in the add view
302 if obj is None:
303 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400304 if isinstance(inline, SliverInline):
305 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400306 yield inline.get_formset(request, obj)
307
Tony Mackfdd4d802013-04-27 13:02:33 -0400308 def get_queryset(self, request):
309 qs = super(SliceAdmin, self).get_queryset(request)
310 if request.user.is_superuser:
311 return qs
312 # users can only see slices at their site
Tony Mack2bd5b412013-06-11 21:05:06 -0400313 return qs.filter(site=request.user.site)
314
315 def save_model(self, request, obj, form, change):
316 # update openstack connection to use this site/tenant
317 obj.caller = request.user
318 obj.save()
Tony Mackfdd4d802013-04-27 13:02:33 -0400319
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400320class SliceMembershipAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400321 fieldsets = [
322 (None, {'fields': ['user', 'slice', 'role']})
323 ]
324 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400325
Tony Mackc2835a92013-05-28 09:18:49 -0400326 def formfield_for_foreignkey(self, db_field, request, **kwargs):
327 if db_field.name == 'slice':
328 if not request.user.is_admin:
329 # only show slices at 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 slices = Slice.objects.filter(site__in=sites)
334 kwargs['queryset'] = slices
335
336 if db_field.name == 'user':
337 if not request.user.is_admin:
338 # only show users from sites where caller has admin or pi role
339 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
340 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
341 sites = [site_privilege.site for site_privilege in site_privileges]
342 site_privileges = SitePrivilege.objects.filter(site__in=sites)
343 emails = [site_privilege.user.email for site_privilege in site_privileges]
344 users = User.objects.filter(email__in=emails)
345 kwargs['queryset'] = users
346
347 return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
348
Tony Mack04062832013-05-10 08:22:44 -0400349 def queryset(self, request):
350 # admins can see all memberships. Users can only see memberships of
351 # slices where they have the admin role.
352 qs = super(SliceMembershipAdmin, self).queryset(request)
353 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400354 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
355 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
356 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
357 sites = Site.objects.filter(login_base__in=login_bases)
358 slices = Slice.objects.filter(site__in=sites)
359 qs = qs.filter(slice__in=slices)
Tony Mack04062832013-05-10 08:22:44 -0400360 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400361
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400362 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400363 # update openstack connection to use this site/tenant
364 auth = request.session.get('auth', {})
365 auth['tenant'] = obj.slice.name
366 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400367 obj.save()
368
369 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400370 # update openstack connection to use this site/tenant
371 auth = request.session.get('auth', {})
372 auth['tenant'] = obj.slice.name
373 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400374 obj.delete()
375
Siobhan Tully567e3e62013-06-21 18:03:16 -0400376
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400377class ImageAdmin(admin.ModelAdmin):
378 fields = ['image_id', 'name', 'disk_format', 'container_format']
379
380class NodeAdmin(admin.ModelAdmin):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400381 list_display = ('name', 'site', 'deployment')
382 list_filter = ('deployment',)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400383 inlines = [TagInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400384
Siobhan Tully567e3e62013-06-21 18:03:16 -0400385
Tony Mackd90cdbf2013-04-16 22:48:40 -0400386class SliverForm(forms.ModelForm):
387 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400388 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400389 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400390 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400391 widgets = {
392 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400393 'instance_name': PlainTextWidget(),
Siobhan Tully53437282013-04-26 19:30:27 -0400394 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400395
Siobhan Tullyd3515752013-06-21 16:34:53 -0400396class ProjectAdmin(admin.ModelAdmin):
397 exclude = ['enacted']
398
399class TagAdmin(admin.ModelAdmin):
400 exclude = ['enacted']
401
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400402class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400403 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400404 fieldsets = [
Tony Mack10082022013-05-06 17:15:00 -0400405 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
Tony Mackcdec0902013-04-15 00:38:49 -0400406 ]
Tony Mack10082022013-05-06 17:15:00 -0400407 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400408 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400409
Tony Mackc2835a92013-05-28 09:18:49 -0400410 def formfield_for_foreignkey(self, db_field, request, **kwargs):
411 if db_field.name == 'slice':
412 if not request.user.is_admin:
413 slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)])
414 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
415
416 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
417
Tony Mack04062832013-05-10 08:22:44 -0400418 def queryset(self, request):
419 # admins can see all slivers. Users can only see slivers of
420 # the slices they belong to.
421 qs = super(SliverAdmin, self).queryset(request)
422 if not request.user.is_admin:
423 tenants = []
424 roles = request.user.get_roles()
425 for tenant_list in roles.values():
426 tenants.extend(tenant_list)
427 valid_slices = Slice.objects.filter(name__in=tenants)
428 qs = qs.filter(slice__in=valid_slices)
429 return qs
430
Tony Mack1d6b85f2013-05-07 18:49:14 -0400431 def get_formsets(self, request, obj=None):
432 # make some fields read only if we are updating an existing record
433 if obj == None:
434 #self.readonly_fields = ('ip', 'instance_name')
435 self.readonly_fields = ()
436 else:
Tony Mack1e889462013-05-10 21:34:54 -0400437 self.readonly_fields = ()
438 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400439
440 for inline in self.get_inline_instances(request, obj):
441 # hide MyInline in the add view
442 if obj is None:
443 continue
444 # give inline object access to driver and caller
445 auth = request.session.get('auth', {})
446 auth['tenant'] = obj.name # meed to connect using slice's tenant
447 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
448 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400449
450 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400451 # update openstack connection to use this site/tenant
452 auth = request.session.get('auth', {})
453 auth['tenant'] = obj.slice.name
454 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackb0d97422013-06-10 09:57:45 -0400455 obj.creator = request.user
Tony Mack53106f32013-04-27 16:43:01 -0400456 obj.save()
457
458 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400459 # update openstack connection to use this site/tenant
460 auth = request.session.get('auth', {})
461 auth['tenant'] = obj.slice.name
462 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400463 obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400464
Siobhan Tully53437282013-04-26 19:30:27 -0400465class UserCreationForm(forms.ModelForm):
466 """A form for creating new users. Includes all the required
467 fields, plus a repeated password."""
468 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
469 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
470
471 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400472 model = User
Tony Mackb0d97422013-06-10 09:57:45 -0400473 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site')
Siobhan Tully53437282013-04-26 19:30:27 -0400474
475 def clean_password2(self):
476 # Check that the two password entries match
477 password1 = self.cleaned_data.get("password1")
478 password2 = self.cleaned_data.get("password2")
479 if password1 and password2 and password1 != password2:
480 raise forms.ValidationError("Passwords don't match")
481 return password2
482
483 def save(self, commit=True):
484 # Save the provided password in hashed format
485 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400486 user.password = self.cleaned_data["password1"]
487 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400488 if commit:
489 user.save()
490 return user
491
Siobhan Tully567e3e62013-06-21 18:03:16 -0400492
Siobhan Tully53437282013-04-26 19:30:27 -0400493class UserChangeForm(forms.ModelForm):
494 """A form for updating users. Includes all the fields on
495 the user, but replaces the password field with admin's
496 password hash display field.
497 """
498 password = ReadOnlyPasswordHashField()
499
500 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400501 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400502
503 def clean_password(self):
504 # Regardless of what the user provides, return the initial value.
505 # This is done here, rather than on the field, because the
506 # field does not have access to the initial value
507 return self.initial["password"]
508
Siobhan Tully567e3e62013-06-21 18:03:16 -0400509
Tony Mack2bd5b412013-06-11 21:05:06 -0400510class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400511 class Meta:
512 app_label = "core"
513
514 # The forms to add and change user instances
515 form = UserChangeForm
516 add_form = UserCreationForm
517
518 # The fields to be used in displaying the User model.
519 # These override the definitions on the base UserAdmin
520 # that reference specific fields on auth.User.
Tony Mack416c0f22013-05-09 16:59:09 -0400521 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tully53437282013-04-26 19:30:27 -0400522 list_filter = ('site',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400523 inlines = [SitePrivilegeInline, SliceMembershipInline]
Siobhan Tully53437282013-04-26 19:30:27 -0400524 fieldsets = (
Scott Baker9266e6b2013-05-19 15:54:48 -0700525 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
Tony Mackb0d97422013-06-10 09:57:45 -0400526 ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}),
Siobhan Tully53437282013-04-26 19:30:27 -0400527 #('Important dates', {'fields': ('last_login',)}),
528 )
529 add_fieldsets = (
530 (None, {
531 'classes': ('wide',),
Tony Mackb0d97422013-06-10 09:57:45 -0400532 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')}
Siobhan Tully53437282013-04-26 19:30:27 -0400533 ),
534 )
535 search_fields = ('email',)
536 ordering = ('email',)
537 filter_horizontal = ()
538
Tony Mackc2835a92013-05-28 09:18:49 -0400539 def formfield_for_foreignkey(self, db_field, request, **kwargs):
540 if db_field.name == 'site':
541 if not request.user.is_admin:
542 # show sites where caller is an admin or pi
543 sites = []
544 for site_privilege in SitePrivilege.objects.filer(user=request.user):
545 if site_privilege.role.role_type in ['admin', 'pi']:
546 sites.append(site_privilege.site.login_base)
547 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
548
549 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
550
Scott Baker3de3e372013-05-10 16:50:44 -0700551class ServiceResourceInline(admin.TabularInline):
552 model = ServiceResource
553 extra = 0
554
555class ServiceClassAdmin(admin.ModelAdmin):
556 list_display = ('name', 'commitment', 'membershipFee')
557 inlines = [ServiceResourceInline]
558
Scott Baker133c9212013-05-17 09:09:11 -0700559class ReservedResourceInline(admin.TabularInline):
smbakera3cf70c2013-06-27 02:01:41 -0700560 exclude = ['enacted']
Scott Baker133c9212013-05-17 09:09:11 -0700561 model = ReservedResource
562 extra = 0
563
564 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
565 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
566
567 if db_field.name == 'resource':
568 # restrict resources to those that the slice's service class allows
569 if request._slice is not None:
570 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
571 if len(field.queryset) > 0:
572 field.initial = field.queryset.all()[0]
573 else:
574 field.queryset = field.queryset.none()
575 elif db_field.name == 'sliver':
576 # restrict slivers to those that belong to the slice
577 if request._slice is not None:
578 field.queryset = field.queryset.filter(slice = request._slice)
579 else:
580 field.queryset = field.queryset.none()
581
582 return field
583
584class ReservationChangeForm(forms.ModelForm):
585 class Meta:
586 model = Reservation
587
588class ReservationAddForm(forms.ModelForm):
589 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
590 refresh = forms.CharField(widget=forms.HiddenInput())
591
592 class Media:
593 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
594
595 def clean_slice(self):
596 slice = self.cleaned_data.get("slice")
597 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
598 if len(x) == 0:
599 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
600 return slice
601
602 class Meta:
603 model = Reservation
604
605class ReservationAddRefreshForm(ReservationAddForm):
606 """ This form is displayed when the Reservation Form receives an update
607 from the Slice dropdown onChange handler. It doesn't validate the
608 data and doesn't save the data. This will cause the form to be
609 redrawn.
610 """
611
Scott Baker8737e5f2013-05-17 09:35:32 -0700612 """ don't validate anything other than slice """
613 dont_validate_fields = ("startTime", "duration")
614
Scott Baker133c9212013-05-17 09:09:11 -0700615 def full_clean(self):
616 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -0700617
618 for fieldname in self.dont_validate_fields:
619 if fieldname in self._errors:
620 del self._errors[fieldname]
621
Scott Baker133c9212013-05-17 09:09:11 -0700622 return result
623
624 """ don't save anything """
625 def is_valid(self):
626 return False
627
628class ReservationAdmin(admin.ModelAdmin):
smbakera3cf70c2013-06-27 02:01:41 -0700629 exclude = ['enacted']
Scott Baker133c9212013-05-17 09:09:11 -0700630 list_display = ('startTime', 'duration')
631 inlines = [ReservedResourceInline]
632 form = ReservationAddForm
633
634 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -0700635 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -0700636 request._refresh = False
637 request._slice = None
638 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -0700639 # "refresh" will be set to "1" if the form was submitted due to
640 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -0700641 if request.POST.get("refresh","1") == "1":
642 request._refresh = True
643 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -0700644
645 # Keep track of the slice that was selected, so the
646 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -0700647 request._slice = request.POST.get("slice",None)
648 if (request._slice is not None):
649 request._slice = Slice.objects.get(id=request._slice)
650
651 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
652 return result
653
Scott Bakeracd45142013-05-19 16:19:16 -0700654 def changelist_view(self, request, extra_context = None):
655 timezone.activate(request.user.timezone)
656 return super(ReservationAdmin, self).changelist_view(request, extra_context)
657
Scott Baker133c9212013-05-17 09:09:11 -0700658 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -0400659 request._obj_ = obj
660 if obj is not None:
661 # For changes, set request._slice to the slice already set in the
662 # object.
663 request._slice = obj.slice
664 self.form = ReservationChangeForm
665 else:
666 if getattr(request, "_refresh", False):
667 self.form = ReservationAddRefreshForm
668 else:
669 self.form = ReservationAddForm
670 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
671
Scott Baker133c9212013-05-17 09:09:11 -0700672 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -0400673 if (obj is not None):
674 # Prevent slice from being changed after the reservation has been
675 # created.
676 return ['slice']
677 else:
Scott Baker133c9212013-05-17 09:09:11 -0700678 return []
Scott Baker3de3e372013-05-10 16:50:44 -0700679
Tony Mack31c2b8f2013-04-26 20:01:42 -0400680# register a signal that caches the user's credentials when they log in
681def cache_credentials(sender, user, request, **kwds):
682 auth = {'username': request.POST['username'],
683 'password': request.POST['password']}
684 request.session['auth'] = auth
685user_logged_in.connect(cache_credentials)
686
Siobhan Tully53437282013-04-26 19:30:27 -0400687# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -0400688admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -0400689# ... and, since we're not using Django's builtin permissions,
690# unregister the Group model from admin.
691admin.site.unregister(Group)
692
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400693#Do not show django evolution in the admin interface
694from django_evolution.models import Version, Evolution
695admin.site.unregister(Version)
696admin.site.unregister(Evolution)
697
698
699# When debugging it is often easier to see all the classes, but for regular use
700# only the top-levels should be displayed
701showAll = False
702
703admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400704admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400705admin.site.register(Slice, SliceAdmin)
Siobhan Tullyd3515752013-06-21 16:34:53 -0400706admin.site.register(Project, ProjectAdmin)
smbaker43591c32013-06-26 12:43:53 -0700707admin.site.register(ServiceClass, ServiceClassAdmin)
smbakera3cf70c2013-06-27 02:01:41 -0700708admin.site.register(Reservation, ReservationAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400709
710if showAll:
Siobhan Tullyd3515752013-06-21 16:34:53 -0400711 admin.site.register(Tag, TagAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400712 admin.site.register(Node, NodeAdmin)
713 admin.site.register(SliceMembership, SliceMembershipAdmin)
714 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
715 admin.site.register(Role, RoleAdmin)
716 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400717 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -0400718