blob: 3e57ee0450b1527140e7f8b51d63efebfbf4bcdf [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
Scott Baker93e80cd2014-09-09 09:58:49 -0700767 deployment_images = []
768 for image in Image.objects.all():
769 for imageDeployment in image.imagedeployments_set.all():
770 deployment_images.append( (imageDeployment.deployment.id, image.id, image.name) )
771
Tony Mackec23b992014-09-02 21:18:45 -0400772 site_login_bases = []
773 for site in Site.objects.all():
Scott Baker93e80cd2014-09-09 09:58:49 -0700774 site_login_bases.append((site.id, site.login_base))
775
Scott Baker510fdbb2014-08-05 17:19:24 -0700776 context["deployment_nodes"] = deployment_nodes
Scott Baker7a61dc42014-09-02 17:08:20 -0700777 context["deployment_flavors"] = deployment_flavors
Scott Baker93e80cd2014-09-09 09:58:49 -0700778 context["deployment_images"] = deployment_images
Tony Mackec23b992014-09-02 21:18:45 -0400779 context["site_login_bases"] = site_login_bases
Scott Baker510fdbb2014-08-05 17:19:24 -0700780 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
781
Tony Mackc2835a92013-05-28 09:18:49 -0400782 def formfield_for_foreignkey(self, db_field, request, **kwargs):
783 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500784 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackec23b992014-09-02 21:18:45 -0400785 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 -0700786
Tony Mackc2835a92013-05-28 09:18:49 -0400787 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
788
Tony Mack04062832013-05-10 08:22:44 -0400789 def queryset(self, request):
790 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500791 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400792
Tony Mack79748612013-05-01 14:52:03 -0400793 def get_formsets(self, request, obj=None):
794 for inline in self.get_inline_instances(request, obj):
795 # hide MyInline in the add view
796 if obj is None:
797 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400798 if isinstance(inline, SliverInline):
799 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400800 yield inline.get_formset(request, obj)
801
Tony Mack2bd5b412013-06-11 21:05:06 -0400802
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400803class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400804 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700805 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -0400806 ]
Scott Baker40c00762014-08-21 16:55:59 -0700807 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700808 list_display = ('backend_status_icon', 'user', 'slice', 'role')
809 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -0400810
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500811 user_readonly_fields = ['user', 'slice', 'role']
812 user_readonly_inlines = []
813
Tony Mackc2835a92013-05-28 09:18:49 -0400814 def formfield_for_foreignkey(self, db_field, request, **kwargs):
815 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500816 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400817
818 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500819 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400820
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400821 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400822
Tony Mack04062832013-05-10 08:22:44 -0400823 def queryset(self, request):
824 # admins can see all memberships. Users can only see memberships of
825 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500826 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400827
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400828 def save_model(self, request, obj, form, change):
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.save()
834
835 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400836 # update openstack connection to use this site/tenant
837 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400838 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400839 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400840 obj.delete()
841
Siobhan Tully567e3e62013-06-21 18:03:16 -0400842
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400843class ImageAdmin(PlanetStackBaseAdmin):
844
Scott Baker36f50872014-08-21 13:01:25 -0700845 fieldsets = [('Image Details',
Scott Baker40c00762014-08-21 16:55:59 -0700846 {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400847 'classes': ['suit-tab suit-tab-general']})
848 ]
Scott Baker40c00762014-08-21 16:55:59 -0700849 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400850
Scott Baker2170b972014-06-03 12:14:07 -0700851 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400852
Scott Baker2170b972014-06-03 12:14:07 -0700853 inlines = [SliverInline, ImageDeploymentsInline]
Scott Bakerb6f99242014-06-11 11:34:44 -0700854
Tony Mack32e1ce32014-05-07 13:29:41 -0400855 user_readonly_fields = ['name', 'disk_format', 'container_format']
Scott Bakerb27b62c2014-08-15 16:29:16 -0700856
Scott Baker63d1a552014-08-21 15:19:07 -0700857 list_display = ['backend_status_icon', 'name']
858 list_display_links = ('backend_status_icon', 'name', )
859
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400860class NodeForm(forms.ModelForm):
861 class Meta:
862 widgets = {
863 'site': LinkedSelect,
864 'deployment': LinkedSelect
865 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400866
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500867class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400868 form = NodeForm
Scott Baker63d1a552014-08-21 15:19:07 -0700869 list_display = ('backend_status_icon', 'name', 'site', 'deployment')
870 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400871 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500872
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400873 inlines = [TagInline,SliverInline]
Scott Baker40c00762014-08-21 16:55:59 -0700874 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
875 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400876
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500877 user_readonly_fields = ['name','site','deployment']
878 user_readonly_inlines = [TagInline,SliverInline]
879
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400880 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400881
Siobhan Tully567e3e62013-06-21 18:03:16 -0400882
Tony Mackd90cdbf2013-04-16 22:48:40 -0400883class SliverForm(forms.ModelForm):
884 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400885 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400886 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400887 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400888 widgets = {
889 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400890 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400891 'slice': LinkedSelect,
892 'deploymentNetwork': LinkedSelect,
893 'node': LinkedSelect,
894 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400895 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400896
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500897class TagAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700898 list_display = ['backend_status_icon', 'service', 'name', 'value', 'content_type', 'content_object',]
899 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500900 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
901 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400902
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400903class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400904 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400905 fieldsets = [
Scott Baker7a61dc42014-09-02 17:08:20 -0700906 ('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 -0400907 ]
Scott Baker40c00762014-08-21 16:55:59 -0700908 readonly_fields = ('backend_status_text', )
Scott Baker7a61dc42014-09-02 17:08:20 -0700909 list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deploymentNetwork']
Scott Baker63d1a552014-08-21 15:19:07 -0700910 list_display_links = ('backend_status_icon', 'ip',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400911
912 suit_form_tabs =(('general', 'Sliver Details'),
913 ('tags','Tags'),
914 )
915
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400916 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400917
Scott Baker7a61dc42014-09-02 17:08:20 -0700918 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500919
Tony Mackc2835a92013-05-28 09:18:49 -0400920 def formfield_for_foreignkey(self, db_field, request, **kwargs):
921 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500922 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400923
924 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
925
Tony Mack04062832013-05-10 08:22:44 -0400926 def queryset(self, request):
Scott Baker36f50872014-08-21 13:01:25 -0700927 # admins can see all slivers. Users can only see slivers of
Tony Mack04062832013-05-10 08:22:44 -0400928 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500929 return Sliver.select_by_user(request.user)
930
Tony Mack04062832013-05-10 08:22:44 -0400931
Tony Mack1d6b85f2013-05-07 18:49:14 -0400932 def get_formsets(self, request, obj=None):
933 # make some fields read only if we are updating an existing record
934 if obj == None:
Scott Baker36f50872014-08-21 13:01:25 -0700935 #self.readonly_fields = ('ip', 'instance_name')
Scott Baker40c00762014-08-21 16:55:59 -0700936 self.readonly_fields = ('backend_status_text')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400937 else:
Scott Baker40c00762014-08-21 16:55:59 -0700938 self.readonly_fields = ('backend_status_text')
Scott Baker36f50872014-08-21 13:01:25 -0700939 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400940
941 for inline in self.get_inline_instances(request, obj):
942 # hide MyInline in the add view
943 if obj is None:
944 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700945 if isinstance(inline, SliverInline):
946 inline.model.caller = request.user
947 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400948
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500949 #def save_model(self, request, obj, form, change):
950 # # update openstack connection to use this site/tenant
951 # auth = request.session.get('auth', {})
952 # auth['tenant'] = obj.slice.name
953 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
954 # obj.creator = request.user
955 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400956
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500957 #def delete_model(self, request, obj):
958 # # update openstack connection to use this site/tenant
959 # auth = request.session.get('auth', {})
960 # auth['tenant'] = obj.slice.name
961 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
962 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400963
Siobhan Tully53437282013-04-26 19:30:27 -0400964class UserCreationForm(forms.ModelForm):
965 """A form for creating new users. Includes all the required
966 fields, plus a repeated password."""
967 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
968 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
969
970 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400971 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400972 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400973
974 def clean_password2(self):
975 # Check that the two password entries match
976 password1 = self.cleaned_data.get("password1")
977 password2 = self.cleaned_data.get("password2")
978 if password1 and password2 and password1 != password2:
979 raise forms.ValidationError("Passwords don't match")
980 return password2
981
982 def save(self, commit=True):
983 # Save the provided password in hashed format
984 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400985 user.password = self.cleaned_data["password1"]
986 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400987 if commit:
988 user.save()
989 return user
990
Siobhan Tully567e3e62013-06-21 18:03:16 -0400991
Siobhan Tully53437282013-04-26 19:30:27 -0400992class UserChangeForm(forms.ModelForm):
993 """A form for updating users. Includes all the fields on
994 the user, but replaces the password field with admin's
995 password hash display field.
996 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500997 password = ReadOnlyPasswordHashField(label='Password',
998 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400999
1000 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -04001001 model = User
Siobhan Tully53437282013-04-26 19:30:27 -04001002
1003 def clean_password(self):
1004 # Regardless of what the user provides, return the initial value.
1005 # This is done here, rather than on the field, because the
1006 # field does not have access to the initial value
1007 return self.initial["password"]
1008
Scott Baker2c3cb642014-05-19 17:55:56 -07001009class UserDashboardViewInline(PlStackTabularInline):
1010 model = UserDashboardView
1011 extra = 0
1012 suit_classes = 'suit-tab suit-tab-dashboards'
1013 fields = ['user', 'dashboardView', 'order']
1014
Tony Mack2bd5b412013-06-11 21:05:06 -04001015class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -04001016 class Meta:
1017 app_label = "core"
1018
1019 # The forms to add and change user instances
1020 form = UserChangeForm
1021 add_form = UserCreationForm
1022
1023 # The fields to be used in displaying the User model.
1024 # These override the definitions on the base UserAdmin
1025 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001026 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001027 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -07001028 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001029
Scott Bakeradae55f2014-08-14 17:32:35 -07001030 fieldListLoginDetails = ['email','site','password','is_active','is_readonly','is_admin','public_key']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001031 fieldListContactInfo = ['firstname','lastname','phone','timezone']
1032
Siobhan Tully53437282013-04-26 19:30:27 -04001033 fieldsets = (
Scott Baker40c00762014-08-21 16:55:59 -07001034 ('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 -04001035 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -07001036 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001037 #('Important dates', {'fields': ('last_login',)}),
1038 )
1039 add_fieldsets = (
1040 (None, {
1041 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001042 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -04001043 ),
1044 )
Scott Baker40c00762014-08-21 16:55:59 -07001045 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001046 search_fields = ('email',)
1047 ordering = ('email',)
1048 filter_horizontal = ()
1049
Scott Baker3ca51f62014-05-23 12:05:11 -07001050 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001051
Scott Baker2c3cb642014-05-19 17:55:56 -07001052 suit_form_tabs =(('general','Login Details'),
1053 ('contact','Contact Information'),
1054 ('sliceprivileges','Slice Privileges'),
1055 ('siteprivileges','Site Privileges'),
1056 ('deploymentprivileges','Deployment Privileges'),
1057 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001058
Tony Mackc2835a92013-05-28 09:18:49 -04001059 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1060 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001061 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001062
1063 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1064
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001065 def has_add_permission(self, request, obj=None):
1066 return (not self.__user_is_readonly(request))
1067
1068 def has_delete_permission(self, request, obj=None):
1069 return (not self.__user_is_readonly(request))
1070
1071 def get_actions(self,request):
1072 actions = super(UserAdmin,self).get_actions(request)
1073
1074 if self.__user_is_readonly(request):
1075 if 'delete_selected' in actions:
1076 del actions['delete_selected']
1077
1078 return actions
1079
1080 def change_view(self,request,object_id, extra_context=None):
1081
1082 if self.__user_is_readonly(request):
Scott Bakerf875eba2014-05-23 12:09:15 -07001083 if not hasattr(self, "readonly_save"):
1084 # save the original readonly fields
1085 self.readonly_save = self.readonly_fields
1086 self.inlines_save = self.inlines
Scott Bakerb27b62c2014-08-15 16:29:16 -07001087 if hasattr(self, "user_readonly_fields"):
1088 self.readonly_fields=self.user_readonly_fields
1089 if hasattr(self, "user_readonly_inlines"):
1090 self.inlines = self.user_readonly_inlines
Scott Bakerf875eba2014-05-23 12:09:15 -07001091 else:
1092 if hasattr(self, "readonly_save"):
1093 # restore the original readonly fields
1094 self.readonly_fields = self.readonly_save
1095 self.inlines = self.inlines_save
1096
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001097 try:
1098 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1099 except PermissionDenied:
1100 pass
1101 if request.method == 'POST':
1102 raise PermissionDenied
1103 request.readonly = True
1104 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1105
1106 def __user_is_readonly(self, request):
1107 #groups = [x.name for x in request.user.groups.all() ]
1108 #return "readonly" in groups
1109 return request.user.isReadOnlyUser()
1110
Tony Mack5b061472014-02-04 07:57:10 -05001111 def queryset(self, request):
1112 return User.select_by_user(request.user)
1113
Scott Baker40c00762014-08-21 16:55:59 -07001114 def backend_status_text(self, obj):
1115 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -07001116
Scott Baker40c00762014-08-21 16:55:59 -07001117 def backend_status_icon(self, obj):
1118 return mark_safe(backend_icon(obj))
1119 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -07001120
Scott Baker2c3cb642014-05-19 17:55:56 -07001121class DashboardViewAdmin(PlanetStackBaseAdmin):
1122 fieldsets = [('Dashboard View Details',
Scott Baker40c00762014-08-21 16:55:59 -07001123 {'fields': ['backend_status_text', 'name', 'url'],
Scott Baker2c3cb642014-05-19 17:55:56 -07001124 'classes': ['suit-tab suit-tab-general']})
1125 ]
Scott Baker40c00762014-08-21 16:55:59 -07001126 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001127
Scott Baker2c3cb642014-05-19 17:55:56 -07001128 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001129
Scott Baker0165fac2014-01-13 11:49:26 -08001130class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001131 model = ServiceResource
1132 extra = 0
1133
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001134class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001135 list_display = ('backend_status_icon', 'name', 'commitment', 'membershipFee')
1136 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001137 inlines = [ServiceResourceInline]
1138
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001139 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1140 user_readonly_inlines = []
1141
Scott Baker0165fac2014-01-13 11:49:26 -08001142class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001143 model = ReservedResource
1144 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001145 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001146
1147 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1148 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1149
1150 if db_field.name == 'resource':
1151 # restrict resources to those that the slice's service class allows
1152 if request._slice is not None:
1153 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1154 if len(field.queryset) > 0:
1155 field.initial = field.queryset.all()[0]
1156 else:
1157 field.queryset = field.queryset.none()
1158 elif db_field.name == 'sliver':
1159 # restrict slivers to those that belong to the slice
1160 if request._slice is not None:
1161 field.queryset = field.queryset.filter(slice = request._slice)
1162 else:
1163 field.queryset = field.queryset.none()
1164
1165 return field
1166
Tony Mack5b061472014-02-04 07:57:10 -05001167 def queryset(self, request):
1168 return ReservedResource.select_by_user(request.user)
1169
Scott Baker133c9212013-05-17 09:09:11 -07001170class ReservationChangeForm(forms.ModelForm):
1171 class Meta:
1172 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001173 widgets = {
1174 'slice' : LinkedSelect
1175 }
Scott Baker133c9212013-05-17 09:09:11 -07001176
1177class ReservationAddForm(forms.ModelForm):
1178 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1179 refresh = forms.CharField(widget=forms.HiddenInput())
1180
1181 class Media:
1182 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1183
1184 def clean_slice(self):
1185 slice = self.cleaned_data.get("slice")
1186 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1187 if len(x) == 0:
1188 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1189 return slice
1190
1191 class Meta:
1192 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001193 widgets = {
1194 'slice' : LinkedSelect
1195 }
1196
Scott Baker133c9212013-05-17 09:09:11 -07001197
1198class ReservationAddRefreshForm(ReservationAddForm):
1199 """ This form is displayed when the Reservation Form receives an update
1200 from the Slice dropdown onChange handler. It doesn't validate the
1201 data and doesn't save the data. This will cause the form to be
1202 redrawn.
1203 """
1204
Scott Baker8737e5f2013-05-17 09:35:32 -07001205 """ don't validate anything other than slice """
1206 dont_validate_fields = ("startTime", "duration")
1207
Scott Baker133c9212013-05-17 09:09:11 -07001208 def full_clean(self):
1209 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001210
1211 for fieldname in self.dont_validate_fields:
1212 if fieldname in self._errors:
1213 del self._errors[fieldname]
1214
Scott Baker133c9212013-05-17 09:09:11 -07001215 return result
1216
1217 """ don't save anything """
1218 def is_valid(self):
1219 return False
1220
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001221class ReservationAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001222 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001223 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001224 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001225 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001226 form = ReservationAddForm
1227
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001228 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1229
1230 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001231 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001232
Scott Baker133c9212013-05-17 09:09:11 -07001233 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001234 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001235 request._refresh = False
1236 request._slice = None
1237 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001238 # "refresh" will be set to "1" if the form was submitted due to
1239 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001240 if request.POST.get("refresh","1") == "1":
1241 request._refresh = True
1242 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001243
1244 # Keep track of the slice that was selected, so the
1245 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001246 request._slice = request.POST.get("slice",None)
1247 if (request._slice is not None):
1248 request._slice = Slice.objects.get(id=request._slice)
1249
1250 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1251 return result
1252
Scott Bakeracd45142013-05-19 16:19:16 -07001253 def changelist_view(self, request, extra_context = None):
1254 timezone.activate(request.user.timezone)
1255 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1256
Scott Baker133c9212013-05-17 09:09:11 -07001257 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001258 request._obj_ = obj
1259 if obj is not None:
1260 # For changes, set request._slice to the slice already set in the
1261 # object.
1262 request._slice = obj.slice
1263 self.form = ReservationChangeForm
1264 else:
1265 if getattr(request, "_refresh", False):
1266 self.form = ReservationAddRefreshForm
1267 else:
1268 self.form = ReservationAddForm
1269 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1270
Scott Baker133c9212013-05-17 09:09:11 -07001271 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001272 if (obj is not None):
1273 # Prevent slice from being changed after the reservation has been
1274 # created.
1275 return ['slice']
1276 else:
Scott Baker133c9212013-05-17 09:09:11 -07001277 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001278
Tony Mack5b061472014-02-04 07:57:10 -05001279 def queryset(self, request):
1280 return Reservation.select_by_user(request.user)
1281
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001282class NetworkParameterTypeAdmin(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 = []
Scott Baker74d8e622013-07-29 16:04:22 -07001287
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001288class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001289 list_display = ("backend_status_icon", "name", )
1290 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001291 user_readonly_fields = ['name']
1292 user_readonly_inlines = []
1293
Scott Baker0165fac2014-01-13 11:49:26 -08001294class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001295 model = Router.networks.through
1296 extra = 0
1297 verbose_name_plural = "Routers"
1298 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001299 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001300
Scott Bakerb27b62c2014-08-15 16:29:16 -07001301class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001302 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07001303 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001304 verbose_name_plural = "Parameters"
1305 verbose_name = "Parameter"
1306 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07001307 fields = ['backend_status_icon', 'parameter', 'value']
1308 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001309
Scott Baker0165fac2014-01-13 11:49:26 -08001310class NetworkSliversInline(PlStackTabularInline):
Scott Baker40c00762014-08-21 16:55:59 -07001311 fields = ['backend_status_icon', 'network','sliver','ip']
1312 readonly_fields = ("backend_status_icon", "ip", )
Scott Baker74d8e622013-07-29 16:04:22 -07001313 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001314 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001315 extra = 0
1316 verbose_name_plural = "Slivers"
1317 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001318 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001319
Scott Baker0165fac2014-01-13 11:49:26 -08001320class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001321 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001322 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001323 extra = 0
1324 verbose_name_plural = "Slices"
1325 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001326 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Baker40c00762014-08-21 16:55:59 -07001327 fields = ['backend_status_icon', 'network','slice']
1328 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07001329
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001330class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001331 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
1332 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07001333 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001334
Scott Bakerd7d2a392013-08-06 08:57:30 -07001335 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001336
Siobhan Tully2d95e482013-09-06 10:56:06 -04001337 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001338 (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 -05001339
Scott Baker40c00762014-08-21 16:55:59 -07001340 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001341 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 -04001342
1343 suit_form_tabs =(
1344 ('general','Network Details'),
1345 ('netparams', 'Parameters'),
1346 ('networkslivers','Slivers'),
1347 ('networkslices','Slices'),
1348 ('routers','Routers'),
1349 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001350class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001351 list_display = ("backend_status_icon", "name", "guaranteedBandwidth", "visibility")
1352 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001353 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1354 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001355
Scott Baker37b47902014-09-02 14:37:41 -07001356class FlavorAdmin(PlanetStackBaseAdmin):
1357 list_display = ("backend_status_icon", "name", "flavor", "order", "default")
1358 list_display_links = ("backend_status_icon", "name")
1359 user_readonly_fields = ("name", "flavor")
1360 fields = ("name", "description", "flavor", "order", "default")
1361
Tony Mack31c2b8f2013-04-26 20:01:42 -04001362# register a signal that caches the user's credentials when they log in
1363def cache_credentials(sender, user, request, **kwds):
1364 auth = {'username': request.POST['username'],
1365 'password': request.POST['password']}
1366 request.session['auth'] = auth
1367user_logged_in.connect(cache_credentials)
1368
Scott Baker15cddfa2013-12-09 13:45:19 -08001369def dollar_field(fieldName, short_description):
1370 def newFunc(self, obj):
1371 try:
1372 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1373 except:
1374 x=getattr(obj, fieldName, 0.0)
1375 return x
1376 newFunc.short_description = short_description
1377 return newFunc
1378
1379def right_dollar_field(fieldName, short_description):
1380 def newFunc(self, obj):
1381 try:
1382 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1383 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1384 except:
1385 x=getattr(obj, fieldName, 0.0)
1386 return x
1387 newFunc.short_description = short_description
1388 newFunc.allow_tags = True
1389 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001390
Scott Baker0165fac2014-01-13 11:49:26 -08001391class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001392 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001393 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001394 verbose_name_plural = "Charges"
1395 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001396 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001397 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1398 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1399 can_delete = False
1400 max_num = 0
1401
1402 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001403
1404class InvoiceAdmin(admin.ModelAdmin):
1405 list_display = ("date", "account")
1406
1407 inlines = [InvoiceChargeInline]
1408
Scott Baker9cb88a22013-12-09 18:56:00 -08001409 fields = ["date", "account", "dollar_amount"]
1410 readonly_fields = ["date", "account", "dollar_amount"]
1411
1412 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001413
Scott Baker0165fac2014-01-13 11:49:26 -08001414class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001415 model = Invoice
1416 extra = 0
1417 verbose_name_plural = "Invoices"
1418 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001419 fields = ["date", "dollar_amount"]
1420 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001421 suit_classes = 'suit-tab suit-tab-accountinvoice'
1422 can_delete=False
1423 max_num=0
1424
1425 dollar_amount = right_dollar_field("amount", "Amount")
1426
Scott Baker0165fac2014-01-13 11:49:26 -08001427class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001428 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001429 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001430 verbose_name_plural = "Charges"
1431 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001432 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001433 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1434 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001435 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001436 can_delete=False
1437 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001438
1439 def queryset(self, request):
1440 qs = super(PendingChargeInline, self).queryset(request)
1441 qs = qs.filter(state="pending")
1442 return qs
1443
Scott Baker15cddfa2013-12-09 13:45:19 -08001444 dollar_amount = right_dollar_field("amount", "Amount")
1445
Scott Baker0165fac2014-01-13 11:49:26 -08001446class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001447 model=Payment
1448 extra = 1
1449 verbose_name_plural = "Payments"
1450 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001451 fields = ["date", "dollar_amount"]
1452 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001453 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001454 can_delete=False
1455 max_num=0
1456
1457 dollar_amount = right_dollar_field("amount", "Amount")
1458
Scott Baker43105042013-12-06 23:23:36 -08001459class AccountAdmin(admin.ModelAdmin):
1460 list_display = ("site", "balance_due")
1461
1462 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1463
1464 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001465 (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 -08001466
Scott Baker15cddfa2013-12-09 13:45:19 -08001467 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001468
1469 suit_form_tabs =(
1470 ('general','Account Details'),
1471 ('accountinvoice', 'Invoices'),
1472 ('accountpayments', 'Payments'),
1473 ('accountpendingcharges','Pending Charges'),
1474 )
1475
Scott Baker15cddfa2013-12-09 13:45:19 -08001476 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1477 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1478 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1479
Siobhan Tully53437282013-04-26 19:30:27 -04001480# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001481admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001482# ... and, since we're not using Django's builtin permissions,
1483# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001484#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001485
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001486#Do not show django evolution in the admin interface
1487from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001488#admin.site.unregister(Version)
1489#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001490
1491
1492# When debugging it is often easier to see all the classes, but for regular use
1493# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001494showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001495
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001496admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001497admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001498admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001499admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001500admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001501admin.site.register(Network, NetworkAdmin)
1502admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001503admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001504admin.site.register(Account, AccountAdmin)
1505admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001506
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001507if True:
1508 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1509 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001510 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001511 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001512 admin.site.register(DeploymentRole)
1513 admin.site.register(SiteRole)
1514 admin.site.register(SliceRole)
1515 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001516 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001517 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1518 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001519 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001520 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001521 admin.site.register(DashboardView, DashboardViewAdmin)
Scott Baker37b47902014-09-02 14:37:41 -07001522 admin.site.register(Flavor, FlavorAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001523