blob: 1c420139f0f847a973ebd1f45541466ffaa2c8d5 [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
Siobhan Tullybfd11dc2013-09-03 12:59:24 -040015from suit.widgets import LinkedSelect
Siobhan Tullycf04fb62014-01-11 11:25:57 -050016from django.core.exceptions import PermissionDenied
Scott Bakere2bbf7e2014-01-13 12:09:31 -080017from django.core.urlresolvers import reverse, NoReverseMatch
Tony Mack7130ac32013-03-22 21:58:00 -040018
Scott Baker36f50872014-08-21 13:01:25 -070019import django_evolution
20
Scott Baker40c00762014-08-21 16:55:59 -070021def backend_icon(obj): # backend_status, enacted, updated):
22 #return "%s %s %s" % (str(obj.updated), str(obj.enacted), str(obj.backend_status))
23 if (obj.enacted is not None) and obj.enacted >= obj.updated:
24 return '<img src="/static/admin/img/icon_success.gif">'
25 else:
26 if obj.backend_status == "Provisioning in progress" or obj.backend_status=="":
Scott Bakerbf88e7e2014-08-28 15:15:18 -070027 return '<span title="%s"><img src="/static/admin/img/icon_clock.gif"></span>' % obj.backend_status
Scott Baker63d1a552014-08-21 15:19:07 -070028 else:
Scott Bakerbf88e7e2014-08-28 15:15:18 -070029 return '<span title="%s"><img src="/static/admin/img/icon_error.gif"></span>' % obj.backend_status
Scott Baker40c00762014-08-21 16:55:59 -070030
31def backend_text(obj):
32 icon = backend_icon(obj)
33 if (obj.enacted is not None) and obj.enacted >= obj.updated:
34 return "%s %s" % (icon, "successfully enacted") # enacted on %s" % str(obj.enacted))
35 else:
36 return "%s %s" % (icon, obj.backend_status)
Scott Baker63d1a552014-08-21 15:19:07 -070037
Scott Baker36f50872014-08-21 13:01:25 -070038class PlainTextWidget(forms.HiddenInput):
39 input_type = 'hidden'
40
41 def render(self, name, value, attrs=None):
42 if value is None:
43 value = ''
44 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
45
Siobhan Tullycf04fb62014-01-11 11:25:57 -050046class ReadOnlyAwareAdmin(admin.ModelAdmin):
47
48 def has_add_permission(self, request, obj=None):
49 return (not self.__user_is_readonly(request))
Scott Baker36f50872014-08-21 13:01:25 -070050
Siobhan Tullycf04fb62014-01-11 11:25:57 -050051 def has_delete_permission(self, request, obj=None):
52 return (not self.__user_is_readonly(request))
53
54 def save_model(self, request, obj, form, change):
55 if self.__user_is_readonly(request):
56 raise PermissionDenied
57 #pass
58 else:
59 return super(ReadOnlyAwareAdmin, self).save_model(request, obj, form, change)
60
61 def get_actions(self,request):
62 actions = super(ReadOnlyAwareAdmin,self).get_actions(request)
63
64 if self.__user_is_readonly(request):
65 if 'delete_selected' in actions:
66 del actions['delete_selected']
67
68 return actions
69
70 def change_view(self,request,object_id, extra_context=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -050071 if self.__user_is_readonly(request):
Scott Bakeraf73e102014-04-22 22:40:07 -070072 if not hasattr(self, "readonly_save"):
73 # save the original readonly fields
74 self.readonly_save = self.readonly_fields
75 self.inlines_save = self.inlines
Scott Bakere8859f92014-05-23 12:42:40 -070076 if hasattr(self, "user_readonly_fields"):
77 self.readonly_fields=self.user_readonly_fields
78 if hasattr(self, "user_readonly_inlines"):
79 self.inlines = self.user_readonly_inlines
Scott Bakeraf73e102014-04-22 22:40:07 -070080 else:
81 if hasattr(self, "readonly_save"):
82 # restore the original readonly fields
83 self.readonly_fields = self.readonly_save
Scott Bakere8859f92014-05-23 12:42:40 -070084 if hasattr(self, "inlines_save"):
Scott Bakeraf73e102014-04-22 22:40:07 -070085 self.inlines = self.inlines_save
Siobhan Tullycf04fb62014-01-11 11:25:57 -050086
87 try:
88 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
89 except PermissionDenied:
90 pass
91 if request.method == 'POST':
92 raise PermissionDenied
93 request.readonly = True
94 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
95
Siobhan Tullycf04fb62014-01-11 11:25:57 -050096 def __user_is_readonly(self, request):
97 return request.user.isReadOnlyUser()
98
Scott Baker40c00762014-08-21 16:55:59 -070099 def backend_status_text(self, obj):
100 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -0700101
Scott Baker63d1a552014-08-21 15:19:07 -0700102 def backend_status_icon(self, obj):
Scott Baker40c00762014-08-21 16:55:59 -0700103 return mark_safe(backend_icon(obj))
Scott Baker63d1a552014-08-21 15:19:07 -0700104 backend_status_icon.short_description = ""
105
Scott Baker36f50872014-08-21 13:01:25 -0700106
Scott Bakere8859f92014-05-23 12:42:40 -0700107class SingletonAdmin (ReadOnlyAwareAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400108 def has_add_permission(self, request):
Scott Bakere8859f92014-05-23 12:42:40 -0700109 if not super(SingletonAdmin, self).has_add_permission(request):
110 return False
111
Siobhan Tullyce652d02013-10-08 21:52:35 -0400112 num_objects = self.model.objects.count()
113 if num_objects >= 1:
114 return False
115 else:
116 return True
117
118
Siobhan Tullyd3515752013-06-21 16:34:53 -0400119class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -0800120 def __init__(self, *args, **kwargs):
121 super(PlStackTabularInline, self).__init__(*args, **kwargs)
122
123 # InlineModelAdmin as no get_fields() method, so in order to add
124 # the selflink field, we override __init__ to modify self.fields and
125 # self.readonly_fields.
126
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800127 self.setup_selflink()
128
Scott Baker874936e2014-01-13 18:15:34 -0800129 def get_change_url(self, model, id):
130 """ Get the URL to a change form in the admin for this model """
131 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800132 try:
Scott Baker874936e2014-01-13 18:15:34 -0800133 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800134 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -0800135 return None
136
137 return url
138
139 def setup_selflink(self):
140 if hasattr(self, "selflink_fieldname"):
141 """ self.selflink_model can be defined to punch through a relation
142 to its target object. For example, in SliceNetworkInline, set
143 selflink_model = "network", and the URL will lead to the Network
144 object instead of trying to bring up a change view of the
145 SliceNetwork object.
146 """
147 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
148 else:
149 self.selflink_model = self.model
150
151 url = self.get_change_url(self.selflink_model, 0)
152
153 # We don't have an admin for this object, so don't create the
154 # selflink.
155 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800156 return
157
Scott Baker874936e2014-01-13 18:15:34 -0800158 # Since we need to add "selflink" to the field list, we need to create
159 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800160 if (self.fields is None):
161 self.fields = []
162 for f in self.model._meta.fields:
163 if f.editable and f.name != "id":
164 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800165
Scott Baker874936e2014-01-13 18:15:34 -0800166 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800167
Scott Baker874936e2014-01-13 18:15:34 -0800168 if self.readonly_fields is None:
169 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800170
Scott Baker874936e2014-01-13 18:15:34 -0800171 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800172
173 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800174 if hasattr(self, "selflink_fieldname"):
175 obj = getattr(obj, self.selflink_fieldname)
176
Scott Baker86568322014-01-12 16:53:31 -0800177 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800178 url = self.get_change_url(self.selflink_model, obj.id)
179 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800180 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800181 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800182
183 selflink.allow_tags = True
184 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400185
Scott Bakerb27b62c2014-08-15 16:29:16 -0700186 def has_add_permission(self, request):
187 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500188
189 def get_readonly_fields(self, request, obj=None):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700190 readonly_fields = list(self.readonly_fields)[:]
191 if request.user.isReadOnlyUser():
192 for field in self.fields:
193 if not field in readonly_fields:
194 readonly_fields.append(field)
195 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500196
Scott Baker40c00762014-08-21 16:55:59 -0700197 def backend_status_icon(self, obj):
198 return mark_safe(backend_icon(obj))
199 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -0700200
Scott Bakerb27b62c2014-08-15 16:29:16 -0700201class PlStackGenericTabularInline(generic.GenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500202 def has_add_permission(self, request):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700203 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500204
Scott Bakerb27b62c2014-08-15 16:29:16 -0700205 def get_readonly_fields(self, request, obj=None):
206 readonly_fields = list(self.readonly_fields)[:]
207 if request.user.isReadOnlyUser():
208 for field in self.fields:
209 if not field in readonly_fields:
210 readonly_fields.append(field)
211 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500212
Scott Baker40c00762014-08-21 16:55:59 -0700213 def backend_status_icon(self, obj):
214 return mark_safe(backend_icon(obj))
215 backend_status_icon.short_description = ""
216
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400217class ReservationInline(PlStackTabularInline):
218 model = Reservation
219 extra = 0
220 suit_classes = 'suit-tab suit-tab-reservations'
Scott Baker36f50872014-08-21 13:01:25 -0700221
Tony Mack5b061472014-02-04 07:57:10 -0500222 def queryset(self, request):
223 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400224
Scott Bakerb27b62c2014-08-15 16:29:16 -0700225class TagInline(PlStackGenericTabularInline):
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400226 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400227 extra = 0
228 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500229 fields = ['service', 'name', 'value']
230
231 def queryset(self, request):
232 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400233
Scott Baker74d8e622013-07-29 16:04:22 -0700234class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400235 """ This is a callable that looks up a network name in a sliver and returns
236 the ip address for that network.
237 """
238
Scott Baker434ca7e2014-08-15 12:29:20 -0700239 byNetworkName = {} # class variable
240
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400241 def __init__(self, name):
242 self.short_description = name
243 self.__name__ = name
244 self.network_name = name
245
246 def __call__(self, obj):
247 if obj is not None:
248 for nbs in obj.networksliver_set.all():
249 if (nbs.network.name == self.network_name):
250 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700251 return ""
252
253 def __str__(self):
254 return self.network_name
255
Scott Baker434ca7e2014-08-15 12:29:20 -0700256 @staticmethod
257 def get(network_name):
258 """ We want to make sure we alwars return the same NetworkLookerUpper
259 because sometimes django will cause them to be instantiated multiple
260 times (and we don't want different ones in form.fields vs
261 SliverInline.readonly_fields).
262 """
263 if network_name not in NetworkLookerUpper.byNetworkName:
264 NetworkLookerUpper.byNetworkName[network_name] = NetworkLookerUpper(network_name)
265 return NetworkLookerUpper.byNetworkName[network_name]
266
Siobhan Tullyd3515752013-06-21 16:34:53 -0400267class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400268 model = Sliver
Scott Baker40c00762014-08-21 16:55:59 -0700269 fields = ['backend_status_icon', 'all_ips_string', 'instance_name', 'slice', 'numberCores', 'deploymentNetwork', 'image', 'node']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400270 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700271 readonly_fields = ['backend_status_icon', 'all_ips_string', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400272 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700273
Tony Mack5b061472014-02-04 07:57:10 -0500274 def queryset(self, request):
275 return Sliver.select_by_user(request.user)
276
Scott Bakerb24cc932014-06-09 10:51:16 -0700277 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
Scott Bakerb24cc932014-06-09 10:51:16 -0700278 if db_field.name == 'deploymentNetwork':
Scott Baker3b678742014-06-09 13:11:54 -0700279 kwargs['queryset'] = Deployment.select_by_acl(request.user)
Scott Baker34b502f2014-08-05 18:33:31 -0700280 # the inscrutable jquery selector below says:
281 # find the closest parent "tr" to the current element
282 # then find the child with class "field-node"
283 # then find the child with that is a select
284 # then return its id
Scott Bakerdf65d882014-08-05 18:52:14 -0700285 kwargs['widget'] = forms.Select(attrs={'onChange': "update_nodes(this, $($(this).closest('tr')[0]).find('.field-node select')[0].id)"})
Scott Baker34b502f2014-08-05 18:33:31 -0700286 #kwargs['widget'] = forms.Select(attrs={'onChange': "console.log($($($(this).closest('tr')[0]).children('.field-node')[0]).children('select')[0].id);"})
Scott Baker3b678742014-06-09 13:11:54 -0700287
288 field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700289
290 return field
291
Scott Baker434ca7e2014-08-15 12:29:20 -0700292"""
293 SMBAKER: This is the old code that implemented each network type as a
294 separate column in the sliver table.
Scott Baker74d8e622013-07-29 16:04:22 -0700295
Scott Baker434ca7e2014-08-15 12:29:20 -0700296 def _declared_fieldsets(self):
297 # Return None so django will call get_fieldsets and we can insert our
298 # dynamic fields
299 return None
300
301 def get_readonly_fields(self, request, obj=None):
302 readonly_fields = list(super(SliverInline, self).get_readonly_fields(request, obj))
303
304 # Lookup the networks that are bound to the slivers, and add those
305 # network names to the list of readonly fields.
306
307 for sliver in obj.slivers.all():
308 for nbs in sliver.networksliver_set.all():
309 if nbs.ip:
310 network_name = nbs.network.name
311 if network_name not in [str(x) for x in readonly_fields]:
312 readonly_fields.append(NetworkLookerUpper.get(network_name))
313
314 return readonly_fields
315
316 def get_fieldsets(self, request, obj=None):
317 form = self.get_formset(request, obj).form
318 # fields = the read/write files + the read-only fields
319 fields = list(self.fields)
320 for fieldName in self.get_readonly_fields(request,obj):
321 if not fieldName in fields:
322 fields.append(fieldName)
323
324 return [(None, {'fields': fields})]
325"""
Siobhan Tully567e3e62013-06-21 18:03:16 -0400326
Siobhan Tullyd3515752013-06-21 16:34:53 -0400327class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400328 model = Site
329 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400330 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400331
Tony Mack5b061472014-02-04 07:57:10 -0500332 def queryset(self, request):
333 return Site.select_by_user(request.user)
334
Siobhan Tullyd3515752013-06-21 16:34:53 -0400335class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400336 model = User
Scott Baker40c00762014-08-21 16:55:59 -0700337 fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
338 readonly_fields = ('backend_status_icon', )
Siobhan Tully30fd4292013-05-10 08:59:56 -0400339 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400340 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400341
Tony Mack5b061472014-02-04 07:57:10 -0500342 def queryset(self, request):
343 return User.select_by_user(request.user)
344
Siobhan Tullyd3515752013-06-21 16:34:53 -0400345class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400346 model = Slice
Scott Baker40c00762014-08-21 16:55:59 -0700347 fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
348 readonly_fields = ('backend_status_icon', )
Tony Mack00d361f2013-04-28 10:28:42 -0400349 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400350 suit_classes = 'suit-tab suit-tab-slices'
351
Tony Mack5b061472014-02-04 07:57:10 -0500352 def queryset(self, request):
353 return Slice.select_by_user(request.user)
354
Siobhan Tullyd3515752013-06-21 16:34:53 -0400355class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400356 model = Node
357 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400358 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker40c00762014-08-21 16:55:59 -0700359 fields = ['backend_status_icon', 'name','deployment','site']
360 readonly_fields = ('backend_status_icon', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400361
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400362class DeploymentPrivilegeInline(PlStackTabularInline):
363 model = DeploymentPrivilege
364 extra = 0
365 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700366 fields = ['backend_status_icon', 'user','role','deployment']
367 readonly_fields = ('backend_status_icon', )
Tony Mack5b061472014-02-04 07:57:10 -0500368
369 def queryset(self, request):
370 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400371
Siobhan Tullyd3515752013-06-21 16:34:53 -0400372class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400373 model = SitePrivilege
374 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400375 suit_classes = 'suit-tab suit-tab-siteprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700376 fields = ['backend_status_icon', 'user','site', 'role']
377 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400378
Tony Mackc2835a92013-05-28 09:18:49 -0400379 def formfield_for_foreignkey(self, db_field, request, **kwargs):
380 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500381 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400382
383 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500384 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400385 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
386
Tony Mack5b061472014-02-04 07:57:10 -0500387 def queryset(self, request):
388 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400389
Tony Macke4be32f2014-03-11 20:45:25 -0400390class SiteDeploymentInline(PlStackTabularInline):
391 model = SiteDeployments
Tony Macke4be32f2014-03-11 20:45:25 -0400392 extra = 0
393 suit_classes = 'suit-tab suit-tab-deployments'
Scott Baker40c00762014-08-21 16:55:59 -0700394 fields = ['backend_status_icon', 'deployment','site']
395 readonly_fields = ('backend_status_icon', )
Tony Macke4be32f2014-03-11 20:45:25 -0400396
397 def formfield_for_foreignkey(self, db_field, request, **kwargs):
398 if db_field.name == 'site':
399 kwargs['queryset'] = Site.select_by_user(request.user)
400
401 if db_field.name == 'deployment':
402 kwargs['queryset'] = Deployment.select_by_user(request.user)
403 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
404
405 def queryset(self, request):
406 return SiteDeployments.select_by_user(request.user)
407
408
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400409class SlicePrivilegeInline(PlStackTabularInline):
410 model = SlicePrivilege
411 suit_classes = 'suit-tab suit-tab-sliceprivileges'
412 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700413 fields = ('backend_status_icon', 'user', 'slice', 'role')
414 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400415
Tony Mackc2835a92013-05-28 09:18:49 -0400416 def formfield_for_foreignkey(self, db_field, request, **kwargs):
417 if db_field.name == 'slice':
Scott Baker36f50872014-08-21 13:01:25 -0700418 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400419 if db_field.name == 'user':
Scott Baker36f50872014-08-21 13:01:25 -0700420 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400421
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400422 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400423
Tony Mack5b061472014-02-04 07:57:10 -0500424 def queryset(self, request):
425 return SlicePrivilege.select_by_user(request.user)
426
Scott Bakera0015eb2013-08-14 17:28:14 -0700427class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700428 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800429 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700430 extra = 0
431 verbose_name = "Network Connection"
432 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400433 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker40c00762014-08-21 16:55:59 -0700434 fields = ['backend_status_icon', 'network']
435 readonly_fields = ('backend_status_icon', )
Scott Baker2170b972014-06-03 12:14:07 -0700436
437class ImageDeploymentsInline(PlStackTabularInline):
438 model = ImageDeployments
439 extra = 0
440 verbose_name = "Image Deployments"
441 verbose_name_plural = "Image Deployments"
442 suit_classes = 'suit-tab suit-tab-imagedeployments'
Scott Baker40c00762014-08-21 16:55:59 -0700443 fields = ['backend_status_icon', 'image', 'deployment', 'glance_image_id']
444 readonly_fields = ['backend_status_icon', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700445
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500446class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400447 save_on_top = False
Scott Baker36f50872014-08-21 13:01:25 -0700448
Tony Mack332ee1d2014-02-04 15:33:45 -0500449 def save_model(self, request, obj, form, change):
Tony Mack3d042792014-03-17 19:18:37 -0400450 obj.caller = request.user
Tony Mack332ee1d2014-02-04 15:33:45 -0500451 # update openstack connection to use this site/tenant
452 obj.save_by_user(request.user)
453
454 def delete_model(self, request, obj):
455 obj.delete_by_user(request.user)
456
457 def save_formset(self, request, form, formset, change):
458 instances = formset.save(commit=False)
459 for instance in instances:
460 instance.save_by_user(request.user)
461 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400462
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400463class SliceRoleAdmin(PlanetStackBaseAdmin):
464 model = SliceRole
465 pass
466
467class SiteRoleAdmin(PlanetStackBaseAdmin):
468 model = SiteRole
469 pass
470
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400471class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400472 sites = forms.ModelMultipleChoiceField(
473 queryset=Site.objects.all(),
474 required=False,
Scott Baker70983182014-06-09 22:10:00 -0700475 help_text="Select which sites are allowed to host nodes in this deployment",
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400476 widget=FilteredSelectMultiple(
477 verbose_name=('Sites'), is_stacked=False
478 )
479 )
Scott Bakerde0f4412014-06-11 15:40:26 -0700480 images = forms.ModelMultipleChoiceField(
481 queryset=Image.objects.all(),
482 required=False,
483 help_text="Select which images should be deployed on this deployment",
484 widget=FilteredSelectMultiple(
485 verbose_name=('Images'), is_stacked=False
486 )
487 )
Scott Baker37b47902014-09-02 14:37:41 -0700488 flavors = forms.ModelMultipleChoiceField(
489 queryset=Flavor.objects.all(),
490 required=False,
491 help_text="Select which flavors should be usable on this deployment",
492 widget=FilteredSelectMultiple(
493 verbose_name=('Flavors'), is_stacked=False
494 )
495 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400496 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400497 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700498 many_to_many = ["flavors",]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400499
Siobhan Tully320b4622014-01-17 15:11:14 -0500500 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700501 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500502 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
503
Scott Baker5380c522014-06-06 14:49:43 -0700504 self.fields['accessControl'].initial = "allow site " + request.user.site.name
505
Siobhan Tully320b4622014-01-17 15:11:14 -0500506 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700507 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Scott Bakerde0f4412014-06-11 15:40:26 -0700508 self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
Scott Baker37b47902014-09-02 14:37:41 -0700509 self.fields['flavors'].initial = self.instance.flavors.all()
Scott Bakerde0f4412014-06-11 15:40:26 -0700510
511 def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
512 """ helper function for handling m2m relations from the MultipleChoiceField
513
514 this_obj: the source object we want to link from
515
516 selected_objs: a list of destination objects we want to link to
517
518 all_relations: the full set of relations involving this_obj, including ones we don't want
519
520 relation_class: the class that implements the relation from source to dest
521
522 local_attrname: field name representing this_obj in relation_class
523
524 foreign_attrname: field name representing selected_objs in relation_class
525
526 This function will remove all newobjclass relations from this_obj
527 that are not contained in selected_objs, and add any relations that
528 are in selected_objs but don't exist in the data model yet.
529 """
530
531 existing_dest_objs = []
532 for relation in list(all_relations):
533 if getattr(relation, foreign_attrname) not in selected_objs:
534 #print "deleting site", sdp.site
535 relation.delete()
536 else:
537 existing_dest_objs.append(getattr(relation, foreign_attrname))
538
539 for dest_obj in selected_objs:
540 if dest_obj not in existing_dest_objs:
541 #print "adding site", site
542 kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
543 relation = relation_class(**kwargs)
544 relation.save()
Siobhan Tully320b4622014-01-17 15:11:14 -0500545
546 def save(self, commit=True):
547 deployment = super(DeploymentAdminForm, self).save(commit=False)
548
Scott Baker37b47902014-09-02 14:37:41 -0700549 deployment.flavors = self.cleaned_data['flavors']
550
Siobhan Tully320b4622014-01-17 15:11:14 -0500551 if commit:
552 deployment.save()
553
554 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700555 # save_m2m() doesn't seem to work with 'through' relations. So we
556 # create/destroy the through models ourselves. There has to be
557 # a better way...
558
Scott Bakerde0f4412014-06-11 15:40:26 -0700559 self.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
560 self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
Scott Bakerc9b14f72014-05-22 13:44:20 -0700561
Scott Baker37b47902014-09-02 14:37:41 -0700562 self.save_m2m()
Siobhan Tully320b4622014-01-17 15:11:14 -0500563
564 return deployment
565
Scott Bakerff5e0f32014-05-22 14:40:27 -0700566class DeploymentAdminROForm(DeploymentAdminForm):
567 def save(self, commit=True):
568 raise PermissionDenied
569
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500570class SiteAssocInline(PlStackTabularInline):
571 model = Site.deployments.through
572 extra = 0
573 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400574
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400575class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500576 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700577 fieldList = ['backend_status_text', 'name', 'sites', 'images', 'flavors', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500578 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Scott Bakerde0f4412014-06-11 15:40:26 -0700579 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
Scott Baker63d1a552014-08-21 15:19:07 -0700580 list_display = ['backend_status_icon', 'name']
581 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700582 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500583
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500584 user_readonly_fields = ['name']
585
Scott Bakerde0f4412014-06-11 15:40:26 -0700586 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags')) # ,('imagedeployments','Images'))
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500587
Scott Bakerff5e0f32014-05-22 14:40:27 -0700588 def get_form(self, request, obj=None, **kwargs):
589 if request.user.isReadOnlyUser():
590 kwargs["form"] = DeploymentAdminROForm
591 else:
592 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700593 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
594
595 # from stackexchange: pass the request object into the form
596
597 class AdminFormMetaClass(adminForm):
598 def __new__(cls, *args, **kwargs):
599 kwargs['request'] = request
600 return adminForm(*args, **kwargs)
601
602 return AdminFormMetaClass
603
Siobhan Tullyce652d02013-10-08 21:52:35 -0400604class ServiceAttrAsTabInline(PlStackTabularInline):
605 model = ServiceAttribute
606 fields = ['name','value']
607 extra = 0
608 suit_classes = 'suit-tab suit-tab-serviceattrs'
609
Siobhan Tullyce652d02013-10-08 21:52:35 -0400610class ServiceAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700611 list_display = ("backend_status_icon","name","description","versionNumber","enabled","published")
612 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700613 fieldList = ["backend_status_text","name","description","versionNumber","enabled","published"]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500614 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
615 inlines = [ServiceAttrAsTabInline,SliceInline]
Scott Baker40c00762014-08-21 16:55:59 -0700616 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500617
618 user_readonly_fields = fieldList
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500619
620 suit_form_tabs =(('general', 'Service Details'),
621 ('slices','Slices'),
622 ('serviceattrs','Additional Attributes'),
623 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400624
Tony Mack0553f282013-06-10 22:54:50 -0400625class SiteAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700626 fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400627 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500628 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400629 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400630 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400631 suit_form_tabs =(('general', 'Site Details'),
632 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400633 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400634 ('deployments','Deployments'),
635 ('slices','Slices'),
Scott Baker36f50872014-08-21 13:01:25 -0700636 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400637 ('tags','Tags'),
638 )
Scott Baker40c00762014-08-21 16:55:59 -0700639 readonly_fields = ['backend_status_text', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500640
641 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500642
Scott Baker63d1a552014-08-21 15:19:07 -0700643 list_display = ('backend_status_icon', 'name', 'login_base','site_url', 'enabled')
644 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400645 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400646 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400647 search_fields = ['name']
648
Tony Mack04062832013-05-10 08:22:44 -0400649 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500650 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400651
Tony Mack5cd13202013-05-01 21:48:38 -0400652 def get_formsets(self, request, obj=None):
653 for inline in self.get_inline_instances(request, obj):
654 # hide MyInline in the add view
655 if obj is None:
656 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400657 if isinstance(inline, SliceInline):
658 inline.model.caller = request.user
659 yield inline.get_formset(request, obj)
660
661 def get_formsets(self, request, obj=None):
662 for inline in self.get_inline_instances(request, obj):
663 # hide MyInline in the add view
664 if obj is None:
665 continue
666 if isinstance(inline, SliverInline):
667 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400668 yield inline.get_formset(request, obj)
669
Scott Baker545db2a2013-12-09 18:44:43 -0800670 def accountLink(self, obj):
671 link_obj = obj.accounts.all()
672 if link_obj:
673 reverse_path = "admin:core_account_change"
674 url = reverse(reverse_path, args =(link_obj[0].id,))
675 return "<a href='%s'>%s</a>" % (url, "view billing details")
676 else:
677 return "no billing data for this site"
678 accountLink.allow_tags = True
679 accountLink.short_description = "Billing"
680
Tony Mack332ee1d2014-02-04 15:33:45 -0500681 def save_model(self, request, obj, form, change):
682 # update openstack connection to use this site/tenant
683 obj.save_by_user(request.user)
684
685 def delete_model(self, request, obj):
686 obj.delete_by_user(request.user)
687
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500688
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400689class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700690 fieldList = ['backend_status_text', 'user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400691 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500692 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400693 ]
Scott Baker40c00762014-08-21 16:55:59 -0700694 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700695 list_display = ('backend_status_icon', 'user', 'site', 'role')
696 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500697 user_readonly_fields = fieldList
698 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400699
Tony Mackc2835a92013-05-28 09:18:49 -0400700 def formfield_for_foreignkey(self, db_field, request, **kwargs):
701 if db_field.name == 'site':
702 if not request.user.is_admin:
703 # only show sites where user is an admin or pi
704 sites = set()
705 for site_privilege in SitePrivilege.objects.filer(user=request.user):
706 if site_privilege.role.role_type in ['admin', 'pi']:
707 sites.add(site_privilege.site)
708 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
709
710 if db_field.name == 'user':
711 if not request.user.is_admin:
712 # only show users from sites where caller has admin or pi role
713 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
714 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
715 sites = [site_privilege.site for site_privilege in site_privileges]
716 site_privileges = SitePrivilege.objects.filter(site__in=sites)
717 emails = [site_privilege.user.email for site_privilege in site_privileges]
718 users = User.objects.filter(email__in=emails)
719 kwargs['queryset'] = users
720
721 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
722
Tony Mack04062832013-05-10 08:22:44 -0400723 def queryset(self, request):
724 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400725 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400726 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500727 #if not request.user.is_admin:
728 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
729 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
730 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
731 # sites = Site.objects.filter(login_base__in=login_bases)
732 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400733 return qs
734
Siobhan Tullyce652d02013-10-08 21:52:35 -0400735class SliceForm(forms.ModelForm):
736 class Meta:
737 model = Slice
738 widgets = {
Scott Baker36f50872014-08-21 13:01:25 -0700739 'service': LinkedSelect
Siobhan Tullyce652d02013-10-08 21:52:35 -0400740 }
741
Tony Mack2bd5b412013-06-11 21:05:06 -0400742class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400743 form = SliceForm
Tony Mackfbb26fc2014-09-02 07:03:27 -0400744 fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500745 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Scott Baker40c00762014-08-21 16:55:59 -0700746 readonly_fields = ('backend_status_text', )
Tony Mack49f75b92014-08-27 11:44:09 -0400747 list_display = ('backend_status_icon', 'slicename', 'site','serviceClass', 'slice_url', 'max_slivers')
748 list_display_links = ('backend_status_icon', 'slicename', )
Siobhan Tully2d95e482013-09-06 10:56:06 -0400749 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400750
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500751 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400752
753 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400754 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400755 ('sliceprivileges','Privileges'),
756 ('slivers','Slivers'),
757 ('tags','Tags'),
758 ('reservations','Reservations'),
759 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400760
Scott Baker510fdbb2014-08-05 17:19:24 -0700761 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
762 #deployment_nodes = {}
763 #for node in Node.objects.all():
764 # deployment_nodes[node.deployment.id] = get(deployment_nodes, node.deployment.id, []).append( (node.id, node.name) )
765
766 deployment_nodes = []
767 for node in Node.objects.all():
768 deployment_nodes.append( (node.deployment.id, node.id, node.name) )
769
Scott Baker0a78cb52014-09-02 16:30:20 -0700770 sites = {}
771 for site in Site.objects.all():
772 sites[site.id] = site.login_base
773
Scott Baker510fdbb2014-08-05 17:19:24 -0700774 context["deployment_nodes"] = deployment_nodes
Scott Baker0a78cb52014-09-02 16:30:20 -0700775 context["sites"] = sites
Scott Baker510fdbb2014-08-05 17:19:24 -0700776
777 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
778
Tony Mackc2835a92013-05-28 09:18:49 -0400779 def formfield_for_foreignkey(self, db_field, request, **kwargs):
780 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500781 kwargs['queryset'] = Site.select_by_user(request.user)
Scott Baker0a78cb52014-09-02 16:30:20 -0700782 kwargs['widget'] = forms.Select(attrs={'onChange': "update_slice_name(this, $($(this).closest('div')[0]).find('.field-name input')[0].id)"})
Scott Baker40c00762014-08-21 16:55:59 -0700783
Tony Mackc2835a92013-05-28 09:18:49 -0400784 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
785
Tony Mack04062832013-05-10 08:22:44 -0400786 def queryset(self, request):
787 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500788 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400789
Tony Mack79748612013-05-01 14:52:03 -0400790 def get_formsets(self, request, obj=None):
791 for inline in self.get_inline_instances(request, obj):
792 # hide MyInline in the add view
793 if obj is None:
794 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400795 if isinstance(inline, SliverInline):
796 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400797 yield inline.get_formset(request, obj)
798
Tony Mack2bd5b412013-06-11 21:05:06 -0400799
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400800class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400801 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700802 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -0400803 ]
Scott Baker40c00762014-08-21 16:55:59 -0700804 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700805 list_display = ('backend_status_icon', 'user', 'slice', 'role')
806 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -0400807
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500808 user_readonly_fields = ['user', 'slice', 'role']
809 user_readonly_inlines = []
810
Tony Mackc2835a92013-05-28 09:18:49 -0400811 def formfield_for_foreignkey(self, db_field, request, **kwargs):
812 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500813 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400814
815 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500816 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400817
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400818 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400819
Tony Mack04062832013-05-10 08:22:44 -0400820 def queryset(self, request):
821 # admins can see all memberships. Users can only see memberships of
822 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500823 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400824
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400825 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400826 # update openstack connection to use this site/tenant
827 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400828 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400829 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400830 obj.save()
831
832 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400833 # update openstack connection to use this site/tenant
834 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400835 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400836 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400837 obj.delete()
838
Siobhan Tully567e3e62013-06-21 18:03:16 -0400839
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400840class ImageAdmin(PlanetStackBaseAdmin):
841
Scott Baker36f50872014-08-21 13:01:25 -0700842 fieldsets = [('Image Details',
Scott Baker40c00762014-08-21 16:55:59 -0700843 {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400844 'classes': ['suit-tab suit-tab-general']})
845 ]
Scott Baker40c00762014-08-21 16:55:59 -0700846 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400847
Scott Baker2170b972014-06-03 12:14:07 -0700848 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400849
Scott Baker2170b972014-06-03 12:14:07 -0700850 inlines = [SliverInline, ImageDeploymentsInline]
Scott Bakerb6f99242014-06-11 11:34:44 -0700851
Tony Mack32e1ce32014-05-07 13:29:41 -0400852 user_readonly_fields = ['name', 'disk_format', 'container_format']
Scott Bakerb27b62c2014-08-15 16:29:16 -0700853
Scott Baker63d1a552014-08-21 15:19:07 -0700854 list_display = ['backend_status_icon', 'name']
855 list_display_links = ('backend_status_icon', 'name', )
856
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400857class NodeForm(forms.ModelForm):
858 class Meta:
859 widgets = {
860 'site': LinkedSelect,
861 'deployment': LinkedSelect
862 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400863
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500864class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400865 form = NodeForm
Scott Baker63d1a552014-08-21 15:19:07 -0700866 list_display = ('backend_status_icon', 'name', 'site', 'deployment')
867 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400868 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500869
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400870 inlines = [TagInline,SliverInline]
Scott Baker40c00762014-08-21 16:55:59 -0700871 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
872 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400873
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500874 user_readonly_fields = ['name','site','deployment']
875 user_readonly_inlines = [TagInline,SliverInline]
876
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400877 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400878
Siobhan Tully567e3e62013-06-21 18:03:16 -0400879
Tony Mackd90cdbf2013-04-16 22:48:40 -0400880class SliverForm(forms.ModelForm):
881 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400882 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400883 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400884 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400885 widgets = {
886 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400887 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400888 'slice': LinkedSelect,
889 'deploymentNetwork': LinkedSelect,
890 'node': LinkedSelect,
891 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400892 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400893
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500894class TagAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700895 list_display = ['backend_status_icon', 'service', 'name', 'value', 'content_type', 'content_object',]
896 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500897 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
898 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400899
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400900class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400901 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400902 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700903 ('Sliver Details', {'fields': ['backend_status_text', 'slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400904 ]
Scott Baker40c00762014-08-21 16:55:59 -0700905 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700906 list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
907 list_display_links = ('backend_status_icon', 'ip',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400908
909 suit_form_tabs =(('general', 'Sliver Details'),
910 ('tags','Tags'),
911 )
912
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400913 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400914
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500915 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500916
Tony Mackc2835a92013-05-28 09:18:49 -0400917 def formfield_for_foreignkey(self, db_field, request, **kwargs):
918 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500919 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400920
921 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
922
Tony Mack04062832013-05-10 08:22:44 -0400923 def queryset(self, request):
Scott Baker36f50872014-08-21 13:01:25 -0700924 # admins can see all slivers. Users can only see slivers of
Tony Mack04062832013-05-10 08:22:44 -0400925 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500926 return Sliver.select_by_user(request.user)
927
Tony Mack04062832013-05-10 08:22:44 -0400928
Tony Mack1d6b85f2013-05-07 18:49:14 -0400929 def get_formsets(self, request, obj=None):
930 # make some fields read only if we are updating an existing record
931 if obj == None:
Scott Baker36f50872014-08-21 13:01:25 -0700932 #self.readonly_fields = ('ip', 'instance_name')
Scott Baker40c00762014-08-21 16:55:59 -0700933 self.readonly_fields = ('backend_status_text')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400934 else:
Scott Baker40c00762014-08-21 16:55:59 -0700935 self.readonly_fields = ('backend_status_text')
Scott Baker36f50872014-08-21 13:01:25 -0700936 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400937
938 for inline in self.get_inline_instances(request, obj):
939 # hide MyInline in the add view
940 if obj is None:
941 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700942 if isinstance(inline, SliverInline):
943 inline.model.caller = request.user
944 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400945
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500946 #def save_model(self, request, obj, form, change):
947 # # update openstack connection to use this site/tenant
948 # auth = request.session.get('auth', {})
949 # auth['tenant'] = obj.slice.name
950 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
951 # obj.creator = request.user
952 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400953
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500954 #def delete_model(self, request, obj):
955 # # update openstack connection to use this site/tenant
956 # auth = request.session.get('auth', {})
957 # auth['tenant'] = obj.slice.name
958 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
959 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400960
Siobhan Tully53437282013-04-26 19:30:27 -0400961class UserCreationForm(forms.ModelForm):
962 """A form for creating new users. Includes all the required
963 fields, plus a repeated password."""
964 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
965 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
966
967 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400968 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400969 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400970
971 def clean_password2(self):
972 # Check that the two password entries match
973 password1 = self.cleaned_data.get("password1")
974 password2 = self.cleaned_data.get("password2")
975 if password1 and password2 and password1 != password2:
976 raise forms.ValidationError("Passwords don't match")
977 return password2
978
979 def save(self, commit=True):
980 # Save the provided password in hashed format
981 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400982 user.password = self.cleaned_data["password1"]
983 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400984 if commit:
985 user.save()
986 return user
987
Siobhan Tully567e3e62013-06-21 18:03:16 -0400988
Siobhan Tully53437282013-04-26 19:30:27 -0400989class UserChangeForm(forms.ModelForm):
990 """A form for updating users. Includes all the fields on
991 the user, but replaces the password field with admin's
992 password hash display field.
993 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500994 password = ReadOnlyPasswordHashField(label='Password',
995 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400996
997 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400998 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400999
1000 def clean_password(self):
1001 # Regardless of what the user provides, return the initial value.
1002 # This is done here, rather than on the field, because the
1003 # field does not have access to the initial value
1004 return self.initial["password"]
1005
Scott Baker2c3cb642014-05-19 17:55:56 -07001006class UserDashboardViewInline(PlStackTabularInline):
1007 model = UserDashboardView
1008 extra = 0
1009 suit_classes = 'suit-tab suit-tab-dashboards'
1010 fields = ['user', 'dashboardView', 'order']
1011
Tony Mack2bd5b412013-06-11 21:05:06 -04001012class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -04001013 class Meta:
1014 app_label = "core"
1015
1016 # The forms to add and change user instances
1017 form = UserChangeForm
1018 add_form = UserCreationForm
1019
1020 # The fields to be used in displaying the User model.
1021 # These override the definitions on the base UserAdmin
1022 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001023 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001024 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -07001025 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001026
Scott Bakeradae55f2014-08-14 17:32:35 -07001027 fieldListLoginDetails = ['email','site','password','is_active','is_readonly','is_admin','public_key']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001028 fieldListContactInfo = ['firstname','lastname','phone','timezone']
1029
Siobhan Tully53437282013-04-26 19:30:27 -04001030 fieldsets = (
Scott Baker40c00762014-08-21 16:55:59 -07001031 ('Login Details', {'fields': ['backend_status_text', 'email', 'site','password', 'is_active', 'is_readonly', 'is_admin', 'public_key'], 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001032 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -07001033 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001034 #('Important dates', {'fields': ('last_login',)}),
1035 )
1036 add_fieldsets = (
1037 (None, {
1038 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001039 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -04001040 ),
1041 )
Scott Baker40c00762014-08-21 16:55:59 -07001042 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001043 search_fields = ('email',)
1044 ordering = ('email',)
1045 filter_horizontal = ()
1046
Scott Baker3ca51f62014-05-23 12:05:11 -07001047 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001048
Scott Baker2c3cb642014-05-19 17:55:56 -07001049 suit_form_tabs =(('general','Login Details'),
1050 ('contact','Contact Information'),
1051 ('sliceprivileges','Slice Privileges'),
1052 ('siteprivileges','Site Privileges'),
1053 ('deploymentprivileges','Deployment Privileges'),
1054 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001055
Tony Mackc2835a92013-05-28 09:18:49 -04001056 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1057 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001058 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001059
1060 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1061
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001062 def has_add_permission(self, request, obj=None):
1063 return (not self.__user_is_readonly(request))
1064
1065 def has_delete_permission(self, request, obj=None):
1066 return (not self.__user_is_readonly(request))
1067
1068 def get_actions(self,request):
1069 actions = super(UserAdmin,self).get_actions(request)
1070
1071 if self.__user_is_readonly(request):
1072 if 'delete_selected' in actions:
1073 del actions['delete_selected']
1074
1075 return actions
1076
1077 def change_view(self,request,object_id, extra_context=None):
1078
1079 if self.__user_is_readonly(request):
Scott Bakerf875eba2014-05-23 12:09:15 -07001080 if not hasattr(self, "readonly_save"):
1081 # save the original readonly fields
1082 self.readonly_save = self.readonly_fields
1083 self.inlines_save = self.inlines
Scott Bakerb27b62c2014-08-15 16:29:16 -07001084 if hasattr(self, "user_readonly_fields"):
1085 self.readonly_fields=self.user_readonly_fields
1086 if hasattr(self, "user_readonly_inlines"):
1087 self.inlines = self.user_readonly_inlines
Scott Bakerf875eba2014-05-23 12:09:15 -07001088 else:
1089 if hasattr(self, "readonly_save"):
1090 # restore the original readonly fields
1091 self.readonly_fields = self.readonly_save
1092 self.inlines = self.inlines_save
1093
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001094 try:
1095 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1096 except PermissionDenied:
1097 pass
1098 if request.method == 'POST':
1099 raise PermissionDenied
1100 request.readonly = True
1101 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1102
1103 def __user_is_readonly(self, request):
1104 #groups = [x.name for x in request.user.groups.all() ]
1105 #return "readonly" in groups
1106 return request.user.isReadOnlyUser()
1107
Tony Mack5b061472014-02-04 07:57:10 -05001108 def queryset(self, request):
1109 return User.select_by_user(request.user)
1110
Scott Baker40c00762014-08-21 16:55:59 -07001111 def backend_status_text(self, obj):
1112 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -07001113
Scott Baker40c00762014-08-21 16:55:59 -07001114 def backend_status_icon(self, obj):
1115 return mark_safe(backend_icon(obj))
1116 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -07001117
Scott Baker2c3cb642014-05-19 17:55:56 -07001118class DashboardViewAdmin(PlanetStackBaseAdmin):
1119 fieldsets = [('Dashboard View Details',
Scott Baker40c00762014-08-21 16:55:59 -07001120 {'fields': ['backend_status_text', 'name', 'url'],
Scott Baker2c3cb642014-05-19 17:55:56 -07001121 'classes': ['suit-tab suit-tab-general']})
1122 ]
Scott Baker40c00762014-08-21 16:55:59 -07001123 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001124
Scott Baker2c3cb642014-05-19 17:55:56 -07001125 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001126
Scott Baker0165fac2014-01-13 11:49:26 -08001127class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001128 model = ServiceResource
1129 extra = 0
1130
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001131class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001132 list_display = ('backend_status_icon', 'name', 'commitment', 'membershipFee')
1133 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001134 inlines = [ServiceResourceInline]
1135
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001136 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1137 user_readonly_inlines = []
1138
Scott Baker0165fac2014-01-13 11:49:26 -08001139class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001140 model = ReservedResource
1141 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001142 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001143
1144 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1145 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1146
1147 if db_field.name == 'resource':
1148 # restrict resources to those that the slice's service class allows
1149 if request._slice is not None:
1150 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1151 if len(field.queryset) > 0:
1152 field.initial = field.queryset.all()[0]
1153 else:
1154 field.queryset = field.queryset.none()
1155 elif db_field.name == 'sliver':
1156 # restrict slivers to those that belong to the slice
1157 if request._slice is not None:
1158 field.queryset = field.queryset.filter(slice = request._slice)
1159 else:
1160 field.queryset = field.queryset.none()
1161
1162 return field
1163
Tony Mack5b061472014-02-04 07:57:10 -05001164 def queryset(self, request):
1165 return ReservedResource.select_by_user(request.user)
1166
Scott Baker133c9212013-05-17 09:09:11 -07001167class ReservationChangeForm(forms.ModelForm):
1168 class Meta:
1169 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001170 widgets = {
1171 'slice' : LinkedSelect
1172 }
Scott Baker133c9212013-05-17 09:09:11 -07001173
1174class ReservationAddForm(forms.ModelForm):
1175 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1176 refresh = forms.CharField(widget=forms.HiddenInput())
1177
1178 class Media:
1179 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1180
1181 def clean_slice(self):
1182 slice = self.cleaned_data.get("slice")
1183 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1184 if len(x) == 0:
1185 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1186 return slice
1187
1188 class Meta:
1189 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001190 widgets = {
1191 'slice' : LinkedSelect
1192 }
1193
Scott Baker133c9212013-05-17 09:09:11 -07001194
1195class ReservationAddRefreshForm(ReservationAddForm):
1196 """ This form is displayed when the Reservation Form receives an update
1197 from the Slice dropdown onChange handler. It doesn't validate the
1198 data and doesn't save the data. This will cause the form to be
1199 redrawn.
1200 """
1201
Scott Baker8737e5f2013-05-17 09:35:32 -07001202 """ don't validate anything other than slice """
1203 dont_validate_fields = ("startTime", "duration")
1204
Scott Baker133c9212013-05-17 09:09:11 -07001205 def full_clean(self):
1206 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001207
1208 for fieldname in self.dont_validate_fields:
1209 if fieldname in self._errors:
1210 del self._errors[fieldname]
1211
Scott Baker133c9212013-05-17 09:09:11 -07001212 return result
1213
1214 """ don't save anything """
1215 def is_valid(self):
1216 return False
1217
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001218class ReservationAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001219 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001220 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001221 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001222 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001223 form = ReservationAddForm
1224
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001225 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1226
1227 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001228 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001229
Scott Baker133c9212013-05-17 09:09:11 -07001230 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001231 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001232 request._refresh = False
1233 request._slice = None
1234 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001235 # "refresh" will be set to "1" if the form was submitted due to
1236 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001237 if request.POST.get("refresh","1") == "1":
1238 request._refresh = True
1239 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001240
1241 # Keep track of the slice that was selected, so the
1242 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001243 request._slice = request.POST.get("slice",None)
1244 if (request._slice is not None):
1245 request._slice = Slice.objects.get(id=request._slice)
1246
1247 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1248 return result
1249
Scott Bakeracd45142013-05-19 16:19:16 -07001250 def changelist_view(self, request, extra_context = None):
1251 timezone.activate(request.user.timezone)
1252 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1253
Scott Baker133c9212013-05-17 09:09:11 -07001254 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001255 request._obj_ = obj
1256 if obj is not None:
1257 # For changes, set request._slice to the slice already set in the
1258 # object.
1259 request._slice = obj.slice
1260 self.form = ReservationChangeForm
1261 else:
1262 if getattr(request, "_refresh", False):
1263 self.form = ReservationAddRefreshForm
1264 else:
1265 self.form = ReservationAddForm
1266 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1267
Scott Baker133c9212013-05-17 09:09:11 -07001268 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001269 if (obj is not None):
1270 # Prevent slice from being changed after the reservation has been
1271 # created.
1272 return ['slice']
1273 else:
Scott Baker133c9212013-05-17 09:09:11 -07001274 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001275
Tony Mack5b061472014-02-04 07:57:10 -05001276 def queryset(self, request):
1277 return Reservation.select_by_user(request.user)
1278
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001279class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001280 list_display = ("backend_status_icon", "name", )
1281 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001282 user_readonly_fields = ['name']
1283 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001284
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001285class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001286 list_display = ("backend_status_icon", "name", )
1287 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001288 user_readonly_fields = ['name']
1289 user_readonly_inlines = []
1290
Scott Baker0165fac2014-01-13 11:49:26 -08001291class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001292 model = Router.networks.through
1293 extra = 0
1294 verbose_name_plural = "Routers"
1295 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001296 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001297
Scott Bakerb27b62c2014-08-15 16:29:16 -07001298class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001299 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07001300 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001301 verbose_name_plural = "Parameters"
1302 verbose_name = "Parameter"
1303 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07001304 fields = ['backend_status_icon', 'parameter', 'value']
1305 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001306
Scott Baker0165fac2014-01-13 11:49:26 -08001307class NetworkSliversInline(PlStackTabularInline):
Scott Baker40c00762014-08-21 16:55:59 -07001308 fields = ['backend_status_icon', 'network','sliver','ip']
1309 readonly_fields = ("backend_status_icon", "ip", )
Scott Baker74d8e622013-07-29 16:04:22 -07001310 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001311 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001312 extra = 0
1313 verbose_name_plural = "Slivers"
1314 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001315 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001316
Scott Baker0165fac2014-01-13 11:49:26 -08001317class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001318 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001319 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001320 extra = 0
1321 verbose_name_plural = "Slices"
1322 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001323 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Baker40c00762014-08-21 16:55:59 -07001324 fields = ['backend_status_icon', 'network','slice']
1325 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07001326
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001327class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001328 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
1329 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07001330 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001331
Scott Bakerd7d2a392013-08-06 08:57:30 -07001332 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001333
Siobhan Tully2d95e482013-09-06 10:56:06 -04001334 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001335 (None, {'fields': ['backend_status_text', 'name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001336
Scott Baker40c00762014-08-21 16:55:59 -07001337 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001338 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
Siobhan Tully2d95e482013-09-06 10:56:06 -04001339
1340 suit_form_tabs =(
1341 ('general','Network Details'),
1342 ('netparams', 'Parameters'),
1343 ('networkslivers','Slivers'),
1344 ('networkslices','Slices'),
1345 ('routers','Routers'),
1346 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001347class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001348 list_display = ("backend_status_icon", "name", "guaranteedBandwidth", "visibility")
1349 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001350 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1351 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001352
Scott Baker37b47902014-09-02 14:37:41 -07001353class FlavorAdmin(PlanetStackBaseAdmin):
1354 list_display = ("backend_status_icon", "name", "flavor", "order", "default")
1355 list_display_links = ("backend_status_icon", "name")
1356 user_readonly_fields = ("name", "flavor")
1357 fields = ("name", "description", "flavor", "order", "default")
1358
Tony Mack31c2b8f2013-04-26 20:01:42 -04001359# register a signal that caches the user's credentials when they log in
1360def cache_credentials(sender, user, request, **kwds):
1361 auth = {'username': request.POST['username'],
1362 'password': request.POST['password']}
1363 request.session['auth'] = auth
1364user_logged_in.connect(cache_credentials)
1365
Scott Baker15cddfa2013-12-09 13:45:19 -08001366def dollar_field(fieldName, short_description):
1367 def newFunc(self, obj):
1368 try:
1369 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1370 except:
1371 x=getattr(obj, fieldName, 0.0)
1372 return x
1373 newFunc.short_description = short_description
1374 return newFunc
1375
1376def right_dollar_field(fieldName, short_description):
1377 def newFunc(self, obj):
1378 try:
1379 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1380 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1381 except:
1382 x=getattr(obj, fieldName, 0.0)
1383 return x
1384 newFunc.short_description = short_description
1385 newFunc.allow_tags = True
1386 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001387
Scott Baker0165fac2014-01-13 11:49:26 -08001388class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001389 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001390 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001391 verbose_name_plural = "Charges"
1392 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001393 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001394 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1395 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1396 can_delete = False
1397 max_num = 0
1398
1399 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001400
1401class InvoiceAdmin(admin.ModelAdmin):
1402 list_display = ("date", "account")
1403
1404 inlines = [InvoiceChargeInline]
1405
Scott Baker9cb88a22013-12-09 18:56:00 -08001406 fields = ["date", "account", "dollar_amount"]
1407 readonly_fields = ["date", "account", "dollar_amount"]
1408
1409 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001410
Scott Baker0165fac2014-01-13 11:49:26 -08001411class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001412 model = Invoice
1413 extra = 0
1414 verbose_name_plural = "Invoices"
1415 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001416 fields = ["date", "dollar_amount"]
1417 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001418 suit_classes = 'suit-tab suit-tab-accountinvoice'
1419 can_delete=False
1420 max_num=0
1421
1422 dollar_amount = right_dollar_field("amount", "Amount")
1423
Scott Baker0165fac2014-01-13 11:49:26 -08001424class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001425 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001426 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001427 verbose_name_plural = "Charges"
1428 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001429 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001430 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1431 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001432 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001433 can_delete=False
1434 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001435
1436 def queryset(self, request):
1437 qs = super(PendingChargeInline, self).queryset(request)
1438 qs = qs.filter(state="pending")
1439 return qs
1440
Scott Baker15cddfa2013-12-09 13:45:19 -08001441 dollar_amount = right_dollar_field("amount", "Amount")
1442
Scott Baker0165fac2014-01-13 11:49:26 -08001443class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001444 model=Payment
1445 extra = 1
1446 verbose_name_plural = "Payments"
1447 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001448 fields = ["date", "dollar_amount"]
1449 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001450 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001451 can_delete=False
1452 max_num=0
1453
1454 dollar_amount = right_dollar_field("amount", "Amount")
1455
Scott Baker43105042013-12-06 23:23:36 -08001456class AccountAdmin(admin.ModelAdmin):
1457 list_display = ("site", "balance_due")
1458
1459 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1460
1461 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001462 (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 -08001463
Scott Baker15cddfa2013-12-09 13:45:19 -08001464 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001465
1466 suit_form_tabs =(
1467 ('general','Account Details'),
1468 ('accountinvoice', 'Invoices'),
1469 ('accountpayments', 'Payments'),
1470 ('accountpendingcharges','Pending Charges'),
1471 )
1472
Scott Baker15cddfa2013-12-09 13:45:19 -08001473 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1474 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1475 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1476
Siobhan Tully53437282013-04-26 19:30:27 -04001477# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001478admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001479# ... and, since we're not using Django's builtin permissions,
1480# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001481#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001482
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001483#Do not show django evolution in the admin interface
1484from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001485#admin.site.unregister(Version)
1486#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001487
1488
1489# When debugging it is often easier to see all the classes, but for regular use
1490# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001491showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001492
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001493admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001494admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001495admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001496admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001497admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001498admin.site.register(Network, NetworkAdmin)
1499admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001500admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001501admin.site.register(Account, AccountAdmin)
1502admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001503
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001504if True:
1505 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1506 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001507 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001508 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001509 admin.site.register(DeploymentRole)
1510 admin.site.register(SiteRole)
1511 admin.site.register(SliceRole)
1512 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001513 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001514 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1515 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001516 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001517 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001518 admin.site.register(DashboardView, DashboardViewAdmin)
Scott Baker37b47902014-09-02 14:37:41 -07001519 admin.site.register(Flavor, FlavorAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001520