blob: 988a766cecf5e3650d2ee6f57330e9d835cb0bd4 [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
Scott Baker545db2a2013-12-09 18:44:43 -080015from django.core.urlresolvers import reverse
Siobhan Tullybfd11dc2013-09-03 12:59:24 -040016from suit.widgets import LinkedSelect
Tony Mack7130ac32013-03-22 21:58:00 -040017
Siobhan Tullyde5450d2013-06-21 11:35:33 -040018import django_evolution
Siobhan Tully4bc09f22013-04-10 21:15:21 -040019
Siobhan Tullyce652d02013-10-08 21:52:35 -040020class SingletonAdmin (admin.ModelAdmin):
21 def has_add_permission(self, request):
22 num_objects = self.model.objects.count()
23 if num_objects >= 1:
24 return False
25 else:
26 return True
27
28
Siobhan Tullyd3515752013-06-21 16:34:53 -040029class PlStackTabularInline(admin.TabularInline):
Siobhan Tully2c780ad2013-09-06 11:22:40 -040030 pass
Siobhan Tullyd3515752013-06-21 16:34:53 -040031
Siobhan Tullybfd11dc2013-09-03 12:59:24 -040032class ReservationInline(PlStackTabularInline):
33 model = Reservation
34 extra = 0
35 suit_classes = 'suit-tab suit-tab-reservations'
36
37
Siobhan Tullyd3515752013-06-21 16:34:53 -040038class ReadonlyTabularInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -040039 can_delete = False
40 extra = 0
41 editable_fields = []
42
43 def get_readonly_fields(self, request, obj=None):
44 fields = []
45 for field in self.model._meta.get_all_field_names():
46 if (not field == 'id'):
47 if (field not in self.editable_fields):
48 fields.append(field)
49 return fields
50
51 def has_add_permission(self, request):
52 return False
53
Siobhan Tullyde5450d2013-06-21 11:35:33 -040054class TagInline(generic.GenericTabularInline):
55 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -040056 extra = 0
57 suit_classes = 'suit-tab suit-tab-tags'
Siobhan Tullyde5450d2013-06-21 11:35:33 -040058
Scott Baker74d8e622013-07-29 16:04:22 -070059class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -040060 """ This is a callable that looks up a network name in a sliver and returns
61 the ip address for that network.
62 """
63
64 def __init__(self, name):
65 self.short_description = name
66 self.__name__ = name
67 self.network_name = name
68
69 def __call__(self, obj):
70 if obj is not None:
71 for nbs in obj.networksliver_set.all():
72 if (nbs.network.name == self.network_name):
73 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -070074 return ""
75
76 def __str__(self):
77 return self.network_name
78
Siobhan Tullyd3515752013-06-21 16:34:53 -040079class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -040080 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -040081 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040082 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -040083 readonly_fields = ['ip', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -040084 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -070085
Siobhan Tully2d95e482013-09-06 10:56:06 -040086# Note this is breaking in the admin.py when trying to use an inline to add a node/image
87# def _declared_fieldsets(self):
88# # Return None so django will call get_fieldsets and we can insert our
89# # dynamic fields
90# return None
91#
92# def get_readonly_fields(self, request, obj=None):
93# readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
94#
95# # Lookup the networks that are bound to the slivers, and add those
96# # network names to the list of readonly fields.
97#
98# for sliver in obj.slivers.all():
99# for nbs in sliver.networksliver_set.all():
100# if nbs.ip:
101# network_name = nbs.network.name
102# if network_name not in [str(x) for x in readonly_fields]:
103# readonly_fields.append(NetworkLookerUpper(network_name))
104#
105# return readonly_fields
106#
107# def get_fieldsets(self, request, obj=None):
108# form = self.get_formset(request, obj).form
109# # fields = the read/write files + the read-only fields
110# fields = self.fields
111# for fieldName in self.get_readonly_fields(request,obj):
112# if not fieldName in fields:
113# fields.append(fieldName)
114#
115# return [(None, {'fields': fields})]
Scott Baker74d8e622013-07-29 16:04:22 -0700116
Tony Mackc2835a92013-05-28 09:18:49 -0400117
Siobhan Tully567e3e62013-06-21 18:03:16 -0400118
Siobhan Tullyd3515752013-06-21 16:34:53 -0400119class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400120 model = Site
121 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400122 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400123
Siobhan Tullyd3515752013-06-21 16:34:53 -0400124class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400125 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400126 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -0400127 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400128 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400129
Siobhan Tullyd3515752013-06-21 16:34:53 -0400130class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400131 model = Slice
Siobhan Tullyce652d02013-10-08 21:52:35 -0400132 fields = ['name','site', 'serviceClass', 'service']
Tony Mack00d361f2013-04-28 10:28:42 -0400133 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400134 suit_classes = 'suit-tab suit-tab-slices'
135
Tony Mack00d361f2013-04-28 10:28:42 -0400136
Siobhan Tullyd3515752013-06-21 16:34:53 -0400137class RoleInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400138 model = Role
139 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400140 suit_classes = 'suit-tab suit-tab-roles'
Tony Mack00d361f2013-04-28 10:28:42 -0400141
Siobhan Tullyd3515752013-06-21 16:34:53 -0400142class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400143 model = Node
144 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400145 suit_classes = 'suit-tab suit-tab-nodes'
146
147class SlicePrivilegeInline(PlStackTabularInline):
148 model = SlicePrivilege
149 extra = 0
150 suit_classes = 'suit-tab suit-tab-sliceprivileges'
151
152class DeploymentPrivilegeInline(PlStackTabularInline):
153 model = DeploymentPrivilege
154 extra = 0
155 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400156
Siobhan Tullyd3515752013-06-21 16:34:53 -0400157class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400158 model = SitePrivilege
159 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400160 suit_classes = 'suit-tab suit-tab-siteprivileges'
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400161
Tony Mackc2835a92013-05-28 09:18:49 -0400162 def formfield_for_foreignkey(self, db_field, request, **kwargs):
163 if db_field.name == 'site':
164 if not request.user.is_admin:
165 # only show sites where user is an admin or pi
166 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
167 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
168 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
169 sites = Site.objects.filter(login_base__in=login_bases)
170 kwargs['queryset'] = sites
171
172 if db_field.name == 'user':
173 if not request.user.is_admin:
174 # only show users from sites where caller has admin or pi role
175 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
176 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
177 sites = [site_privilege.site for site_privilege in site_privileges]
178 site_privileges = SitePrivilege.objects.filter(site__in=sites)
179 emails = [site_privilege.user.email for site_privilege in site_privileges]
180 users = User.objects.filter(email__in=emails)
181 kwargs['queryset'] = users
182 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
183
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400184class SitePrivilegeInline(PlStackTabularInline):
185 model = SitePrivilege
186 suit_classes = 'suit-tab suit-tab-siteprivileges'
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400187 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400188 fields = ('user', 'site','role')
189
190class SlicePrivilegeInline(PlStackTabularInline):
191 model = SlicePrivilege
192 suit_classes = 'suit-tab suit-tab-sliceprivileges'
193 extra = 0
194 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400195
Tony Mackc2835a92013-05-28 09:18:49 -0400196 def formfield_for_foreignkey(self, db_field, request, **kwargs):
197 if db_field.name == 'slice':
198 if not request.user.is_admin:
199 # only show slices at sites where caller has admin or pi role
200 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
201 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
202 sites = [site_privilege.site for site_privilege in site_privileges]
203 slices = Slice.objects.filter(site__in=sites)
204 kwargs['queryset'] = slices
205 if db_field.name == 'user':
206 if not request.user.is_admin:
207 # only show users from sites where caller has admin or pi role
208 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
209 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
210 sites = [site_privilege.site for site_privilege in site_privileges]
211 site_privileges = SitePrivilege.objects.filter(site__in=sites)
212 emails = [site_privilege.user.email for site_privilege in site_privileges]
213 users = User.objects.filter(email__in=emails)
214 kwargs['queryset'] = list(users)
215
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400216 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400217
Scott Bakera0015eb2013-08-14 17:28:14 -0700218class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700219 model = Network.slices.through
220 extra = 0
221 verbose_name = "Network Connection"
222 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400223 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker74d8e622013-07-29 16:04:22 -0700224
Siobhan Tullyd3515752013-06-21 16:34:53 -0400225class SliceTagInline(PlStackTabularInline):
Scott Baker307e06f2013-05-21 17:25:56 -0700226 model = SliceTag
227 extra = 0
228
Tony Mack5e71a662013-05-03 23:30:41 -0400229class PlainTextWidget(forms.HiddenInput):
230 input_type = 'hidden'
231
232 def render(self, name, value, attrs=None):
233 if value is None:
234 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400235 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400236
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400237class PlanetStackBaseAdmin(admin.ModelAdmin):
238 save_on_top = False
239
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400240class SliceRoleAdmin(PlanetStackBaseAdmin):
241 model = SliceRole
242 pass
243
244class SiteRoleAdmin(PlanetStackBaseAdmin):
245 model = SiteRole
246 pass
247
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400248class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400249 sites = forms.ModelMultipleChoiceField(
250 queryset=Site.objects.all(),
251 required=False,
252 widget=FilteredSelectMultiple(
253 verbose_name=('Sites'), is_stacked=False
254 )
255 )
256 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400257 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400258
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400259
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400260class DeploymentAdmin(PlanetStackBaseAdmin):
261 form = DeploymentAdminForm
Siobhan Tully2d95e482013-09-06 10:56:06 -0400262 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400263 fieldsets = [
264 (None, {'fields': ['sites'], 'classes':['suit-tab suit-tab-sites']}),]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400265 suit_form_tabs =(('sites', 'Sites'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
Tony Mack5cd13202013-05-01 21:48:38 -0400266
Siobhan Tullyce652d02013-10-08 21:52:35 -0400267class ServiceAttrAsTabInline(PlStackTabularInline):
268 model = ServiceAttribute
269 fields = ['name','value']
270 extra = 0
271 suit_classes = 'suit-tab suit-tab-serviceattrs'
272
273class ServiceAttributeInline(PlStackTabularInline):
274 model = ServiceAttribute
275 fields = ['name','value']
276 extra = 0
277
278class ServiceAdmin(PlanetStackBaseAdmin):
279 list_display = ("name","enabled")
280 fieldsets = [(None, {'fields': ['name','enabled','description']})]
281 inlines = [ServiceAttributeInline,]
282
Tony Mack0553f282013-06-10 22:54:50 -0400283class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400284 fieldsets = [
Scott Baker9cb88a22013-12-09 18:56:00 -0800285 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink', 'location'], 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400286 ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400287 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400288 suit_form_tabs =(('general', 'Site Details'),
289 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400290 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400291 ('deployments','Deployments'),
292 ('slices','Slices'),
Scott Baker545db2a2013-12-09 18:44:43 -0800293 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400294 ('tags','Tags'),
295 )
Scott Baker545db2a2013-12-09 18:44:43 -0800296 readonly_fields = ['accountLink']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400297 list_display = ('name', 'login_base','site_url', 'enabled')
298 filter_horizontal = ('deployments',)
Siobhan Tully2d95e482013-09-06 10:56:06 -0400299 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400300 search_fields = ['name']
301
Tony Mack04062832013-05-10 08:22:44 -0400302 def queryset(self, request):
303 # admins can see all keys. Users can only see sites they belong to.
304 qs = super(SiteAdmin, self).queryset(request)
305 if not request.user.is_admin:
306 valid_sites = [request.user.site.login_base]
307 roles = request.user.get_roles()
308 for tenant_list in roles.values():
309 valid_sites.extend(tenant_list)
310 qs = qs.filter(login_base__in=valid_sites)
311 return qs
312
Tony Mack5cd13202013-05-01 21:48:38 -0400313 def get_formsets(self, request, obj=None):
314 for inline in self.get_inline_instances(request, obj):
315 # hide MyInline in the add view
316 if obj is None:
317 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400318 if isinstance(inline, SliceInline):
319 inline.model.caller = request.user
320 yield inline.get_formset(request, obj)
321
322 def get_formsets(self, request, obj=None):
323 for inline in self.get_inline_instances(request, obj):
324 # hide MyInline in the add view
325 if obj is None:
326 continue
327 if isinstance(inline, SliverInline):
328 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400329 yield inline.get_formset(request, obj)
330
Scott Baker545db2a2013-12-09 18:44:43 -0800331 def accountLink(self, obj):
332 link_obj = obj.accounts.all()
333 if link_obj:
334 reverse_path = "admin:core_account_change"
335 url = reverse(reverse_path, args =(link_obj[0].id,))
336 return "<a href='%s'>%s</a>" % (url, "view billing details")
337 else:
338 return "no billing data for this site"
339 accountLink.allow_tags = True
340 accountLink.short_description = "Billing"
341
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400342class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400343 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400344 (None, {'fields': ['user', 'site', 'role'], 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400345 ]
346 list_display = ('user', 'site', 'role')
347
Tony Mackc2835a92013-05-28 09:18:49 -0400348 def formfield_for_foreignkey(self, db_field, request, **kwargs):
349 if db_field.name == 'site':
350 if not request.user.is_admin:
351 # only show sites where user is an admin or pi
352 sites = set()
353 for site_privilege in SitePrivilege.objects.filer(user=request.user):
354 if site_privilege.role.role_type in ['admin', 'pi']:
355 sites.add(site_privilege.site)
356 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
357
358 if db_field.name == 'user':
359 if not request.user.is_admin:
360 # only show users from sites where caller has admin or pi role
361 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
362 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
363 sites = [site_privilege.site for site_privilege in site_privileges]
364 site_privileges = SitePrivilege.objects.filter(site__in=sites)
365 emails = [site_privilege.user.email for site_privilege in site_privileges]
366 users = User.objects.filter(email__in=emails)
367 kwargs['queryset'] = users
368
369 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
370
Tony Mack04062832013-05-10 08:22:44 -0400371 def queryset(self, request):
372 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400373 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400374 qs = super(SitePrivilegeAdmin, self).queryset(request)
375 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400376 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
377 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
378 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
379 sites = Site.objects.filter(login_base__in=login_bases)
380 qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400381 return qs
382
Siobhan Tullyce652d02013-10-08 21:52:35 -0400383class SliceForm(forms.ModelForm):
384 class Meta:
385 model = Slice
386 widgets = {
387 'service': LinkedSelect
388 }
389
Tony Mack2bd5b412013-06-11 21:05:06 -0400390class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400391 form = SliceForm
392 fieldsets = [('Slice Details', {'fields': ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url'], 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tully30fd4292013-05-10 08:59:56 -0400393 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400394 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400395
396
Siobhan Tully2d95e482013-09-06 10:56:06 -0400397 #inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline, SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400398 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400399 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400400 ('sliceprivileges','Privileges'),
401 ('slivers','Slivers'),
402 ('tags','Tags'),
403 ('reservations','Reservations'),
404 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400405
Tony Mackc2835a92013-05-28 09:18:49 -0400406 def formfield_for_foreignkey(self, db_field, request, **kwargs):
407 if db_field.name == 'site':
408 if not request.user.is_admin:
409 # only show sites where user is a pi or admin
410 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
411 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
412 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
413 sites = Site.objects.filter(login_base__in=login_bases)
414 kwargs['queryset'] = sites
415
416 return super(SliceAdmin, 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 keys. Users can only see slices they belong to.
420 qs = super(SliceAdmin, self).queryset(request)
421 if not request.user.is_admin:
422 valid_slices = []
423 roles = request.user.get_roles()
424 for tenant_list in roles.values():
425 valid_slices.extend(tenant_list)
426 qs = qs.filter(name__in=valid_slices)
427 return qs
428
Tony Mack79748612013-05-01 14:52:03 -0400429 def get_formsets(self, request, obj=None):
430 for inline in self.get_inline_instances(request, obj):
431 # hide MyInline in the add view
432 if obj is None:
433 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400434 if isinstance(inline, SliverInline):
435 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400436 yield inline.get_formset(request, obj)
437
Tony Mackfdd4d802013-04-27 13:02:33 -0400438 def get_queryset(self, request):
439 qs = super(SliceAdmin, self).get_queryset(request)
440 if request.user.is_superuser:
441 return qs
442 # users can only see slices at their site
Tony Mack2bd5b412013-06-11 21:05:06 -0400443 return qs.filter(site=request.user.site)
444
445 def save_model(self, request, obj, form, change):
446 # update openstack connection to use this site/tenant
447 obj.caller = request.user
448 obj.save()
Tony Mackfdd4d802013-04-27 13:02:33 -0400449
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400450class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400451 fieldsets = [
452 (None, {'fields': ['user', 'slice', 'role']})
453 ]
454 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400455
Tony Mackc2835a92013-05-28 09:18:49 -0400456 def formfield_for_foreignkey(self, db_field, request, **kwargs):
457 if db_field.name == 'slice':
458 if not request.user.is_admin:
459 # only show slices at sites where caller has admin or pi role
460 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
461 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
462 sites = [site_privilege.site for site_privilege in site_privileges]
463 slices = Slice.objects.filter(site__in=sites)
464 kwargs['queryset'] = slices
465
466 if db_field.name == 'user':
467 if not request.user.is_admin:
468 # only show users from sites where caller has admin or pi role
469 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
470 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
471 sites = [site_privilege.site for site_privilege in site_privileges]
472 site_privileges = SitePrivilege.objects.filter(site__in=sites)
473 emails = [site_privilege.user.email for site_privilege in site_privileges]
474 users = User.objects.filter(email__in=emails)
475 kwargs['queryset'] = users
476
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400477 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400478
Tony Mack04062832013-05-10 08:22:44 -0400479 def queryset(self, request):
480 # admins can see all memberships. Users can only see memberships of
481 # slices where they have the admin role.
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400482 qs = super(SlicePrivilegeAdmin, self).queryset(request)
Tony Mack04062832013-05-10 08:22:44 -0400483 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400484 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
485 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
486 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
487 sites = Site.objects.filter(login_base__in=login_bases)
488 slices = Slice.objects.filter(site__in=sites)
489 qs = qs.filter(slice__in=slices)
Tony Mack04062832013-05-10 08:22:44 -0400490 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400491
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400492 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400493 # update openstack connection to use this site/tenant
494 auth = request.session.get('auth', {})
495 auth['tenant'] = obj.slice.name
496 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400497 obj.save()
498
499 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400500 # update openstack connection to use this site/tenant
501 auth = request.session.get('auth', {})
502 auth['tenant'] = obj.slice.name
503 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400504 obj.delete()
505
Siobhan Tully567e3e62013-06-21 18:03:16 -0400506
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400507class ImageAdmin(PlanetStackBaseAdmin):
508
509 fieldsets = [('Image Details',
510 {'fields': ['image_id', 'name', 'disk_format', 'container_format'],
511 'classes': ['suit-tab suit-tab-general']})
512 ]
513
514 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
515
516 inlines = [SliverInline]
517
518class NodeForm(forms.ModelForm):
519 class Meta:
520 widgets = {
521 'site': LinkedSelect,
522 'deployment': LinkedSelect
523 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400524
525class NodeAdmin(admin.ModelAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400526 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400527 list_display = ('name', 'site', 'deployment')
528 list_filter = ('deployment',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400529 inlines = [TagInline,SliverInline]
530 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
531
532 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400533
Siobhan Tully567e3e62013-06-21 18:03:16 -0400534
Tony Mackd90cdbf2013-04-16 22:48:40 -0400535class SliverForm(forms.ModelForm):
536 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400537 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400538 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400539 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400540 widgets = {
541 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400542 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400543 'slice': LinkedSelect,
544 'deploymentNetwork': LinkedSelect,
545 'node': LinkedSelect,
546 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400547 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400548
Siobhan Tullyd3515752013-06-21 16:34:53 -0400549class TagAdmin(admin.ModelAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400550 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullyd3515752013-06-21 16:34:53 -0400551
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400552class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400553 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400554 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400555 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400556 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400557 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400558
559 suit_form_tabs =(('general', 'Sliver Details'),
560 ('tags','Tags'),
561 )
562
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400563 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400564
Tony Mackc2835a92013-05-28 09:18:49 -0400565 def formfield_for_foreignkey(self, db_field, request, **kwargs):
566 if db_field.name == 'slice':
567 if not request.user.is_admin:
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400568 slices = set([sm.slice.name for sm in SlicePrivilege.objects.filter(user=request.user)])
Tony Mackc2835a92013-05-28 09:18:49 -0400569 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
570
571 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
572
Tony Mack04062832013-05-10 08:22:44 -0400573 def queryset(self, request):
574 # admins can see all slivers. Users can only see slivers of
575 # the slices they belong to.
576 qs = super(SliverAdmin, self).queryset(request)
577 if not request.user.is_admin:
578 tenants = []
579 roles = request.user.get_roles()
580 for tenant_list in roles.values():
581 tenants.extend(tenant_list)
582 valid_slices = Slice.objects.filter(name__in=tenants)
583 qs = qs.filter(slice__in=valid_slices)
584 return qs
585
Tony Mack1d6b85f2013-05-07 18:49:14 -0400586 def get_formsets(self, request, obj=None):
587 # make some fields read only if we are updating an existing record
588 if obj == None:
589 #self.readonly_fields = ('ip', 'instance_name')
590 self.readonly_fields = ()
591 else:
Tony Mack1e889462013-05-10 21:34:54 -0400592 self.readonly_fields = ()
593 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400594
595 for inline in self.get_inline_instances(request, obj):
596 # hide MyInline in the add view
597 if obj is None:
598 continue
599 # give inline object access to driver and caller
600 auth = request.session.get('auth', {})
601 auth['tenant'] = obj.name # meed to connect using slice's tenant
602 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
603 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400604
605 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400606 # update openstack connection to use this site/tenant
607 auth = request.session.get('auth', {})
608 auth['tenant'] = obj.slice.name
609 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackb0d97422013-06-10 09:57:45 -0400610 obj.creator = request.user
Tony Mack53106f32013-04-27 16:43:01 -0400611 obj.save()
612
613 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400614 # update openstack connection to use this site/tenant
615 auth = request.session.get('auth', {})
616 auth['tenant'] = obj.slice.name
617 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400618 obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400619
Siobhan Tully53437282013-04-26 19:30:27 -0400620class UserCreationForm(forms.ModelForm):
621 """A form for creating new users. Includes all the required
622 fields, plus a repeated password."""
623 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
624 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
625
626 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400627 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400628 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400629
630 def clean_password2(self):
631 # Check that the two password entries match
632 password1 = self.cleaned_data.get("password1")
633 password2 = self.cleaned_data.get("password2")
634 if password1 and password2 and password1 != password2:
635 raise forms.ValidationError("Passwords don't match")
636 return password2
637
638 def save(self, commit=True):
639 # Save the provided password in hashed format
640 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400641 user.password = self.cleaned_data["password1"]
642 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400643 if commit:
644 user.save()
645 return user
646
Siobhan Tully567e3e62013-06-21 18:03:16 -0400647
Siobhan Tully53437282013-04-26 19:30:27 -0400648class UserChangeForm(forms.ModelForm):
649 """A form for updating users. Includes all the fields on
650 the user, but replaces the password field with admin's
651 password hash display field.
652 """
653 password = ReadOnlyPasswordHashField()
654
655 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400656 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400657
658 def clean_password(self):
659 # Regardless of what the user provides, return the initial value.
660 # This is done here, rather than on the field, because the
661 # field does not have access to the initial value
662 return self.initial["password"]
663
Siobhan Tully567e3e62013-06-21 18:03:16 -0400664
Tony Mack2bd5b412013-06-11 21:05:06 -0400665class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400666 class Meta:
667 app_label = "core"
668
669 # The forms to add and change user instances
670 form = UserChangeForm
671 add_form = UserCreationForm
672
673 # The fields to be used in displaying the User model.
674 # These override the definitions on the base UserAdmin
675 # that reference specific fields on auth.User.
Siobhan Tullyfece0d52013-09-06 12:57:05 -0400676 list_display = ('email', 'firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400677 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400678 list_filter = ()
679 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
Siobhan Tully53437282013-04-26 19:30:27 -0400680 fieldsets = (
Siobhan Tullyfece0d52013-09-06 12:57:05 -0400681 ('Login Details', {'fields': ('email', 'site','password', 'is_admin', 'public_key'), 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400682 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400683 #('Important dates', {'fields': ('last_login',)}),
684 )
685 add_fieldsets = (
686 (None, {
687 'classes': ('wide',),
Siobhan Tullyfece0d52013-09-06 12:57:05 -0400688 'fields': ('email', 'firstname', 'lastname', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400689 ),
690 )
691 search_fields = ('email',)
692 ordering = ('email',)
693 filter_horizontal = ()
694
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400695 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
696
Tony Mackc2835a92013-05-28 09:18:49 -0400697 def formfield_for_foreignkey(self, db_field, request, **kwargs):
698 if db_field.name == 'site':
699 if not request.user.is_admin:
700 # show sites where caller is an admin or pi
701 sites = []
702 for site_privilege in SitePrivilege.objects.filer(user=request.user):
703 if site_privilege.role.role_type in ['admin', 'pi']:
704 sites.append(site_privilege.site.login_base)
705 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
706
707 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
708
Scott Baker3de3e372013-05-10 16:50:44 -0700709class ServiceResourceInline(admin.TabularInline):
710 model = ServiceResource
711 extra = 0
712
713class ServiceClassAdmin(admin.ModelAdmin):
714 list_display = ('name', 'commitment', 'membershipFee')
715 inlines = [ServiceResourceInline]
716
Scott Baker133c9212013-05-17 09:09:11 -0700717class ReservedResourceInline(admin.TabularInline):
718 model = ReservedResource
719 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400720 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -0700721
722 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
723 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
724
725 if db_field.name == 'resource':
726 # restrict resources to those that the slice's service class allows
727 if request._slice is not None:
728 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
729 if len(field.queryset) > 0:
730 field.initial = field.queryset.all()[0]
731 else:
732 field.queryset = field.queryset.none()
733 elif db_field.name == 'sliver':
734 # restrict slivers to those that belong to the slice
735 if request._slice is not None:
736 field.queryset = field.queryset.filter(slice = request._slice)
737 else:
738 field.queryset = field.queryset.none()
739
740 return field
741
742class ReservationChangeForm(forms.ModelForm):
743 class Meta:
744 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400745 widgets = {
746 'slice' : LinkedSelect
747 }
Scott Baker133c9212013-05-17 09:09:11 -0700748
749class ReservationAddForm(forms.ModelForm):
750 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
751 refresh = forms.CharField(widget=forms.HiddenInput())
752
753 class Media:
754 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
755
756 def clean_slice(self):
757 slice = self.cleaned_data.get("slice")
758 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
759 if len(x) == 0:
760 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
761 return slice
762
763 class Meta:
764 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400765 widgets = {
766 'slice' : LinkedSelect
767 }
768
Scott Baker133c9212013-05-17 09:09:11 -0700769
770class ReservationAddRefreshForm(ReservationAddForm):
771 """ This form is displayed when the Reservation Form receives an update
772 from the Slice dropdown onChange handler. It doesn't validate the
773 data and doesn't save the data. This will cause the form to be
774 redrawn.
775 """
776
Scott Baker8737e5f2013-05-17 09:35:32 -0700777 """ don't validate anything other than slice """
778 dont_validate_fields = ("startTime", "duration")
779
Scott Baker133c9212013-05-17 09:09:11 -0700780 def full_clean(self):
781 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -0700782
783 for fieldname in self.dont_validate_fields:
784 if fieldname in self._errors:
785 del self._errors[fieldname]
786
Scott Baker133c9212013-05-17 09:09:11 -0700787 return result
788
789 """ don't save anything """
790 def is_valid(self):
791 return False
792
793class ReservationAdmin(admin.ModelAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400794 fieldsets = [('Reservation Details', {'fields': ['slice', 'startTime', 'duration'], 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -0700795 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -0700796 form = ReservationAddForm
797
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400798 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
799
800 inlines = [ReservedResourceInline]
801
Scott Baker133c9212013-05-17 09:09:11 -0700802 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -0700803 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -0700804 request._refresh = False
805 request._slice = None
806 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -0700807 # "refresh" will be set to "1" if the form was submitted due to
808 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -0700809 if request.POST.get("refresh","1") == "1":
810 request._refresh = True
811 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -0700812
813 # Keep track of the slice that was selected, so the
814 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -0700815 request._slice = request.POST.get("slice",None)
816 if (request._slice is not None):
817 request._slice = Slice.objects.get(id=request._slice)
818
819 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
820 return result
821
Scott Bakeracd45142013-05-19 16:19:16 -0700822 def changelist_view(self, request, extra_context = None):
823 timezone.activate(request.user.timezone)
824 return super(ReservationAdmin, self).changelist_view(request, extra_context)
825
Scott Baker133c9212013-05-17 09:09:11 -0700826 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -0400827 request._obj_ = obj
828 if obj is not None:
829 # For changes, set request._slice to the slice already set in the
830 # object.
831 request._slice = obj.slice
832 self.form = ReservationChangeForm
833 else:
834 if getattr(request, "_refresh", False):
835 self.form = ReservationAddRefreshForm
836 else:
837 self.form = ReservationAddForm
838 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
839
Scott Baker133c9212013-05-17 09:09:11 -0700840 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -0400841 if (obj is not None):
842 # Prevent slice from being changed after the reservation has been
843 # created.
844 return ['slice']
845 else:
Scott Baker133c9212013-05-17 09:09:11 -0700846 return []
Scott Baker3de3e372013-05-10 16:50:44 -0700847
Scott Baker74d8e622013-07-29 16:04:22 -0700848class NetworkParameterTypeAdmin(admin.ModelAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -0700849 list_display = ("name", )
850
851class RouterAdmin(admin.ModelAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -0700852 list_display = ("name", )
853
854class RouterInline(admin.TabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700855 model = Router.networks.through
856 extra = 0
857 verbose_name_plural = "Routers"
858 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400859 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -0700860
861class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700862 model = NetworkParameter
863 extra = 1
864 verbose_name_plural = "Parameters"
865 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400866 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -0700867
868class NetworkSliversInline(admin.TabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700869 readonly_fields = ("ip", )
870 model = NetworkSliver
871 extra = 0
872 verbose_name_plural = "Slivers"
873 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400874 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700875
Scott Bakerd7d2a392013-08-06 08:57:30 -0700876class NetworkSlicesInline(admin.TabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -0700877 model = NetworkSlice
878 extra = 0
879 verbose_name_plural = "Slices"
880 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400881 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -0700882
Andy Bavierfe81aa42013-11-21 14:11:48 -0500883class NetworkForm(forms.ModelForm):
884 class Meta:
885 widgets = {
886 'deployment': LinkedSelect,
887 'site': LinkedSelect,
888 }
889
Scott Baker74d8e622013-07-29 16:04:22 -0700890class NetworkAdmin(admin.ModelAdmin):
Andy Bavierfe81aa42013-11-21 14:11:48 -0500891 form = NetworkForm
Scott Baker74d8e622013-07-29 16:04:22 -0700892 list_display = ("name", "subnet", "ports", "labels")
Andy Bavierfe81aa42013-11-21 14:11:48 -0500893 list_filter = ('deployment', )
Scott Baker74d8e622013-07-29 16:04:22 -0700894 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -0400895
Scott Bakerd7d2a392013-08-06 08:57:30 -0700896 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -0700897
Siobhan Tully2d95e482013-09-06 10:56:06 -0400898 fieldsets = [
Andy Bavierfe81aa42013-11-21 14:11:48 -0500899 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','site','deployment','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400900
901 suit_form_tabs =(
902 ('general','Network Details'),
903 ('netparams', 'Parameters'),
904 ('networkslivers','Slivers'),
905 ('networkslices','Slices'),
906 ('routers','Routers'),
907 )
Scott Baker74d8e622013-07-29 16:04:22 -0700908class NetworkTemplateAdmin(admin.ModelAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -0700909 list_display = ("name", "guaranteedBandwidth", "visibility")
910
Tony Mack31c2b8f2013-04-26 20:01:42 -0400911# register a signal that caches the user's credentials when they log in
912def cache_credentials(sender, user, request, **kwds):
913 auth = {'username': request.POST['username'],
914 'password': request.POST['password']}
915 request.session['auth'] = auth
916user_logged_in.connect(cache_credentials)
917
Scott Baker15cddfa2013-12-09 13:45:19 -0800918def dollar_field(fieldName, short_description):
919 def newFunc(self, obj):
920 try:
921 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
922 except:
923 x=getattr(obj, fieldName, 0.0)
924 return x
925 newFunc.short_description = short_description
926 return newFunc
927
928def right_dollar_field(fieldName, short_description):
929 def newFunc(self, obj):
930 try:
931 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
932 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
933 except:
934 x=getattr(obj, fieldName, 0.0)
935 return x
936 newFunc.short_description = short_description
937 newFunc.allow_tags = True
938 return newFunc
Scott Baker43105042013-12-06 23:23:36 -0800939
940class InvoiceChargeInline(admin.TabularInline):
941 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -0800942 extra = 0
Scott Baker43105042013-12-06 23:23:36 -0800943 verbose_name_plural = "Charges"
944 verbose_name = "Charge"
Scott Baker9cb88a22013-12-09 18:56:00 -0800945 exclude = ['enacted', 'account']
946 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
947 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
948 can_delete = False
949 max_num = 0
950
951 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -0800952
953class InvoiceAdmin(admin.ModelAdmin):
954 list_display = ("date", "account")
955
956 inlines = [InvoiceChargeInline]
957
Scott Baker9cb88a22013-12-09 18:56:00 -0800958 fields = ["date", "account", "dollar_amount"]
959 readonly_fields = ["date", "account", "dollar_amount"]
960
961 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -0800962
Scott Baker15cddfa2013-12-09 13:45:19 -0800963class InvoiceInline(admin.TabularInline):
964 model = Invoice
965 extra = 0
966 verbose_name_plural = "Invoices"
967 verbose_name = "Invoice"
968 exclude = ['enacted']
Scott Baker9cb88a22013-12-09 18:56:00 -0800969 fields = ["date", "dollar_amount", "invoiceLink"]
970 readonly_fields = ["date", "dollar_amount", "invoiceLink"]
Scott Baker15cddfa2013-12-09 13:45:19 -0800971 suit_classes = 'suit-tab suit-tab-accountinvoice'
972 can_delete=False
973 max_num=0
974
975 dollar_amount = right_dollar_field("amount", "Amount")
976
Scott Baker9cb88a22013-12-09 18:56:00 -0800977 def invoiceLink(self, obj):
978 reverse_path = "admin:core_invoice_change"
979 url = reverse(reverse_path, args =(obj.id,))
980 return "<a href='%s'>%s</a>" % (url, "details")
981 invoiceLink.allow_tags = True
982 invoiceLink.short_description = "Details"
983
Scott Baker43105042013-12-06 23:23:36 -0800984class PendingChargeInline(admin.TabularInline):
985 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -0800986 extra = 0
Scott Baker43105042013-12-06 23:23:36 -0800987 verbose_name_plural = "Charges"
988 verbose_name = "Charge"
989 exclude = ['enacted', "invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -0800990 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
991 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -0800992 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -0800993 can_delete=False
994 max_num=0
Scott Baker43105042013-12-06 23:23:36 -0800995
996 def queryset(self, request):
997 qs = super(PendingChargeInline, self).queryset(request)
998 qs = qs.filter(state="pending")
999 return qs
1000
Scott Baker15cddfa2013-12-09 13:45:19 -08001001 dollar_amount = right_dollar_field("amount", "Amount")
1002
Scott Baker43105042013-12-06 23:23:36 -08001003class PaymentInline(admin.TabularInline):
1004 model=Payment
1005 extra = 1
1006 verbose_name_plural = "Payments"
1007 verbose_name = "Payment"
1008 exclude = ['enacted']
Scott Baker15cddfa2013-12-09 13:45:19 -08001009 fields = ["date", "dollar_amount"]
1010 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001011 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001012 can_delete=False
1013 max_num=0
1014
1015 dollar_amount = right_dollar_field("amount", "Amount")
1016
Scott Baker43105042013-12-06 23:23:36 -08001017
1018class AccountAdmin(admin.ModelAdmin):
1019 list_display = ("site", "balance_due")
1020
1021 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1022
1023 fieldsets = [
Scott Baker15cddfa2013-12-09 13:45:19 -08001024 (None, {'fields': ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']})] # ,'classes':['suit-tab suit-tab-general']}),]
Scott Baker43105042013-12-06 23:23:36 -08001025
Scott Baker15cddfa2013-12-09 13:45:19 -08001026 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001027
1028 suit_form_tabs =(
1029 ('general','Account Details'),
1030 ('accountinvoice', 'Invoices'),
1031 ('accountpayments', 'Payments'),
1032 ('accountpendingcharges','Pending Charges'),
1033 )
1034
Scott Baker15cddfa2013-12-09 13:45:19 -08001035 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1036 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1037 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1038
Siobhan Tullyce652d02013-10-08 21:52:35 -04001039
Siobhan Tully53437282013-04-26 19:30:27 -04001040# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001041admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001042# ... and, since we're not using Django's builtin permissions,
1043# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001044#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001045
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001046#Do not show django evolution in the admin interface
1047from django_evolution.models import Version, Evolution
1048admin.site.unregister(Version)
1049admin.site.unregister(Evolution)
1050
1051
1052# When debugging it is often easier to see all the classes, but for regular use
1053# only the top-levels should be displayed
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001054showAll = True
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001055
Scott Baker43105042013-12-06 23:23:36 -08001056admin.site.register(Account, AccountAdmin)
Scott Baker9cb88a22013-12-09 18:56:00 -08001057admin.site.register(Invoice, InvoiceAdmin)
Scott Baker43105042013-12-06 23:23:36 -08001058
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001059admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001060admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001061admin.site.register(Slice, SliceAdmin)
smbaker43591c32013-06-26 12:43:53 -07001062admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001063admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001064admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001065admin.site.register(Network, NetworkAdmin)
1066admin.site.register(Router, RouterAdmin)
1067admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1068admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001069
1070if showAll:
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001071 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001072 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001073 admin.site.register(DeploymentRole)
1074 admin.site.register(SiteRole)
1075 admin.site.register(SliceRole)
1076 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001077 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001078 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1079 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001080 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001081 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001082