blob: fad99a07a29dcaabf94e66c59b1a2ca8882eca56 [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 Baker7a61dc42014-09-02 17:08:20 -0700269 fields = ['backend_status_icon', 'all_ips_string', 'instance_name', 'slice', 'deploymentNetwork', 'flavor', '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 Baker7a61dc42014-09-02 17:08:20 -0700280 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_deployment_changed(this);"})
Scott Baker3b678742014-06-09 13:11:54 -0700281
282 field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700283
284 return field
285
Scott Baker434ca7e2014-08-15 12:29:20 -0700286"""
287 SMBAKER: This is the old code that implemented each network type as a
288 separate column in the sliver table.
Scott Baker74d8e622013-07-29 16:04:22 -0700289
Scott Baker434ca7e2014-08-15 12:29:20 -0700290 def _declared_fieldsets(self):
291 # Return None so django will call get_fieldsets and we can insert our
292 # dynamic fields
293 return None
294
295 def get_readonly_fields(self, request, obj=None):
296 readonly_fields = list(super(SliverInline, self).get_readonly_fields(request, obj))
297
298 # Lookup the networks that are bound to the slivers, and add those
299 # network names to the list of readonly fields.
300
301 for sliver in obj.slivers.all():
302 for nbs in sliver.networksliver_set.all():
303 if nbs.ip:
304 network_name = nbs.network.name
305 if network_name not in [str(x) for x in readonly_fields]:
306 readonly_fields.append(NetworkLookerUpper.get(network_name))
307
308 return readonly_fields
309
310 def get_fieldsets(self, request, obj=None):
311 form = self.get_formset(request, obj).form
312 # fields = the read/write files + the read-only fields
313 fields = list(self.fields)
314 for fieldName in self.get_readonly_fields(request,obj):
315 if not fieldName in fields:
316 fields.append(fieldName)
317
318 return [(None, {'fields': fields})]
319"""
Siobhan Tully567e3e62013-06-21 18:03:16 -0400320
Siobhan Tullyd3515752013-06-21 16:34:53 -0400321class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400322 model = Site
323 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400324 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400325
Tony Mack5b061472014-02-04 07:57:10 -0500326 def queryset(self, request):
327 return Site.select_by_user(request.user)
328
Siobhan Tullyd3515752013-06-21 16:34:53 -0400329class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400330 model = User
Scott Baker40c00762014-08-21 16:55:59 -0700331 fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
332 readonly_fields = ('backend_status_icon', )
Siobhan Tully30fd4292013-05-10 08:59:56 -0400333 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400334 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400335
Tony Mack5b061472014-02-04 07:57:10 -0500336 def queryset(self, request):
337 return User.select_by_user(request.user)
338
Siobhan Tullyd3515752013-06-21 16:34:53 -0400339class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400340 model = Slice
Scott Baker40c00762014-08-21 16:55:59 -0700341 fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
342 readonly_fields = ('backend_status_icon', )
Tony Mack00d361f2013-04-28 10:28:42 -0400343 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400344 suit_classes = 'suit-tab suit-tab-slices'
345
Tony Mack5b061472014-02-04 07:57:10 -0500346 def queryset(self, request):
347 return Slice.select_by_user(request.user)
348
Siobhan Tullyd3515752013-06-21 16:34:53 -0400349class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400350 model = Node
351 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400352 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker40c00762014-08-21 16:55:59 -0700353 fields = ['backend_status_icon', 'name','deployment','site']
354 readonly_fields = ('backend_status_icon', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400355
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400356class DeploymentPrivilegeInline(PlStackTabularInline):
357 model = DeploymentPrivilege
358 extra = 0
359 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700360 fields = ['backend_status_icon', 'user','role','deployment']
361 readonly_fields = ('backend_status_icon', )
Tony Mack5b061472014-02-04 07:57:10 -0500362
363 def queryset(self, request):
364 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400365
Siobhan Tullyd3515752013-06-21 16:34:53 -0400366class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400367 model = SitePrivilege
368 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400369 suit_classes = 'suit-tab suit-tab-siteprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700370 fields = ['backend_status_icon', 'user','site', 'role']
371 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400372
Tony Mackc2835a92013-05-28 09:18:49 -0400373 def formfield_for_foreignkey(self, db_field, request, **kwargs):
374 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500375 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400376
377 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500378 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400379 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
380
Tony Mack5b061472014-02-04 07:57:10 -0500381 def queryset(self, request):
382 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400383
Tony Macke4be32f2014-03-11 20:45:25 -0400384class SiteDeploymentInline(PlStackTabularInline):
385 model = SiteDeployments
Tony Macke4be32f2014-03-11 20:45:25 -0400386 extra = 0
387 suit_classes = 'suit-tab suit-tab-deployments'
Scott Baker40c00762014-08-21 16:55:59 -0700388 fields = ['backend_status_icon', 'deployment','site']
389 readonly_fields = ('backend_status_icon', )
Tony Macke4be32f2014-03-11 20:45:25 -0400390
391 def formfield_for_foreignkey(self, db_field, request, **kwargs):
392 if db_field.name == 'site':
393 kwargs['queryset'] = Site.select_by_user(request.user)
394
395 if db_field.name == 'deployment':
396 kwargs['queryset'] = Deployment.select_by_user(request.user)
397 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
398
399 def queryset(self, request):
400 return SiteDeployments.select_by_user(request.user)
401
402
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400403class SlicePrivilegeInline(PlStackTabularInline):
404 model = SlicePrivilege
405 suit_classes = 'suit-tab suit-tab-sliceprivileges'
406 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700407 fields = ('backend_status_icon', 'user', 'slice', 'role')
408 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400409
Tony Mackc2835a92013-05-28 09:18:49 -0400410 def formfield_for_foreignkey(self, db_field, request, **kwargs):
411 if db_field.name == 'slice':
Scott Baker36f50872014-08-21 13:01:25 -0700412 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400413 if db_field.name == 'user':
Scott Baker36f50872014-08-21 13:01:25 -0700414 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400415
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400416 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400417
Tony Mack5b061472014-02-04 07:57:10 -0500418 def queryset(self, request):
419 return SlicePrivilege.select_by_user(request.user)
420
Scott Bakera0015eb2013-08-14 17:28:14 -0700421class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700422 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800423 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700424 extra = 0
425 verbose_name = "Network Connection"
426 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400427 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker40c00762014-08-21 16:55:59 -0700428 fields = ['backend_status_icon', 'network']
429 readonly_fields = ('backend_status_icon', )
Scott Baker2170b972014-06-03 12:14:07 -0700430
431class ImageDeploymentsInline(PlStackTabularInline):
432 model = ImageDeployments
433 extra = 0
434 verbose_name = "Image Deployments"
435 verbose_name_plural = "Image Deployments"
436 suit_classes = 'suit-tab suit-tab-imagedeployments'
Scott Baker40c00762014-08-21 16:55:59 -0700437 fields = ['backend_status_icon', 'image', 'deployment', 'glance_image_id']
438 readonly_fields = ['backend_status_icon', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700439
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500440class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400441 save_on_top = False
Scott Baker36f50872014-08-21 13:01:25 -0700442
Tony Mack332ee1d2014-02-04 15:33:45 -0500443 def save_model(self, request, obj, form, change):
Tony Mack3d042792014-03-17 19:18:37 -0400444 obj.caller = request.user
Tony Mack332ee1d2014-02-04 15:33:45 -0500445 # update openstack connection to use this site/tenant
446 obj.save_by_user(request.user)
447
448 def delete_model(self, request, obj):
449 obj.delete_by_user(request.user)
450
451 def save_formset(self, request, form, formset, change):
452 instances = formset.save(commit=False)
453 for instance in instances:
454 instance.save_by_user(request.user)
455 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400456
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400457class SliceRoleAdmin(PlanetStackBaseAdmin):
458 model = SliceRole
459 pass
460
461class SiteRoleAdmin(PlanetStackBaseAdmin):
462 model = SiteRole
463 pass
464
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400465class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400466 sites = forms.ModelMultipleChoiceField(
467 queryset=Site.objects.all(),
468 required=False,
Scott Baker70983182014-06-09 22:10:00 -0700469 help_text="Select which sites are allowed to host nodes in this deployment",
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400470 widget=FilteredSelectMultiple(
471 verbose_name=('Sites'), is_stacked=False
472 )
473 )
Scott Bakerde0f4412014-06-11 15:40:26 -0700474 images = forms.ModelMultipleChoiceField(
475 queryset=Image.objects.all(),
476 required=False,
477 help_text="Select which images should be deployed on this deployment",
478 widget=FilteredSelectMultiple(
479 verbose_name=('Images'), is_stacked=False
480 )
481 )
Scott Baker37b47902014-09-02 14:37:41 -0700482 flavors = forms.ModelMultipleChoiceField(
483 queryset=Flavor.objects.all(),
484 required=False,
485 help_text="Select which flavors should be usable on this deployment",
486 widget=FilteredSelectMultiple(
487 verbose_name=('Flavors'), is_stacked=False
488 )
489 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400490 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400491 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700492 many_to_many = ["flavors",]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400493
Siobhan Tully320b4622014-01-17 15:11:14 -0500494 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700495 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500496 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
497
Scott Baker5380c522014-06-06 14:49:43 -0700498 self.fields['accessControl'].initial = "allow site " + request.user.site.name
499
Siobhan Tully320b4622014-01-17 15:11:14 -0500500 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700501 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Scott Bakerde0f4412014-06-11 15:40:26 -0700502 self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
Scott Baker37b47902014-09-02 14:37:41 -0700503 self.fields['flavors'].initial = self.instance.flavors.all()
Scott Bakerde0f4412014-06-11 15:40:26 -0700504
505 def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
506 """ helper function for handling m2m relations from the MultipleChoiceField
507
508 this_obj: the source object we want to link from
509
510 selected_objs: a list of destination objects we want to link to
511
512 all_relations: the full set of relations involving this_obj, including ones we don't want
513
514 relation_class: the class that implements the relation from source to dest
515
516 local_attrname: field name representing this_obj in relation_class
517
518 foreign_attrname: field name representing selected_objs in relation_class
519
520 This function will remove all newobjclass relations from this_obj
521 that are not contained in selected_objs, and add any relations that
522 are in selected_objs but don't exist in the data model yet.
523 """
524
525 existing_dest_objs = []
526 for relation in list(all_relations):
527 if getattr(relation, foreign_attrname) not in selected_objs:
528 #print "deleting site", sdp.site
529 relation.delete()
530 else:
531 existing_dest_objs.append(getattr(relation, foreign_attrname))
532
533 for dest_obj in selected_objs:
534 if dest_obj not in existing_dest_objs:
535 #print "adding site", site
536 kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
537 relation = relation_class(**kwargs)
538 relation.save()
Siobhan Tully320b4622014-01-17 15:11:14 -0500539
540 def save(self, commit=True):
541 deployment = super(DeploymentAdminForm, self).save(commit=False)
542
Scott Baker37b47902014-09-02 14:37:41 -0700543 deployment.flavors = self.cleaned_data['flavors']
544
Siobhan Tully320b4622014-01-17 15:11:14 -0500545 if commit:
546 deployment.save()
547
548 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700549 # save_m2m() doesn't seem to work with 'through' relations. So we
550 # create/destroy the through models ourselves. There has to be
551 # a better way...
552
Scott Bakerde0f4412014-06-11 15:40:26 -0700553 self.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
554 self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
Scott Bakerc9b14f72014-05-22 13:44:20 -0700555
Scott Baker37b47902014-09-02 14:37:41 -0700556 self.save_m2m()
Siobhan Tully320b4622014-01-17 15:11:14 -0500557
558 return deployment
559
Scott Bakerff5e0f32014-05-22 14:40:27 -0700560class DeploymentAdminROForm(DeploymentAdminForm):
561 def save(self, commit=True):
562 raise PermissionDenied
563
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500564class SiteAssocInline(PlStackTabularInline):
565 model = Site.deployments.through
566 extra = 0
567 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400568
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400569class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500570 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700571 fieldList = ['backend_status_text', 'name', 'sites', 'images', 'flavors', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500572 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Scott Bakerde0f4412014-06-11 15:40:26 -0700573 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
Scott Baker63d1a552014-08-21 15:19:07 -0700574 list_display = ['backend_status_icon', 'name']
575 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700576 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500577
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500578 user_readonly_fields = ['name']
579
Scott Bakerde0f4412014-06-11 15:40:26 -0700580 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags')) # ,('imagedeployments','Images'))
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500581
Scott Bakerff5e0f32014-05-22 14:40:27 -0700582 def get_form(self, request, obj=None, **kwargs):
583 if request.user.isReadOnlyUser():
584 kwargs["form"] = DeploymentAdminROForm
585 else:
586 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700587 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
588
589 # from stackexchange: pass the request object into the form
590
591 class AdminFormMetaClass(adminForm):
592 def __new__(cls, *args, **kwargs):
593 kwargs['request'] = request
594 return adminForm(*args, **kwargs)
595
596 return AdminFormMetaClass
597
Siobhan Tullyce652d02013-10-08 21:52:35 -0400598class ServiceAttrAsTabInline(PlStackTabularInline):
599 model = ServiceAttribute
600 fields = ['name','value']
601 extra = 0
602 suit_classes = 'suit-tab suit-tab-serviceattrs'
603
Siobhan Tullyce652d02013-10-08 21:52:35 -0400604class ServiceAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700605 list_display = ("backend_status_icon","name","description","versionNumber","enabled","published")
606 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700607 fieldList = ["backend_status_text","name","description","versionNumber","enabled","published"]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500608 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
609 inlines = [ServiceAttrAsTabInline,SliceInline]
Scott Baker40c00762014-08-21 16:55:59 -0700610 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500611
612 user_readonly_fields = fieldList
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500613
614 suit_form_tabs =(('general', 'Service Details'),
615 ('slices','Slices'),
616 ('serviceattrs','Additional Attributes'),
617 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400618
Tony Mack0553f282013-06-10 22:54:50 -0400619class SiteAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700620 fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400621 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500622 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400623 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400624 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400625 suit_form_tabs =(('general', 'Site Details'),
626 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400627 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400628 ('deployments','Deployments'),
629 ('slices','Slices'),
Scott Baker36f50872014-08-21 13:01:25 -0700630 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400631 ('tags','Tags'),
632 )
Scott Baker40c00762014-08-21 16:55:59 -0700633 readonly_fields = ['backend_status_text', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500634
635 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500636
Scott Baker63d1a552014-08-21 15:19:07 -0700637 list_display = ('backend_status_icon', 'name', 'login_base','site_url', 'enabled')
638 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400639 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400640 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400641 search_fields = ['name']
642
Tony Mack04062832013-05-10 08:22:44 -0400643 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500644 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400645
Tony Mack5cd13202013-05-01 21:48:38 -0400646 def get_formsets(self, request, obj=None):
647 for inline in self.get_inline_instances(request, obj):
648 # hide MyInline in the add view
649 if obj is None:
650 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400651 if isinstance(inline, SliceInline):
652 inline.model.caller = request.user
653 yield inline.get_formset(request, obj)
654
655 def get_formsets(self, request, obj=None):
656 for inline in self.get_inline_instances(request, obj):
657 # hide MyInline in the add view
658 if obj is None:
659 continue
660 if isinstance(inline, SliverInline):
661 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400662 yield inline.get_formset(request, obj)
663
Scott Baker545db2a2013-12-09 18:44:43 -0800664 def accountLink(self, obj):
665 link_obj = obj.accounts.all()
666 if link_obj:
667 reverse_path = "admin:core_account_change"
668 url = reverse(reverse_path, args =(link_obj[0].id,))
669 return "<a href='%s'>%s</a>" % (url, "view billing details")
670 else:
671 return "no billing data for this site"
672 accountLink.allow_tags = True
673 accountLink.short_description = "Billing"
674
Tony Mack332ee1d2014-02-04 15:33:45 -0500675 def save_model(self, request, obj, form, change):
676 # update openstack connection to use this site/tenant
677 obj.save_by_user(request.user)
678
679 def delete_model(self, request, obj):
680 obj.delete_by_user(request.user)
681
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500682
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400683class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700684 fieldList = ['backend_status_text', 'user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400685 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500686 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400687 ]
Scott Baker40c00762014-08-21 16:55:59 -0700688 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700689 list_display = ('backend_status_icon', 'user', 'site', 'role')
690 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500691 user_readonly_fields = fieldList
692 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400693
Tony Mackc2835a92013-05-28 09:18:49 -0400694 def formfield_for_foreignkey(self, db_field, request, **kwargs):
695 if db_field.name == 'site':
696 if not request.user.is_admin:
697 # only show sites where user is an admin or pi
698 sites = set()
699 for site_privilege in SitePrivilege.objects.filer(user=request.user):
700 if site_privilege.role.role_type in ['admin', 'pi']:
701 sites.add(site_privilege.site)
702 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
703
704 if db_field.name == 'user':
705 if not request.user.is_admin:
706 # only show users from sites where caller has admin or pi role
707 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
708 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
709 sites = [site_privilege.site for site_privilege in site_privileges]
710 site_privileges = SitePrivilege.objects.filter(site__in=sites)
711 emails = [site_privilege.user.email for site_privilege in site_privileges]
712 users = User.objects.filter(email__in=emails)
713 kwargs['queryset'] = users
714
715 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
716
Tony Mack04062832013-05-10 08:22:44 -0400717 def queryset(self, request):
718 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400719 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400720 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500721 #if not request.user.is_admin:
722 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
723 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
724 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
725 # sites = Site.objects.filter(login_base__in=login_bases)
726 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400727 return qs
728
Siobhan Tullyce652d02013-10-08 21:52:35 -0400729class SliceForm(forms.ModelForm):
730 class Meta:
731 model = Slice
732 widgets = {
Scott Baker36f50872014-08-21 13:01:25 -0700733 'service': LinkedSelect
Siobhan Tullyce652d02013-10-08 21:52:35 -0400734 }
735
Tony Mack2bd5b412013-06-11 21:05:06 -0400736class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400737 form = SliceForm
Tony Mackfbb26fc2014-09-02 07:03:27 -0400738 fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500739 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Scott Baker40c00762014-08-21 16:55:59 -0700740 readonly_fields = ('backend_status_text', )
Tony Mack49f75b92014-08-27 11:44:09 -0400741 list_display = ('backend_status_icon', 'slicename', 'site','serviceClass', 'slice_url', 'max_slivers')
742 list_display_links = ('backend_status_icon', 'slicename', )
Siobhan Tully2d95e482013-09-06 10:56:06 -0400743 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400744
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500745 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400746
747 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400748 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400749 ('sliceprivileges','Privileges'),
750 ('slivers','Slivers'),
751 ('tags','Tags'),
752 ('reservations','Reservations'),
753 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400754
Scott Baker510fdbb2014-08-05 17:19:24 -0700755 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
Scott Baker510fdbb2014-08-05 17:19:24 -0700756 deployment_nodes = []
757 for node in Node.objects.all():
758 deployment_nodes.append( (node.deployment.id, node.id, node.name) )
759
Scott Baker7a61dc42014-09-02 17:08:20 -0700760 deployment_flavors = []
761 for flavor in Flavor.objects.all():
762 for deployment in flavor.deployments.all():
763 deployment_flavors.append( (deployment.id, flavor.id, flavor.name) )
764
Scott Baker0a78cb52014-09-02 16:30:20 -0700765 sites = {}
766 for site in Site.objects.all():
767 sites[site.id] = site.login_base
768
Scott Baker510fdbb2014-08-05 17:19:24 -0700769 context["deployment_nodes"] = deployment_nodes
Scott Baker7a61dc42014-09-02 17:08:20 -0700770 context["deployment_flavors"] = deployment_flavors
Scott Baker0a78cb52014-09-02 16:30:20 -0700771 context["sites"] = sites
Scott Baker510fdbb2014-08-05 17:19:24 -0700772
773 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
774
Tony Mackc2835a92013-05-28 09:18:49 -0400775 def formfield_for_foreignkey(self, db_field, request, **kwargs):
776 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500777 kwargs['queryset'] = Site.select_by_user(request.user)
Scott Baker0a78cb52014-09-02 16:30:20 -0700778 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 -0700779
Tony Mackc2835a92013-05-28 09:18:49 -0400780 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
781
Tony Mack04062832013-05-10 08:22:44 -0400782 def queryset(self, request):
783 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500784 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400785
Tony Mack79748612013-05-01 14:52:03 -0400786 def get_formsets(self, request, obj=None):
787 for inline in self.get_inline_instances(request, obj):
788 # hide MyInline in the add view
789 if obj is None:
790 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400791 if isinstance(inline, SliverInline):
792 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400793 yield inline.get_formset(request, obj)
794
Tony Mack2bd5b412013-06-11 21:05:06 -0400795
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400796class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400797 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700798 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -0400799 ]
Scott Baker40c00762014-08-21 16:55:59 -0700800 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700801 list_display = ('backend_status_icon', 'user', 'slice', 'role')
802 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -0400803
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500804 user_readonly_fields = ['user', 'slice', 'role']
805 user_readonly_inlines = []
806
Tony Mackc2835a92013-05-28 09:18:49 -0400807 def formfield_for_foreignkey(self, db_field, request, **kwargs):
808 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500809 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400810
811 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500812 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400813
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400814 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400815
Tony Mack04062832013-05-10 08:22:44 -0400816 def queryset(self, request):
817 # admins can see all memberships. Users can only see memberships of
818 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500819 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400820
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400821 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400822 # update openstack connection to use this site/tenant
823 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400824 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400825 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400826 obj.save()
827
828 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400829 # update openstack connection to use this site/tenant
830 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400831 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400832 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400833 obj.delete()
834
Siobhan Tully567e3e62013-06-21 18:03:16 -0400835
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400836class ImageAdmin(PlanetStackBaseAdmin):
837
Scott Baker36f50872014-08-21 13:01:25 -0700838 fieldsets = [('Image Details',
Scott Baker40c00762014-08-21 16:55:59 -0700839 {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400840 'classes': ['suit-tab suit-tab-general']})
841 ]
Scott Baker40c00762014-08-21 16:55:59 -0700842 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400843
Scott Baker2170b972014-06-03 12:14:07 -0700844 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400845
Scott Baker2170b972014-06-03 12:14:07 -0700846 inlines = [SliverInline, ImageDeploymentsInline]
Scott Bakerb6f99242014-06-11 11:34:44 -0700847
Tony Mack32e1ce32014-05-07 13:29:41 -0400848 user_readonly_fields = ['name', 'disk_format', 'container_format']
Scott Bakerb27b62c2014-08-15 16:29:16 -0700849
Scott Baker63d1a552014-08-21 15:19:07 -0700850 list_display = ['backend_status_icon', 'name']
851 list_display_links = ('backend_status_icon', 'name', )
852
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400853class NodeForm(forms.ModelForm):
854 class Meta:
855 widgets = {
856 'site': LinkedSelect,
857 'deployment': LinkedSelect
858 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400859
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500860class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400861 form = NodeForm
Scott Baker63d1a552014-08-21 15:19:07 -0700862 list_display = ('backend_status_icon', 'name', 'site', 'deployment')
863 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400864 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500865
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400866 inlines = [TagInline,SliverInline]
Scott Baker40c00762014-08-21 16:55:59 -0700867 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
868 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400869
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500870 user_readonly_fields = ['name','site','deployment']
871 user_readonly_inlines = [TagInline,SliverInline]
872
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400873 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400874
Siobhan Tully567e3e62013-06-21 18:03:16 -0400875
Tony Mackd90cdbf2013-04-16 22:48:40 -0400876class SliverForm(forms.ModelForm):
877 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400878 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400879 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400880 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400881 widgets = {
882 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400883 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400884 'slice': LinkedSelect,
885 'deploymentNetwork': LinkedSelect,
886 'node': LinkedSelect,
887 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400888 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400889
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500890class TagAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700891 list_display = ['backend_status_icon', 'service', 'name', 'value', 'content_type', 'content_object',]
892 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500893 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
894 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400895
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400896class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400897 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400898 fieldsets = [
Scott Baker7a61dc42014-09-02 17:08:20 -0700899 ('Sliver Details', {'fields': ['backend_status_text', 'slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400900 ]
Scott Baker40c00762014-08-21 16:55:59 -0700901 readonly_fields = ('backend_status_text', )
Scott Baker7a61dc42014-09-02 17:08:20 -0700902 list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deploymentNetwork']
Scott Baker63d1a552014-08-21 15:19:07 -0700903 list_display_links = ('backend_status_icon', 'ip',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400904
905 suit_form_tabs =(('general', 'Sliver Details'),
906 ('tags','Tags'),
907 )
908
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400909 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400910
Scott Baker7a61dc42014-09-02 17:08:20 -0700911 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500912
Tony Mackc2835a92013-05-28 09:18:49 -0400913 def formfield_for_foreignkey(self, db_field, request, **kwargs):
914 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500915 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400916
917 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
918
Tony Mack04062832013-05-10 08:22:44 -0400919 def queryset(self, request):
Scott Baker36f50872014-08-21 13:01:25 -0700920 # admins can see all slivers. Users can only see slivers of
Tony Mack04062832013-05-10 08:22:44 -0400921 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500922 return Sliver.select_by_user(request.user)
923
Tony Mack04062832013-05-10 08:22:44 -0400924
Tony Mack1d6b85f2013-05-07 18:49:14 -0400925 def get_formsets(self, request, obj=None):
926 # make some fields read only if we are updating an existing record
927 if obj == None:
Scott Baker36f50872014-08-21 13:01:25 -0700928 #self.readonly_fields = ('ip', 'instance_name')
Scott Baker40c00762014-08-21 16:55:59 -0700929 self.readonly_fields = ('backend_status_text')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400930 else:
Scott Baker40c00762014-08-21 16:55:59 -0700931 self.readonly_fields = ('backend_status_text')
Scott Baker36f50872014-08-21 13:01:25 -0700932 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400933
934 for inline in self.get_inline_instances(request, obj):
935 # hide MyInline in the add view
936 if obj is None:
937 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700938 if isinstance(inline, SliverInline):
939 inline.model.caller = request.user
940 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400941
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500942 #def save_model(self, request, obj, form, change):
943 # # update openstack connection to use this site/tenant
944 # auth = request.session.get('auth', {})
945 # auth['tenant'] = obj.slice.name
946 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
947 # obj.creator = request.user
948 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400949
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500950 #def delete_model(self, request, obj):
951 # # update openstack connection to use this site/tenant
952 # auth = request.session.get('auth', {})
953 # auth['tenant'] = obj.slice.name
954 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
955 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400956
Siobhan Tully53437282013-04-26 19:30:27 -0400957class UserCreationForm(forms.ModelForm):
958 """A form for creating new users. Includes all the required
959 fields, plus a repeated password."""
960 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
961 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
962
963 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400964 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400965 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400966
967 def clean_password2(self):
968 # Check that the two password entries match
969 password1 = self.cleaned_data.get("password1")
970 password2 = self.cleaned_data.get("password2")
971 if password1 and password2 and password1 != password2:
972 raise forms.ValidationError("Passwords don't match")
973 return password2
974
975 def save(self, commit=True):
976 # Save the provided password in hashed format
977 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400978 user.password = self.cleaned_data["password1"]
979 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400980 if commit:
981 user.save()
982 return user
983
Siobhan Tully567e3e62013-06-21 18:03:16 -0400984
Siobhan Tully53437282013-04-26 19:30:27 -0400985class UserChangeForm(forms.ModelForm):
986 """A form for updating users. Includes all the fields on
987 the user, but replaces the password field with admin's
988 password hash display field.
989 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500990 password = ReadOnlyPasswordHashField(label='Password',
991 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400992
993 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400994 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400995
996 def clean_password(self):
997 # Regardless of what the user provides, return the initial value.
998 # This is done here, rather than on the field, because the
999 # field does not have access to the initial value
1000 return self.initial["password"]
1001
Scott Baker2c3cb642014-05-19 17:55:56 -07001002class UserDashboardViewInline(PlStackTabularInline):
1003 model = UserDashboardView
1004 extra = 0
1005 suit_classes = 'suit-tab suit-tab-dashboards'
1006 fields = ['user', 'dashboardView', 'order']
1007
Tony Mack2bd5b412013-06-11 21:05:06 -04001008class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -04001009 class Meta:
1010 app_label = "core"
1011
1012 # The forms to add and change user instances
1013 form = UserChangeForm
1014 add_form = UserCreationForm
1015
1016 # The fields to be used in displaying the User model.
1017 # These override the definitions on the base UserAdmin
1018 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001019 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001020 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -07001021 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001022
Scott Bakeradae55f2014-08-14 17:32:35 -07001023 fieldListLoginDetails = ['email','site','password','is_active','is_readonly','is_admin','public_key']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001024 fieldListContactInfo = ['firstname','lastname','phone','timezone']
1025
Siobhan Tully53437282013-04-26 19:30:27 -04001026 fieldsets = (
Scott Baker40c00762014-08-21 16:55:59 -07001027 ('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 -04001028 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -07001029 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001030 #('Important dates', {'fields': ('last_login',)}),
1031 )
1032 add_fieldsets = (
1033 (None, {
1034 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001035 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -04001036 ),
1037 )
Scott Baker40c00762014-08-21 16:55:59 -07001038 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001039 search_fields = ('email',)
1040 ordering = ('email',)
1041 filter_horizontal = ()
1042
Scott Baker3ca51f62014-05-23 12:05:11 -07001043 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001044
Scott Baker2c3cb642014-05-19 17:55:56 -07001045 suit_form_tabs =(('general','Login Details'),
1046 ('contact','Contact Information'),
1047 ('sliceprivileges','Slice Privileges'),
1048 ('siteprivileges','Site Privileges'),
1049 ('deploymentprivileges','Deployment Privileges'),
1050 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001051
Tony Mackc2835a92013-05-28 09:18:49 -04001052 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1053 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001054 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001055
1056 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1057
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001058 def has_add_permission(self, request, obj=None):
1059 return (not self.__user_is_readonly(request))
1060
1061 def has_delete_permission(self, request, obj=None):
1062 return (not self.__user_is_readonly(request))
1063
1064 def get_actions(self,request):
1065 actions = super(UserAdmin,self).get_actions(request)
1066
1067 if self.__user_is_readonly(request):
1068 if 'delete_selected' in actions:
1069 del actions['delete_selected']
1070
1071 return actions
1072
1073 def change_view(self,request,object_id, extra_context=None):
1074
1075 if self.__user_is_readonly(request):
Scott Bakerf875eba2014-05-23 12:09:15 -07001076 if not hasattr(self, "readonly_save"):
1077 # save the original readonly fields
1078 self.readonly_save = self.readonly_fields
1079 self.inlines_save = self.inlines
Scott Bakerb27b62c2014-08-15 16:29:16 -07001080 if hasattr(self, "user_readonly_fields"):
1081 self.readonly_fields=self.user_readonly_fields
1082 if hasattr(self, "user_readonly_inlines"):
1083 self.inlines = self.user_readonly_inlines
Scott Bakerf875eba2014-05-23 12:09:15 -07001084 else:
1085 if hasattr(self, "readonly_save"):
1086 # restore the original readonly fields
1087 self.readonly_fields = self.readonly_save
1088 self.inlines = self.inlines_save
1089
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001090 try:
1091 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1092 except PermissionDenied:
1093 pass
1094 if request.method == 'POST':
1095 raise PermissionDenied
1096 request.readonly = True
1097 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1098
1099 def __user_is_readonly(self, request):
1100 #groups = [x.name for x in request.user.groups.all() ]
1101 #return "readonly" in groups
1102 return request.user.isReadOnlyUser()
1103
Tony Mack5b061472014-02-04 07:57:10 -05001104 def queryset(self, request):
1105 return User.select_by_user(request.user)
1106
Scott Baker40c00762014-08-21 16:55:59 -07001107 def backend_status_text(self, obj):
1108 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -07001109
Scott Baker40c00762014-08-21 16:55:59 -07001110 def backend_status_icon(self, obj):
1111 return mark_safe(backend_icon(obj))
1112 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -07001113
Scott Baker2c3cb642014-05-19 17:55:56 -07001114class DashboardViewAdmin(PlanetStackBaseAdmin):
1115 fieldsets = [('Dashboard View Details',
Scott Baker40c00762014-08-21 16:55:59 -07001116 {'fields': ['backend_status_text', 'name', 'url'],
Scott Baker2c3cb642014-05-19 17:55:56 -07001117 'classes': ['suit-tab suit-tab-general']})
1118 ]
Scott Baker40c00762014-08-21 16:55:59 -07001119 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001120
Scott Baker2c3cb642014-05-19 17:55:56 -07001121 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001122
Scott Baker0165fac2014-01-13 11:49:26 -08001123class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001124 model = ServiceResource
1125 extra = 0
1126
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001127class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001128 list_display = ('backend_status_icon', 'name', 'commitment', 'membershipFee')
1129 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001130 inlines = [ServiceResourceInline]
1131
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001132 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1133 user_readonly_inlines = []
1134
Scott Baker0165fac2014-01-13 11:49:26 -08001135class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001136 model = ReservedResource
1137 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001138 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001139
1140 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1141 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1142
1143 if db_field.name == 'resource':
1144 # restrict resources to those that the slice's service class allows
1145 if request._slice is not None:
1146 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1147 if len(field.queryset) > 0:
1148 field.initial = field.queryset.all()[0]
1149 else:
1150 field.queryset = field.queryset.none()
1151 elif db_field.name == 'sliver':
1152 # restrict slivers to those that belong to the slice
1153 if request._slice is not None:
1154 field.queryset = field.queryset.filter(slice = request._slice)
1155 else:
1156 field.queryset = field.queryset.none()
1157
1158 return field
1159
Tony Mack5b061472014-02-04 07:57:10 -05001160 def queryset(self, request):
1161 return ReservedResource.select_by_user(request.user)
1162
Scott Baker133c9212013-05-17 09:09:11 -07001163class ReservationChangeForm(forms.ModelForm):
1164 class Meta:
1165 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001166 widgets = {
1167 'slice' : LinkedSelect
1168 }
Scott Baker133c9212013-05-17 09:09:11 -07001169
1170class ReservationAddForm(forms.ModelForm):
1171 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1172 refresh = forms.CharField(widget=forms.HiddenInput())
1173
1174 class Media:
1175 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1176
1177 def clean_slice(self):
1178 slice = self.cleaned_data.get("slice")
1179 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1180 if len(x) == 0:
1181 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1182 return slice
1183
1184 class Meta:
1185 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001186 widgets = {
1187 'slice' : LinkedSelect
1188 }
1189
Scott Baker133c9212013-05-17 09:09:11 -07001190
1191class ReservationAddRefreshForm(ReservationAddForm):
1192 """ This form is displayed when the Reservation Form receives an update
1193 from the Slice dropdown onChange handler. It doesn't validate the
1194 data and doesn't save the data. This will cause the form to be
1195 redrawn.
1196 """
1197
Scott Baker8737e5f2013-05-17 09:35:32 -07001198 """ don't validate anything other than slice """
1199 dont_validate_fields = ("startTime", "duration")
1200
Scott Baker133c9212013-05-17 09:09:11 -07001201 def full_clean(self):
1202 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001203
1204 for fieldname in self.dont_validate_fields:
1205 if fieldname in self._errors:
1206 del self._errors[fieldname]
1207
Scott Baker133c9212013-05-17 09:09:11 -07001208 return result
1209
1210 """ don't save anything """
1211 def is_valid(self):
1212 return False
1213
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001214class ReservationAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001215 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001216 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001217 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001218 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001219 form = ReservationAddForm
1220
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001221 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1222
1223 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001224 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001225
Scott Baker133c9212013-05-17 09:09:11 -07001226 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001227 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001228 request._refresh = False
1229 request._slice = None
1230 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001231 # "refresh" will be set to "1" if the form was submitted due to
1232 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001233 if request.POST.get("refresh","1") == "1":
1234 request._refresh = True
1235 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001236
1237 # Keep track of the slice that was selected, so the
1238 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001239 request._slice = request.POST.get("slice",None)
1240 if (request._slice is not None):
1241 request._slice = Slice.objects.get(id=request._slice)
1242
1243 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1244 return result
1245
Scott Bakeracd45142013-05-19 16:19:16 -07001246 def changelist_view(self, request, extra_context = None):
1247 timezone.activate(request.user.timezone)
1248 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1249
Scott Baker133c9212013-05-17 09:09:11 -07001250 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001251 request._obj_ = obj
1252 if obj is not None:
1253 # For changes, set request._slice to the slice already set in the
1254 # object.
1255 request._slice = obj.slice
1256 self.form = ReservationChangeForm
1257 else:
1258 if getattr(request, "_refresh", False):
1259 self.form = ReservationAddRefreshForm
1260 else:
1261 self.form = ReservationAddForm
1262 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1263
Scott Baker133c9212013-05-17 09:09:11 -07001264 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001265 if (obj is not None):
1266 # Prevent slice from being changed after the reservation has been
1267 # created.
1268 return ['slice']
1269 else:
Scott Baker133c9212013-05-17 09:09:11 -07001270 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001271
Tony Mack5b061472014-02-04 07:57:10 -05001272 def queryset(self, request):
1273 return Reservation.select_by_user(request.user)
1274
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001275class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001276 list_display = ("backend_status_icon", "name", )
1277 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001278 user_readonly_fields = ['name']
1279 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001280
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001281class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001282 list_display = ("backend_status_icon", "name", )
1283 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001284 user_readonly_fields = ['name']
1285 user_readonly_inlines = []
1286
Scott Baker0165fac2014-01-13 11:49:26 -08001287class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001288 model = Router.networks.through
1289 extra = 0
1290 verbose_name_plural = "Routers"
1291 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001292 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001293
Scott Bakerb27b62c2014-08-15 16:29:16 -07001294class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001295 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07001296 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001297 verbose_name_plural = "Parameters"
1298 verbose_name = "Parameter"
1299 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07001300 fields = ['backend_status_icon', 'parameter', 'value']
1301 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001302
Scott Baker0165fac2014-01-13 11:49:26 -08001303class NetworkSliversInline(PlStackTabularInline):
Scott Baker40c00762014-08-21 16:55:59 -07001304 fields = ['backend_status_icon', 'network','sliver','ip']
1305 readonly_fields = ("backend_status_icon", "ip", )
Scott Baker74d8e622013-07-29 16:04:22 -07001306 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001307 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001308 extra = 0
1309 verbose_name_plural = "Slivers"
1310 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001311 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001312
Scott Baker0165fac2014-01-13 11:49:26 -08001313class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001314 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001315 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001316 extra = 0
1317 verbose_name_plural = "Slices"
1318 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001319 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Baker40c00762014-08-21 16:55:59 -07001320 fields = ['backend_status_icon', 'network','slice']
1321 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07001322
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001323class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001324 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
1325 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07001326 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001327
Scott Bakerd7d2a392013-08-06 08:57:30 -07001328 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001329
Siobhan Tully2d95e482013-09-06 10:56:06 -04001330 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001331 (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 -05001332
Scott Baker40c00762014-08-21 16:55:59 -07001333 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001334 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 -04001335
1336 suit_form_tabs =(
1337 ('general','Network Details'),
1338 ('netparams', 'Parameters'),
1339 ('networkslivers','Slivers'),
1340 ('networkslices','Slices'),
1341 ('routers','Routers'),
1342 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001343class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001344 list_display = ("backend_status_icon", "name", "guaranteedBandwidth", "visibility")
1345 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001346 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1347 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001348
Scott Baker37b47902014-09-02 14:37:41 -07001349class FlavorAdmin(PlanetStackBaseAdmin):
1350 list_display = ("backend_status_icon", "name", "flavor", "order", "default")
1351 list_display_links = ("backend_status_icon", "name")
1352 user_readonly_fields = ("name", "flavor")
1353 fields = ("name", "description", "flavor", "order", "default")
1354
Tony Mack31c2b8f2013-04-26 20:01:42 -04001355# register a signal that caches the user's credentials when they log in
1356def cache_credentials(sender, user, request, **kwds):
1357 auth = {'username': request.POST['username'],
1358 'password': request.POST['password']}
1359 request.session['auth'] = auth
1360user_logged_in.connect(cache_credentials)
1361
Scott Baker15cddfa2013-12-09 13:45:19 -08001362def dollar_field(fieldName, short_description):
1363 def newFunc(self, obj):
1364 try:
1365 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1366 except:
1367 x=getattr(obj, fieldName, 0.0)
1368 return x
1369 newFunc.short_description = short_description
1370 return newFunc
1371
1372def right_dollar_field(fieldName, short_description):
1373 def newFunc(self, obj):
1374 try:
1375 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1376 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1377 except:
1378 x=getattr(obj, fieldName, 0.0)
1379 return x
1380 newFunc.short_description = short_description
1381 newFunc.allow_tags = True
1382 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001383
Scott Baker0165fac2014-01-13 11:49:26 -08001384class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001385 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001386 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001387 verbose_name_plural = "Charges"
1388 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001389 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001390 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1391 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1392 can_delete = False
1393 max_num = 0
1394
1395 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001396
1397class InvoiceAdmin(admin.ModelAdmin):
1398 list_display = ("date", "account")
1399
1400 inlines = [InvoiceChargeInline]
1401
Scott Baker9cb88a22013-12-09 18:56:00 -08001402 fields = ["date", "account", "dollar_amount"]
1403 readonly_fields = ["date", "account", "dollar_amount"]
1404
1405 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001406
Scott Baker0165fac2014-01-13 11:49:26 -08001407class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001408 model = Invoice
1409 extra = 0
1410 verbose_name_plural = "Invoices"
1411 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001412 fields = ["date", "dollar_amount"]
1413 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001414 suit_classes = 'suit-tab suit-tab-accountinvoice'
1415 can_delete=False
1416 max_num=0
1417
1418 dollar_amount = right_dollar_field("amount", "Amount")
1419
Scott Baker0165fac2014-01-13 11:49:26 -08001420class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001421 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001422 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001423 verbose_name_plural = "Charges"
1424 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001425 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001426 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1427 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001428 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001429 can_delete=False
1430 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001431
1432 def queryset(self, request):
1433 qs = super(PendingChargeInline, self).queryset(request)
1434 qs = qs.filter(state="pending")
1435 return qs
1436
Scott Baker15cddfa2013-12-09 13:45:19 -08001437 dollar_amount = right_dollar_field("amount", "Amount")
1438
Scott Baker0165fac2014-01-13 11:49:26 -08001439class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001440 model=Payment
1441 extra = 1
1442 verbose_name_plural = "Payments"
1443 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001444 fields = ["date", "dollar_amount"]
1445 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001446 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001447 can_delete=False
1448 max_num=0
1449
1450 dollar_amount = right_dollar_field("amount", "Amount")
1451
Scott Baker43105042013-12-06 23:23:36 -08001452class AccountAdmin(admin.ModelAdmin):
1453 list_display = ("site", "balance_due")
1454
1455 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1456
1457 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001458 (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 -08001459
Scott Baker15cddfa2013-12-09 13:45:19 -08001460 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001461
1462 suit_form_tabs =(
1463 ('general','Account Details'),
1464 ('accountinvoice', 'Invoices'),
1465 ('accountpayments', 'Payments'),
1466 ('accountpendingcharges','Pending Charges'),
1467 )
1468
Scott Baker15cddfa2013-12-09 13:45:19 -08001469 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1470 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1471 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1472
Siobhan Tully53437282013-04-26 19:30:27 -04001473# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001474admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001475# ... and, since we're not using Django's builtin permissions,
1476# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001477#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001478
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001479#Do not show django evolution in the admin interface
1480from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001481#admin.site.unregister(Version)
1482#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001483
1484
1485# When debugging it is often easier to see all the classes, but for regular use
1486# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001487showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001488
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001489admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001490admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001491admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001492admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001493admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001494admin.site.register(Network, NetworkAdmin)
1495admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001496admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001497admin.site.register(Account, AccountAdmin)
1498admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001499
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001500if True:
1501 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1502 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001503 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001504 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001505 admin.site.register(DeploymentRole)
1506 admin.site.register(SiteRole)
1507 admin.site.register(SliceRole)
1508 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001509 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001510 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1511 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001512 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001513 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001514 admin.site.register(DashboardView, DashboardViewAdmin)
Scott Baker37b47902014-09-02 14:37:41 -07001515 admin.site.register(Flavor, FlavorAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001516