blob: 3ff973fe8000c9eaa81c571d03626f234fa746a8 [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 Baker32481312014-09-08 12:14:14 -0700281 elif db_field.name == 'flavor':
282 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_flavor_changed(this);"})
Scott Baker3b678742014-06-09 13:11:54 -0700283
284 field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700285
286 return field
287
Scott Baker434ca7e2014-08-15 12:29:20 -0700288"""
289 SMBAKER: This is the old code that implemented each network type as a
290 separate column in the sliver table.
Scott Baker74d8e622013-07-29 16:04:22 -0700291
Scott Baker434ca7e2014-08-15 12:29:20 -0700292 def _declared_fieldsets(self):
293 # Return None so django will call get_fieldsets and we can insert our
294 # dynamic fields
295 return None
296
297 def get_readonly_fields(self, request, obj=None):
298 readonly_fields = list(super(SliverInline, self).get_readonly_fields(request, obj))
299
300 # Lookup the networks that are bound to the slivers, and add those
301 # network names to the list of readonly fields.
302
303 for sliver in obj.slivers.all():
304 for nbs in sliver.networksliver_set.all():
305 if nbs.ip:
306 network_name = nbs.network.name
307 if network_name not in [str(x) for x in readonly_fields]:
308 readonly_fields.append(NetworkLookerUpper.get(network_name))
309
310 return readonly_fields
311
312 def get_fieldsets(self, request, obj=None):
313 form = self.get_formset(request, obj).form
314 # fields = the read/write files + the read-only fields
315 fields = list(self.fields)
316 for fieldName in self.get_readonly_fields(request,obj):
317 if not fieldName in fields:
318 fields.append(fieldName)
319
320 return [(None, {'fields': fields})]
321"""
Siobhan Tully567e3e62013-06-21 18:03:16 -0400322
Siobhan Tullyd3515752013-06-21 16:34:53 -0400323class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400324 model = Site
325 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400326 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400327
Tony Mack5b061472014-02-04 07:57:10 -0500328 def queryset(self, request):
329 return Site.select_by_user(request.user)
330
Siobhan Tullyd3515752013-06-21 16:34:53 -0400331class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400332 model = User
Scott Baker40c00762014-08-21 16:55:59 -0700333 fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
334 readonly_fields = ('backend_status_icon', )
Siobhan Tully30fd4292013-05-10 08:59:56 -0400335 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400336 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400337
Tony Mack5b061472014-02-04 07:57:10 -0500338 def queryset(self, request):
339 return User.select_by_user(request.user)
340
Siobhan Tullyd3515752013-06-21 16:34:53 -0400341class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400342 model = Slice
Scott Baker40c00762014-08-21 16:55:59 -0700343 fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
344 readonly_fields = ('backend_status_icon', )
Tony Mack00d361f2013-04-28 10:28:42 -0400345 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400346 suit_classes = 'suit-tab suit-tab-slices'
347
Tony Mack5b061472014-02-04 07:57:10 -0500348 def queryset(self, request):
349 return Slice.select_by_user(request.user)
350
Siobhan Tullyd3515752013-06-21 16:34:53 -0400351class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400352 model = Node
353 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400354 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker40c00762014-08-21 16:55:59 -0700355 fields = ['backend_status_icon', 'name','deployment','site']
356 readonly_fields = ('backend_status_icon', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400357
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400358class DeploymentPrivilegeInline(PlStackTabularInline):
359 model = DeploymentPrivilege
360 extra = 0
361 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700362 fields = ['backend_status_icon', 'user','role','deployment']
363 readonly_fields = ('backend_status_icon', )
Tony Mack5b061472014-02-04 07:57:10 -0500364
365 def queryset(self, request):
366 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400367
Siobhan Tullyd3515752013-06-21 16:34:53 -0400368class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400369 model = SitePrivilege
370 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400371 suit_classes = 'suit-tab suit-tab-siteprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700372 fields = ['backend_status_icon', 'user','site', 'role']
373 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400374
Tony Mackc2835a92013-05-28 09:18:49 -0400375 def formfield_for_foreignkey(self, db_field, request, **kwargs):
376 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500377 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400378
379 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500380 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400381 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
382
Tony Mack5b061472014-02-04 07:57:10 -0500383 def queryset(self, request):
384 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400385
Tony Macke4be32f2014-03-11 20:45:25 -0400386class SiteDeploymentInline(PlStackTabularInline):
387 model = SiteDeployments
Tony Macke4be32f2014-03-11 20:45:25 -0400388 extra = 0
389 suit_classes = 'suit-tab suit-tab-deployments'
Scott Baker40c00762014-08-21 16:55:59 -0700390 fields = ['backend_status_icon', 'deployment','site']
391 readonly_fields = ('backend_status_icon', )
Tony Macke4be32f2014-03-11 20:45:25 -0400392
393 def formfield_for_foreignkey(self, db_field, request, **kwargs):
394 if db_field.name == 'site':
395 kwargs['queryset'] = Site.select_by_user(request.user)
396
397 if db_field.name == 'deployment':
398 kwargs['queryset'] = Deployment.select_by_user(request.user)
399 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
400
401 def queryset(self, request):
402 return SiteDeployments.select_by_user(request.user)
403
404
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400405class SlicePrivilegeInline(PlStackTabularInline):
406 model = SlicePrivilege
407 suit_classes = 'suit-tab suit-tab-sliceprivileges'
408 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700409 fields = ('backend_status_icon', 'user', 'slice', 'role')
410 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400411
Tony Mackc2835a92013-05-28 09:18:49 -0400412 def formfield_for_foreignkey(self, db_field, request, **kwargs):
413 if db_field.name == 'slice':
Scott Baker36f50872014-08-21 13:01:25 -0700414 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400415 if db_field.name == 'user':
Scott Baker36f50872014-08-21 13:01:25 -0700416 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400417
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400418 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400419
Tony Mack5b061472014-02-04 07:57:10 -0500420 def queryset(self, request):
421 return SlicePrivilege.select_by_user(request.user)
422
Scott Bakera0015eb2013-08-14 17:28:14 -0700423class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700424 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800425 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700426 extra = 0
427 verbose_name = "Network Connection"
428 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400429 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker40c00762014-08-21 16:55:59 -0700430 fields = ['backend_status_icon', 'network']
431 readonly_fields = ('backend_status_icon', )
Scott Baker2170b972014-06-03 12:14:07 -0700432
433class ImageDeploymentsInline(PlStackTabularInline):
434 model = ImageDeployments
435 extra = 0
436 verbose_name = "Image Deployments"
437 verbose_name_plural = "Image Deployments"
438 suit_classes = 'suit-tab suit-tab-imagedeployments'
Scott Baker40c00762014-08-21 16:55:59 -0700439 fields = ['backend_status_icon', 'image', 'deployment', 'glance_image_id']
440 readonly_fields = ['backend_status_icon', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700441
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500442class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400443 save_on_top = False
Scott Baker36f50872014-08-21 13:01:25 -0700444
Tony Mack332ee1d2014-02-04 15:33:45 -0500445 def save_model(self, request, obj, form, change):
Tony Mack3d042792014-03-17 19:18:37 -0400446 obj.caller = request.user
Tony Mack332ee1d2014-02-04 15:33:45 -0500447 # update openstack connection to use this site/tenant
448 obj.save_by_user(request.user)
449
450 def delete_model(self, request, obj):
451 obj.delete_by_user(request.user)
452
453 def save_formset(self, request, form, formset, change):
454 instances = formset.save(commit=False)
455 for instance in instances:
456 instance.save_by_user(request.user)
457 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400458
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400459class SliceRoleAdmin(PlanetStackBaseAdmin):
460 model = SliceRole
461 pass
462
463class SiteRoleAdmin(PlanetStackBaseAdmin):
464 model = SiteRole
465 pass
466
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400467class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400468 sites = forms.ModelMultipleChoiceField(
469 queryset=Site.objects.all(),
470 required=False,
Scott Baker70983182014-06-09 22:10:00 -0700471 help_text="Select which sites are allowed to host nodes in this deployment",
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400472 widget=FilteredSelectMultiple(
473 verbose_name=('Sites'), is_stacked=False
474 )
475 )
Scott Bakerde0f4412014-06-11 15:40:26 -0700476 images = forms.ModelMultipleChoiceField(
477 queryset=Image.objects.all(),
478 required=False,
479 help_text="Select which images should be deployed on this deployment",
480 widget=FilteredSelectMultiple(
481 verbose_name=('Images'), is_stacked=False
482 )
483 )
Scott Baker37b47902014-09-02 14:37:41 -0700484 flavors = forms.ModelMultipleChoiceField(
485 queryset=Flavor.objects.all(),
486 required=False,
487 help_text="Select which flavors should be usable on this deployment",
488 widget=FilteredSelectMultiple(
489 verbose_name=('Flavors'), is_stacked=False
490 )
491 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400492 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400493 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700494 many_to_many = ["flavors",]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400495
Siobhan Tully320b4622014-01-17 15:11:14 -0500496 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700497 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500498 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
499
Scott Baker5380c522014-06-06 14:49:43 -0700500 self.fields['accessControl'].initial = "allow site " + request.user.site.name
501
Siobhan Tully320b4622014-01-17 15:11:14 -0500502 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700503 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Scott Bakerde0f4412014-06-11 15:40:26 -0700504 self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
Scott Baker37b47902014-09-02 14:37:41 -0700505 self.fields['flavors'].initial = self.instance.flavors.all()
Scott Bakerde0f4412014-06-11 15:40:26 -0700506
507 def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
508 """ helper function for handling m2m relations from the MultipleChoiceField
509
510 this_obj: the source object we want to link from
511
512 selected_objs: a list of destination objects we want to link to
513
514 all_relations: the full set of relations involving this_obj, including ones we don't want
515
516 relation_class: the class that implements the relation from source to dest
517
518 local_attrname: field name representing this_obj in relation_class
519
520 foreign_attrname: field name representing selected_objs in relation_class
521
522 This function will remove all newobjclass relations from this_obj
523 that are not contained in selected_objs, and add any relations that
524 are in selected_objs but don't exist in the data model yet.
525 """
526
527 existing_dest_objs = []
528 for relation in list(all_relations):
529 if getattr(relation, foreign_attrname) not in selected_objs:
530 #print "deleting site", sdp.site
531 relation.delete()
532 else:
533 existing_dest_objs.append(getattr(relation, foreign_attrname))
534
535 for dest_obj in selected_objs:
536 if dest_obj not in existing_dest_objs:
537 #print "adding site", site
538 kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
539 relation = relation_class(**kwargs)
540 relation.save()
Siobhan Tully320b4622014-01-17 15:11:14 -0500541
542 def save(self, commit=True):
543 deployment = super(DeploymentAdminForm, self).save(commit=False)
544
Scott Baker37b47902014-09-02 14:37:41 -0700545 deployment.flavors = self.cleaned_data['flavors']
546
Siobhan Tully320b4622014-01-17 15:11:14 -0500547 if commit:
548 deployment.save()
549
550 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700551 # save_m2m() doesn't seem to work with 'through' relations. So we
552 # create/destroy the through models ourselves. There has to be
553 # a better way...
554
Scott Bakerde0f4412014-06-11 15:40:26 -0700555 self.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
556 self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
Scott Bakerc9b14f72014-05-22 13:44:20 -0700557
Scott Baker37b47902014-09-02 14:37:41 -0700558 self.save_m2m()
Siobhan Tully320b4622014-01-17 15:11:14 -0500559
560 return deployment
561
Scott Bakerff5e0f32014-05-22 14:40:27 -0700562class DeploymentAdminROForm(DeploymentAdminForm):
563 def save(self, commit=True):
564 raise PermissionDenied
565
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500566class SiteAssocInline(PlStackTabularInline):
567 model = Site.deployments.through
568 extra = 0
569 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400570
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400571class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500572 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700573 fieldList = ['backend_status_text', 'name', 'sites', 'images', 'flavors', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500574 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Scott Bakerde0f4412014-06-11 15:40:26 -0700575 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
Scott Baker63d1a552014-08-21 15:19:07 -0700576 list_display = ['backend_status_icon', 'name']
577 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700578 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500579
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500580 user_readonly_fields = ['name']
581
Scott Bakerde0f4412014-06-11 15:40:26 -0700582 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags')) # ,('imagedeployments','Images'))
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500583
Scott Bakerff5e0f32014-05-22 14:40:27 -0700584 def get_form(self, request, obj=None, **kwargs):
585 if request.user.isReadOnlyUser():
586 kwargs["form"] = DeploymentAdminROForm
587 else:
588 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700589 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
590
591 # from stackexchange: pass the request object into the form
592
593 class AdminFormMetaClass(adminForm):
594 def __new__(cls, *args, **kwargs):
595 kwargs['request'] = request
596 return adminForm(*args, **kwargs)
597
598 return AdminFormMetaClass
599
Siobhan Tullyce652d02013-10-08 21:52:35 -0400600class ServiceAttrAsTabInline(PlStackTabularInline):
601 model = ServiceAttribute
602 fields = ['name','value']
603 extra = 0
604 suit_classes = 'suit-tab suit-tab-serviceattrs'
605
Siobhan Tullyce652d02013-10-08 21:52:35 -0400606class ServiceAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700607 list_display = ("backend_status_icon","name","description","versionNumber","enabled","published")
608 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700609 fieldList = ["backend_status_text","name","description","versionNumber","enabled","published"]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500610 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
611 inlines = [ServiceAttrAsTabInline,SliceInline]
Scott Baker40c00762014-08-21 16:55:59 -0700612 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500613
614 user_readonly_fields = fieldList
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500615
616 suit_form_tabs =(('general', 'Service Details'),
617 ('slices','Slices'),
618 ('serviceattrs','Additional Attributes'),
619 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400620
Tony Mack0553f282013-06-10 22:54:50 -0400621class SiteAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700622 fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400623 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500624 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400625 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400626 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400627 suit_form_tabs =(('general', 'Site Details'),
628 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400629 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400630 ('deployments','Deployments'),
631 ('slices','Slices'),
Scott Baker36f50872014-08-21 13:01:25 -0700632 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400633 ('tags','Tags'),
634 )
Scott Baker40c00762014-08-21 16:55:59 -0700635 readonly_fields = ['backend_status_text', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500636
637 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500638
Scott Baker63d1a552014-08-21 15:19:07 -0700639 list_display = ('backend_status_icon', 'name', 'login_base','site_url', 'enabled')
640 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400641 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400642 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400643 search_fields = ['name']
644
Tony Mack04062832013-05-10 08:22:44 -0400645 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500646 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400647
Tony Mack5cd13202013-05-01 21:48:38 -0400648 def get_formsets(self, request, obj=None):
649 for inline in self.get_inline_instances(request, obj):
650 # hide MyInline in the add view
651 if obj is None:
652 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400653 if isinstance(inline, SliceInline):
654 inline.model.caller = request.user
655 yield inline.get_formset(request, obj)
656
657 def get_formsets(self, request, obj=None):
658 for inline in self.get_inline_instances(request, obj):
659 # hide MyInline in the add view
660 if obj is None:
661 continue
662 if isinstance(inline, SliverInline):
663 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400664 yield inline.get_formset(request, obj)
665
Scott Baker545db2a2013-12-09 18:44:43 -0800666 def accountLink(self, obj):
667 link_obj = obj.accounts.all()
668 if link_obj:
669 reverse_path = "admin:core_account_change"
670 url = reverse(reverse_path, args =(link_obj[0].id,))
671 return "<a href='%s'>%s</a>" % (url, "view billing details")
672 else:
673 return "no billing data for this site"
674 accountLink.allow_tags = True
675 accountLink.short_description = "Billing"
676
Tony Mack332ee1d2014-02-04 15:33:45 -0500677 def save_model(self, request, obj, form, change):
678 # update openstack connection to use this site/tenant
679 obj.save_by_user(request.user)
680
681 def delete_model(self, request, obj):
682 obj.delete_by_user(request.user)
683
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500684
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400685class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700686 fieldList = ['backend_status_text', 'user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400687 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500688 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400689 ]
Scott Baker40c00762014-08-21 16:55:59 -0700690 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700691 list_display = ('backend_status_icon', 'user', 'site', 'role')
692 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500693 user_readonly_fields = fieldList
694 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400695
Tony Mackc2835a92013-05-28 09:18:49 -0400696 def formfield_for_foreignkey(self, db_field, request, **kwargs):
697 if db_field.name == 'site':
698 if not request.user.is_admin:
699 # only show sites where user is an admin or pi
700 sites = set()
701 for site_privilege in SitePrivilege.objects.filer(user=request.user):
702 if site_privilege.role.role_type in ['admin', 'pi']:
703 sites.add(site_privilege.site)
704 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
705
706 if db_field.name == 'user':
707 if not request.user.is_admin:
708 # only show users from sites where caller has admin or pi role
709 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
710 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
711 sites = [site_privilege.site for site_privilege in site_privileges]
712 site_privileges = SitePrivilege.objects.filter(site__in=sites)
713 emails = [site_privilege.user.email for site_privilege in site_privileges]
714 users = User.objects.filter(email__in=emails)
715 kwargs['queryset'] = users
716
717 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
718
Tony Mack04062832013-05-10 08:22:44 -0400719 def queryset(self, request):
720 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400721 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400722 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500723 #if not request.user.is_admin:
724 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
725 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
726 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
727 # sites = Site.objects.filter(login_base__in=login_bases)
728 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400729 return qs
730
Siobhan Tullyce652d02013-10-08 21:52:35 -0400731class SliceForm(forms.ModelForm):
732 class Meta:
733 model = Slice
734 widgets = {
Scott Baker36f50872014-08-21 13:01:25 -0700735 'service': LinkedSelect
Siobhan Tullyce652d02013-10-08 21:52:35 -0400736 }
737
Tony Mack2bd5b412013-06-11 21:05:06 -0400738class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400739 form = SliceForm
Tony Mackfbb26fc2014-09-02 07:03:27 -0400740 fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500741 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Scott Baker40c00762014-08-21 16:55:59 -0700742 readonly_fields = ('backend_status_text', )
Tony Mack7d459902014-09-03 13:18:57 -0400743 list_display = ('backend_status_icon', 'name', 'site','serviceClass', 'slice_url', 'max_slivers')
744 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully2d95e482013-09-06 10:56:06 -0400745 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400746
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500747 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400748
749 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400750 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400751 ('sliceprivileges','Privileges'),
752 ('slivers','Slivers'),
753 ('tags','Tags'),
754 ('reservations','Reservations'),
755 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400756
Scott Baker510fdbb2014-08-05 17:19:24 -0700757 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
Scott Baker510fdbb2014-08-05 17:19:24 -0700758 deployment_nodes = []
759 for node in Node.objects.all():
760 deployment_nodes.append( (node.deployment.id, node.id, node.name) )
761
Scott Baker7a61dc42014-09-02 17:08:20 -0700762 deployment_flavors = []
763 for flavor in Flavor.objects.all():
764 for deployment in flavor.deployments.all():
765 deployment_flavors.append( (deployment.id, flavor.id, flavor.name) )
766
Tony Mackec23b992014-09-02 21:18:45 -0400767 site_login_bases = []
768 for site in Site.objects.all():
769 site_login_bases.append((site.id, site.login_base))
770
Scott Baker510fdbb2014-08-05 17:19:24 -0700771 context["deployment_nodes"] = deployment_nodes
Scott Baker7a61dc42014-09-02 17:08:20 -0700772 context["deployment_flavors"] = deployment_flavors
Tony Mackec23b992014-09-02 21:18:45 -0400773 context["site_login_bases"] = site_login_bases
Scott Baker510fdbb2014-08-05 17:19:24 -0700774 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
775
Tony Mackc2835a92013-05-28 09:18:49 -0400776 def formfield_for_foreignkey(self, db_field, request, **kwargs):
777 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500778 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackec23b992014-09-02 21:18:45 -0400779 kwargs['widget'] = forms.Select(attrs={'onChange': "update_slice_prefix(this, $($(this).closest('fieldset')[0]).find('.field-name input')[0].id)"})
Scott Baker40c00762014-08-21 16:55:59 -0700780
Tony Mackc2835a92013-05-28 09:18:49 -0400781 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
782
Tony Mack04062832013-05-10 08:22:44 -0400783 def queryset(self, request):
784 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500785 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400786
Tony Mack79748612013-05-01 14:52:03 -0400787 def get_formsets(self, request, obj=None):
788 for inline in self.get_inline_instances(request, obj):
789 # hide MyInline in the add view
790 if obj is None:
791 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400792 if isinstance(inline, SliverInline):
793 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400794 yield inline.get_formset(request, obj)
795
Tony Mack2bd5b412013-06-11 21:05:06 -0400796
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400797class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400798 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700799 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -0400800 ]
Scott Baker40c00762014-08-21 16:55:59 -0700801 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700802 list_display = ('backend_status_icon', 'user', 'slice', 'role')
803 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -0400804
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500805 user_readonly_fields = ['user', 'slice', 'role']
806 user_readonly_inlines = []
807
Tony Mackc2835a92013-05-28 09:18:49 -0400808 def formfield_for_foreignkey(self, db_field, request, **kwargs):
809 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500810 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400811
812 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500813 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400814
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400815 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400816
Tony Mack04062832013-05-10 08:22:44 -0400817 def queryset(self, request):
818 # admins can see all memberships. Users can only see memberships of
819 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500820 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400821
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400822 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400823 # update openstack connection to use this site/tenant
824 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400825 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400826 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400827 obj.save()
828
829 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400830 # update openstack connection to use this site/tenant
831 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400832 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400833 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400834 obj.delete()
835
Siobhan Tully567e3e62013-06-21 18:03:16 -0400836
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400837class ImageAdmin(PlanetStackBaseAdmin):
838
Scott Baker36f50872014-08-21 13:01:25 -0700839 fieldsets = [('Image Details',
Scott Baker40c00762014-08-21 16:55:59 -0700840 {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400841 'classes': ['suit-tab suit-tab-general']})
842 ]
Scott Baker40c00762014-08-21 16:55:59 -0700843 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400844
Scott Baker2170b972014-06-03 12:14:07 -0700845 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400846
Scott Baker2170b972014-06-03 12:14:07 -0700847 inlines = [SliverInline, ImageDeploymentsInline]
Scott Bakerb6f99242014-06-11 11:34:44 -0700848
Tony Mack32e1ce32014-05-07 13:29:41 -0400849 user_readonly_fields = ['name', 'disk_format', 'container_format']
Scott Bakerb27b62c2014-08-15 16:29:16 -0700850
Scott Baker63d1a552014-08-21 15:19:07 -0700851 list_display = ['backend_status_icon', 'name']
852 list_display_links = ('backend_status_icon', 'name', )
853
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400854class NodeForm(forms.ModelForm):
855 class Meta:
856 widgets = {
857 'site': LinkedSelect,
858 'deployment': LinkedSelect
859 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400860
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500861class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400862 form = NodeForm
Scott Baker63d1a552014-08-21 15:19:07 -0700863 list_display = ('backend_status_icon', 'name', 'site', 'deployment')
864 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400865 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500866
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400867 inlines = [TagInline,SliverInline]
Scott Baker40c00762014-08-21 16:55:59 -0700868 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
869 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400870
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500871 user_readonly_fields = ['name','site','deployment']
872 user_readonly_inlines = [TagInline,SliverInline]
873
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400874 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400875
Siobhan Tully567e3e62013-06-21 18:03:16 -0400876
Tony Mackd90cdbf2013-04-16 22:48:40 -0400877class SliverForm(forms.ModelForm):
878 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400879 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400880 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400881 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400882 widgets = {
883 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400884 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400885 'slice': LinkedSelect,
886 'deploymentNetwork': LinkedSelect,
887 'node': LinkedSelect,
888 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400889 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400890
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500891class TagAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700892 list_display = ['backend_status_icon', 'service', 'name', 'value', 'content_type', 'content_object',]
893 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500894 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
895 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400896
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400897class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400898 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400899 fieldsets = [
Scott Baker7a61dc42014-09-02 17:08:20 -0700900 ('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 -0400901 ]
Scott Baker40c00762014-08-21 16:55:59 -0700902 readonly_fields = ('backend_status_text', )
Scott Baker7a61dc42014-09-02 17:08:20 -0700903 list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deploymentNetwork']
Scott Baker63d1a552014-08-21 15:19:07 -0700904 list_display_links = ('backend_status_icon', 'ip',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400905
906 suit_form_tabs =(('general', 'Sliver Details'),
907 ('tags','Tags'),
908 )
909
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400910 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400911
Scott Baker7a61dc42014-09-02 17:08:20 -0700912 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500913
Tony Mackc2835a92013-05-28 09:18:49 -0400914 def formfield_for_foreignkey(self, db_field, request, **kwargs):
915 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500916 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400917
918 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
919
Tony Mack04062832013-05-10 08:22:44 -0400920 def queryset(self, request):
Scott Baker36f50872014-08-21 13:01:25 -0700921 # admins can see all slivers. Users can only see slivers of
Tony Mack04062832013-05-10 08:22:44 -0400922 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500923 return Sliver.select_by_user(request.user)
924
Tony Mack04062832013-05-10 08:22:44 -0400925
Tony Mack1d6b85f2013-05-07 18:49:14 -0400926 def get_formsets(self, request, obj=None):
927 # make some fields read only if we are updating an existing record
928 if obj == None:
Scott Baker36f50872014-08-21 13:01:25 -0700929 #self.readonly_fields = ('ip', 'instance_name')
Scott Baker40c00762014-08-21 16:55:59 -0700930 self.readonly_fields = ('backend_status_text')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400931 else:
Scott Baker40c00762014-08-21 16:55:59 -0700932 self.readonly_fields = ('backend_status_text')
Scott Baker36f50872014-08-21 13:01:25 -0700933 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400934
935 for inline in self.get_inline_instances(request, obj):
936 # hide MyInline in the add view
937 if obj is None:
938 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700939 if isinstance(inline, SliverInline):
940 inline.model.caller = request.user
941 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400942
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500943 #def save_model(self, request, obj, form, change):
944 # # update openstack connection to use this site/tenant
945 # auth = request.session.get('auth', {})
946 # auth['tenant'] = obj.slice.name
947 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
948 # obj.creator = request.user
949 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400950
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500951 #def delete_model(self, request, obj):
952 # # update openstack connection to use this site/tenant
953 # auth = request.session.get('auth', {})
954 # auth['tenant'] = obj.slice.name
955 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
956 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400957
Siobhan Tully53437282013-04-26 19:30:27 -0400958class UserCreationForm(forms.ModelForm):
959 """A form for creating new users. Includes all the required
960 fields, plus a repeated password."""
961 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
962 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
963
964 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400965 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400966 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400967
968 def clean_password2(self):
969 # Check that the two password entries match
970 password1 = self.cleaned_data.get("password1")
971 password2 = self.cleaned_data.get("password2")
972 if password1 and password2 and password1 != password2:
973 raise forms.ValidationError("Passwords don't match")
974 return password2
975
976 def save(self, commit=True):
977 # Save the provided password in hashed format
978 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400979 user.password = self.cleaned_data["password1"]
980 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400981 if commit:
982 user.save()
983 return user
984
Siobhan Tully567e3e62013-06-21 18:03:16 -0400985
Siobhan Tully53437282013-04-26 19:30:27 -0400986class UserChangeForm(forms.ModelForm):
987 """A form for updating users. Includes all the fields on
988 the user, but replaces the password field with admin's
989 password hash display field.
990 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500991 password = ReadOnlyPasswordHashField(label='Password',
992 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400993
994 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400995 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400996
997 def clean_password(self):
998 # Regardless of what the user provides, return the initial value.
999 # This is done here, rather than on the field, because the
1000 # field does not have access to the initial value
1001 return self.initial["password"]
1002
Scott Baker2c3cb642014-05-19 17:55:56 -07001003class UserDashboardViewInline(PlStackTabularInline):
1004 model = UserDashboardView
1005 extra = 0
1006 suit_classes = 'suit-tab suit-tab-dashboards'
1007 fields = ['user', 'dashboardView', 'order']
1008
Tony Mack2bd5b412013-06-11 21:05:06 -04001009class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -04001010 class Meta:
1011 app_label = "core"
1012
1013 # The forms to add and change user instances
1014 form = UserChangeForm
1015 add_form = UserCreationForm
1016
1017 # The fields to be used in displaying the User model.
1018 # These override the definitions on the base UserAdmin
1019 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001020 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001021 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -07001022 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001023
Scott Bakeradae55f2014-08-14 17:32:35 -07001024 fieldListLoginDetails = ['email','site','password','is_active','is_readonly','is_admin','public_key']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001025 fieldListContactInfo = ['firstname','lastname','phone','timezone']
1026
Siobhan Tully53437282013-04-26 19:30:27 -04001027 fieldsets = (
Scott Baker40c00762014-08-21 16:55:59 -07001028 ('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 -04001029 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -07001030 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001031 #('Important dates', {'fields': ('last_login',)}),
1032 )
1033 add_fieldsets = (
1034 (None, {
1035 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001036 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -04001037 ),
1038 )
Scott Baker40c00762014-08-21 16:55:59 -07001039 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001040 search_fields = ('email',)
1041 ordering = ('email',)
1042 filter_horizontal = ()
1043
Scott Baker3ca51f62014-05-23 12:05:11 -07001044 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001045
Scott Baker2c3cb642014-05-19 17:55:56 -07001046 suit_form_tabs =(('general','Login Details'),
1047 ('contact','Contact Information'),
1048 ('sliceprivileges','Slice Privileges'),
1049 ('siteprivileges','Site Privileges'),
1050 ('deploymentprivileges','Deployment Privileges'),
1051 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001052
Tony Mackc2835a92013-05-28 09:18:49 -04001053 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1054 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001055 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001056
1057 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1058
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001059 def has_add_permission(self, request, obj=None):
1060 return (not self.__user_is_readonly(request))
1061
1062 def has_delete_permission(self, request, obj=None):
1063 return (not self.__user_is_readonly(request))
1064
1065 def get_actions(self,request):
1066 actions = super(UserAdmin,self).get_actions(request)
1067
1068 if self.__user_is_readonly(request):
1069 if 'delete_selected' in actions:
1070 del actions['delete_selected']
1071
1072 return actions
1073
1074 def change_view(self,request,object_id, extra_context=None):
1075
1076 if self.__user_is_readonly(request):
Scott Bakerf875eba2014-05-23 12:09:15 -07001077 if not hasattr(self, "readonly_save"):
1078 # save the original readonly fields
1079 self.readonly_save = self.readonly_fields
1080 self.inlines_save = self.inlines
Scott Bakerb27b62c2014-08-15 16:29:16 -07001081 if hasattr(self, "user_readonly_fields"):
1082 self.readonly_fields=self.user_readonly_fields
1083 if hasattr(self, "user_readonly_inlines"):
1084 self.inlines = self.user_readonly_inlines
Scott Bakerf875eba2014-05-23 12:09:15 -07001085 else:
1086 if hasattr(self, "readonly_save"):
1087 # restore the original readonly fields
1088 self.readonly_fields = self.readonly_save
1089 self.inlines = self.inlines_save
1090
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001091 try:
1092 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1093 except PermissionDenied:
1094 pass
1095 if request.method == 'POST':
1096 raise PermissionDenied
1097 request.readonly = True
1098 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1099
1100 def __user_is_readonly(self, request):
1101 #groups = [x.name for x in request.user.groups.all() ]
1102 #return "readonly" in groups
1103 return request.user.isReadOnlyUser()
1104
Tony Mack5b061472014-02-04 07:57:10 -05001105 def queryset(self, request):
1106 return User.select_by_user(request.user)
1107
Scott Baker40c00762014-08-21 16:55:59 -07001108 def backend_status_text(self, obj):
1109 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -07001110
Scott Baker40c00762014-08-21 16:55:59 -07001111 def backend_status_icon(self, obj):
1112 return mark_safe(backend_icon(obj))
1113 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -07001114
Scott Baker2c3cb642014-05-19 17:55:56 -07001115class DashboardViewAdmin(PlanetStackBaseAdmin):
1116 fieldsets = [('Dashboard View Details',
Scott Baker40c00762014-08-21 16:55:59 -07001117 {'fields': ['backend_status_text', 'name', 'url'],
Scott Baker2c3cb642014-05-19 17:55:56 -07001118 'classes': ['suit-tab suit-tab-general']})
1119 ]
Scott Baker40c00762014-08-21 16:55:59 -07001120 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001121
Scott Baker2c3cb642014-05-19 17:55:56 -07001122 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001123
Scott Baker0165fac2014-01-13 11:49:26 -08001124class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001125 model = ServiceResource
1126 extra = 0
1127
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001128class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001129 list_display = ('backend_status_icon', 'name', 'commitment', 'membershipFee')
1130 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001131 inlines = [ServiceResourceInline]
1132
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001133 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1134 user_readonly_inlines = []
1135
Scott Baker0165fac2014-01-13 11:49:26 -08001136class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001137 model = ReservedResource
1138 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001139 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001140
1141 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1142 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1143
1144 if db_field.name == 'resource':
1145 # restrict resources to those that the slice's service class allows
1146 if request._slice is not None:
1147 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1148 if len(field.queryset) > 0:
1149 field.initial = field.queryset.all()[0]
1150 else:
1151 field.queryset = field.queryset.none()
1152 elif db_field.name == 'sliver':
1153 # restrict slivers to those that belong to the slice
1154 if request._slice is not None:
1155 field.queryset = field.queryset.filter(slice = request._slice)
1156 else:
1157 field.queryset = field.queryset.none()
1158
1159 return field
1160
Tony Mack5b061472014-02-04 07:57:10 -05001161 def queryset(self, request):
1162 return ReservedResource.select_by_user(request.user)
1163
Scott Baker133c9212013-05-17 09:09:11 -07001164class ReservationChangeForm(forms.ModelForm):
1165 class Meta:
1166 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001167 widgets = {
1168 'slice' : LinkedSelect
1169 }
Scott Baker133c9212013-05-17 09:09:11 -07001170
1171class ReservationAddForm(forms.ModelForm):
1172 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1173 refresh = forms.CharField(widget=forms.HiddenInput())
1174
1175 class Media:
1176 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1177
1178 def clean_slice(self):
1179 slice = self.cleaned_data.get("slice")
1180 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1181 if len(x) == 0:
1182 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1183 return slice
1184
1185 class Meta:
1186 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001187 widgets = {
1188 'slice' : LinkedSelect
1189 }
1190
Scott Baker133c9212013-05-17 09:09:11 -07001191
1192class ReservationAddRefreshForm(ReservationAddForm):
1193 """ This form is displayed when the Reservation Form receives an update
1194 from the Slice dropdown onChange handler. It doesn't validate the
1195 data and doesn't save the data. This will cause the form to be
1196 redrawn.
1197 """
1198
Scott Baker8737e5f2013-05-17 09:35:32 -07001199 """ don't validate anything other than slice """
1200 dont_validate_fields = ("startTime", "duration")
1201
Scott Baker133c9212013-05-17 09:09:11 -07001202 def full_clean(self):
1203 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001204
1205 for fieldname in self.dont_validate_fields:
1206 if fieldname in self._errors:
1207 del self._errors[fieldname]
1208
Scott Baker133c9212013-05-17 09:09:11 -07001209 return result
1210
1211 """ don't save anything """
1212 def is_valid(self):
1213 return False
1214
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001215class ReservationAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001216 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001217 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001218 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001219 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001220 form = ReservationAddForm
1221
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001222 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1223
1224 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001225 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001226
Scott Baker133c9212013-05-17 09:09:11 -07001227 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001228 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001229 request._refresh = False
1230 request._slice = None
1231 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001232 # "refresh" will be set to "1" if the form was submitted due to
1233 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001234 if request.POST.get("refresh","1") == "1":
1235 request._refresh = True
1236 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001237
1238 # Keep track of the slice that was selected, so the
1239 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001240 request._slice = request.POST.get("slice",None)
1241 if (request._slice is not None):
1242 request._slice = Slice.objects.get(id=request._slice)
1243
1244 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1245 return result
1246
Scott Bakeracd45142013-05-19 16:19:16 -07001247 def changelist_view(self, request, extra_context = None):
1248 timezone.activate(request.user.timezone)
1249 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1250
Scott Baker133c9212013-05-17 09:09:11 -07001251 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001252 request._obj_ = obj
1253 if obj is not None:
1254 # For changes, set request._slice to the slice already set in the
1255 # object.
1256 request._slice = obj.slice
1257 self.form = ReservationChangeForm
1258 else:
1259 if getattr(request, "_refresh", False):
1260 self.form = ReservationAddRefreshForm
1261 else:
1262 self.form = ReservationAddForm
1263 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1264
Scott Baker133c9212013-05-17 09:09:11 -07001265 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001266 if (obj is not None):
1267 # Prevent slice from being changed after the reservation has been
1268 # created.
1269 return ['slice']
1270 else:
Scott Baker133c9212013-05-17 09:09:11 -07001271 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001272
Tony Mack5b061472014-02-04 07:57:10 -05001273 def queryset(self, request):
1274 return Reservation.select_by_user(request.user)
1275
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001276class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001277 list_display = ("backend_status_icon", "name", )
1278 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001279 user_readonly_fields = ['name']
1280 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001281
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001282class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001283 list_display = ("backend_status_icon", "name", )
1284 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001285 user_readonly_fields = ['name']
1286 user_readonly_inlines = []
1287
Scott Baker0165fac2014-01-13 11:49:26 -08001288class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001289 model = Router.networks.through
1290 extra = 0
1291 verbose_name_plural = "Routers"
1292 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001293 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001294
Scott Bakerb27b62c2014-08-15 16:29:16 -07001295class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001296 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07001297 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001298 verbose_name_plural = "Parameters"
1299 verbose_name = "Parameter"
1300 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07001301 fields = ['backend_status_icon', 'parameter', 'value']
1302 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001303
Scott Baker0165fac2014-01-13 11:49:26 -08001304class NetworkSliversInline(PlStackTabularInline):
Scott Baker40c00762014-08-21 16:55:59 -07001305 fields = ['backend_status_icon', 'network','sliver','ip']
1306 readonly_fields = ("backend_status_icon", "ip", )
Scott Baker74d8e622013-07-29 16:04:22 -07001307 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001308 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001309 extra = 0
1310 verbose_name_plural = "Slivers"
1311 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001312 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001313
Scott Baker0165fac2014-01-13 11:49:26 -08001314class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001315 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001316 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001317 extra = 0
1318 verbose_name_plural = "Slices"
1319 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001320 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Baker40c00762014-08-21 16:55:59 -07001321 fields = ['backend_status_icon', 'network','slice']
1322 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07001323
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001324class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001325 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
1326 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07001327 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001328
Scott Bakerd7d2a392013-08-06 08:57:30 -07001329 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001330
Siobhan Tully2d95e482013-09-06 10:56:06 -04001331 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001332 (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 -05001333
Scott Baker40c00762014-08-21 16:55:59 -07001334 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001335 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 -04001336
1337 suit_form_tabs =(
1338 ('general','Network Details'),
1339 ('netparams', 'Parameters'),
1340 ('networkslivers','Slivers'),
1341 ('networkslices','Slices'),
1342 ('routers','Routers'),
1343 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001344class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001345 list_display = ("backend_status_icon", "name", "guaranteedBandwidth", "visibility")
1346 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001347 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1348 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001349
Scott Baker37b47902014-09-02 14:37:41 -07001350class FlavorAdmin(PlanetStackBaseAdmin):
1351 list_display = ("backend_status_icon", "name", "flavor", "order", "default")
1352 list_display_links = ("backend_status_icon", "name")
1353 user_readonly_fields = ("name", "flavor")
1354 fields = ("name", "description", "flavor", "order", "default")
1355
Tony Mack31c2b8f2013-04-26 20:01:42 -04001356# register a signal that caches the user's credentials when they log in
1357def cache_credentials(sender, user, request, **kwds):
1358 auth = {'username': request.POST['username'],
1359 'password': request.POST['password']}
1360 request.session['auth'] = auth
1361user_logged_in.connect(cache_credentials)
1362
Scott Baker15cddfa2013-12-09 13:45:19 -08001363def dollar_field(fieldName, short_description):
1364 def newFunc(self, obj):
1365 try:
1366 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1367 except:
1368 x=getattr(obj, fieldName, 0.0)
1369 return x
1370 newFunc.short_description = short_description
1371 return newFunc
1372
1373def right_dollar_field(fieldName, short_description):
1374 def newFunc(self, obj):
1375 try:
1376 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1377 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1378 except:
1379 x=getattr(obj, fieldName, 0.0)
1380 return x
1381 newFunc.short_description = short_description
1382 newFunc.allow_tags = True
1383 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001384
Scott Baker0165fac2014-01-13 11:49:26 -08001385class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001386 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001387 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001388 verbose_name_plural = "Charges"
1389 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001390 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001391 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1392 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1393 can_delete = False
1394 max_num = 0
1395
1396 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001397
1398class InvoiceAdmin(admin.ModelAdmin):
1399 list_display = ("date", "account")
1400
1401 inlines = [InvoiceChargeInline]
1402
Scott Baker9cb88a22013-12-09 18:56:00 -08001403 fields = ["date", "account", "dollar_amount"]
1404 readonly_fields = ["date", "account", "dollar_amount"]
1405
1406 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001407
Scott Baker0165fac2014-01-13 11:49:26 -08001408class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001409 model = Invoice
1410 extra = 0
1411 verbose_name_plural = "Invoices"
1412 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001413 fields = ["date", "dollar_amount"]
1414 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001415 suit_classes = 'suit-tab suit-tab-accountinvoice'
1416 can_delete=False
1417 max_num=0
1418
1419 dollar_amount = right_dollar_field("amount", "Amount")
1420
Scott Baker0165fac2014-01-13 11:49:26 -08001421class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001422 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001423 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001424 verbose_name_plural = "Charges"
1425 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001426 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001427 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1428 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001429 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001430 can_delete=False
1431 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001432
1433 def queryset(self, request):
1434 qs = super(PendingChargeInline, self).queryset(request)
1435 qs = qs.filter(state="pending")
1436 return qs
1437
Scott Baker15cddfa2013-12-09 13:45:19 -08001438 dollar_amount = right_dollar_field("amount", "Amount")
1439
Scott Baker0165fac2014-01-13 11:49:26 -08001440class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001441 model=Payment
1442 extra = 1
1443 verbose_name_plural = "Payments"
1444 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001445 fields = ["date", "dollar_amount"]
1446 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001447 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001448 can_delete=False
1449 max_num=0
1450
1451 dollar_amount = right_dollar_field("amount", "Amount")
1452
Scott Baker43105042013-12-06 23:23:36 -08001453class AccountAdmin(admin.ModelAdmin):
1454 list_display = ("site", "balance_due")
1455
1456 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1457
1458 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001459 (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 -08001460
Scott Baker15cddfa2013-12-09 13:45:19 -08001461 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001462
1463 suit_form_tabs =(
1464 ('general','Account Details'),
1465 ('accountinvoice', 'Invoices'),
1466 ('accountpayments', 'Payments'),
1467 ('accountpendingcharges','Pending Charges'),
1468 )
1469
Scott Baker15cddfa2013-12-09 13:45:19 -08001470 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1471 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1472 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1473
Siobhan Tully53437282013-04-26 19:30:27 -04001474# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001475admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001476# ... and, since we're not using Django's builtin permissions,
1477# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001478#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001479
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001480#Do not show django evolution in the admin interface
1481from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001482#admin.site.unregister(Version)
1483#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001484
1485
1486# When debugging it is often easier to see all the classes, but for regular use
1487# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001488showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001489
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001490admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001491admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001492admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001493admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001494admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001495admin.site.register(Network, NetworkAdmin)
1496admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001497admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001498admin.site.register(Account, AccountAdmin)
1499admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001500
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001501if True:
1502 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1503 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001504 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001505 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001506 admin.site.register(DeploymentRole)
1507 admin.site.register(SiteRole)
1508 admin.site.register(SliceRole)
1509 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001510 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001511 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1512 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001513 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001514 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001515 admin.site.register(DashboardView, DashboardViewAdmin)
Scott Baker37b47902014-09-02 14:37:41 -07001516 admin.site.register(Flavor, FlavorAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001517