blob: 47f9eabb6c8a826bf342880edcd6eef085246ada [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
Scott Bakercbfb6002014-10-03 00:32:37 -070011from django.contrib.auth.forms import ReadOnlyPasswordHashField, AdminPasswordChangeForm
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
Scott Baker0a5633b2014-10-06 17:51:20 -070020import threading
21
22# thread locals necessary to work around a django-suit issue
23_thread_locals = threading.local()
Scott Baker36f50872014-08-21 13:01:25 -070024
Scott Baker40c00762014-08-21 16:55:59 -070025def backend_icon(obj): # backend_status, enacted, updated):
26 #return "%s %s %s" % (str(obj.updated), str(obj.enacted), str(obj.backend_status))
27 if (obj.enacted is not None) and obj.enacted >= obj.updated:
Scott Bakerfbf06642014-09-09 10:38:15 -070028 return '<span style="min-width:16px;"><img src="/static/admin/img/icon_success.gif"></span>'
Scott Baker40c00762014-08-21 16:55:59 -070029 else:
30 if obj.backend_status == "Provisioning in progress" or obj.backend_status=="":
Scott Bakerfbf06642014-09-09 10:38:15 -070031 return '<span style="min-width:16px;" title="%s"><img src="/static/admin/img/icon_clock.gif"></span>' % obj.backend_status
Scott Baker63d1a552014-08-21 15:19:07 -070032 else:
Scott Bakerfbf06642014-09-09 10:38:15 -070033 return '<span style="min-width:16px;" title="%s"><img src="/static/admin/img/icon_error.gif"></span>' % obj.backend_status
Scott Baker40c00762014-08-21 16:55:59 -070034
35def backend_text(obj):
36 icon = backend_icon(obj)
37 if (obj.enacted is not None) and obj.enacted >= obj.updated:
38 return "%s %s" % (icon, "successfully enacted") # enacted on %s" % str(obj.enacted))
39 else:
40 return "%s %s" % (icon, obj.backend_status)
Scott Baker63d1a552014-08-21 15:19:07 -070041
Scott Baker36f50872014-08-21 13:01:25 -070042class PlainTextWidget(forms.HiddenInput):
43 input_type = 'hidden'
44
45 def render(self, name, value, attrs=None):
46 if value is None:
47 value = ''
48 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
49
Scott Baker86c83ab2014-10-03 13:10:47 -070050class PermissionCheckingAdminMixin(object):
Scott Bakercbfb6002014-10-03 00:32:37 -070051 # call save_by_user and delete_by_user instead of save and delete
Siobhan Tullycf04fb62014-01-11 11:25:57 -050052
53 def has_add_permission(self, request, obj=None):
54 return (not self.__user_is_readonly(request))
Scott Baker36f50872014-08-21 13:01:25 -070055
Siobhan Tullycf04fb62014-01-11 11:25:57 -050056 def has_delete_permission(self, request, obj=None):
57 return (not self.__user_is_readonly(request))
58
59 def save_model(self, request, obj, form, change):
60 if self.__user_is_readonly(request):
Scott Bakercbfb6002014-10-03 00:32:37 -070061 # this 'if' might be redundant if save_by_user is implemented right
Siobhan Tullycf04fb62014-01-11 11:25:57 -050062 raise PermissionDenied
Scott Bakercbfb6002014-10-03 00:32:37 -070063
64 obj.caller = request.user
65 # update openstack connection to use this site/tenant
66 obj.save_by_user(request.user)
67
68 def delete_model(self, request, obj):
69 obj.delete_by_user(request.user)
70
71 def save_formset(self, request, form, formset, change):
72 instances = formset.save(commit=False)
73 for instance in instances:
74 instance.save_by_user(request.user)
75
76 # BUG in django 1.7? Objects are not deleted by formset.save if
77 # commit is False. So let's delete them ourselves.
78 #
79 # code from forms/models.py save_existing_objects()
80 try:
81 forms_to_delete = formset.deleted_forms
82 except AttributeError:
83 forms_to_delete = []
84 if formset.initial_forms:
85 for form in formset.initial_forms:
86 obj = form.instance
87 if form in forms_to_delete:
88 if obj.pk is None:
89 continue
90 formset.deleted_objects.append(obj)
91 obj.delete()
92
93 formset.save_m2m()
Siobhan Tullycf04fb62014-01-11 11:25:57 -050094
95 def get_actions(self,request):
Scott Baker86c83ab2014-10-03 13:10:47 -070096 actions = super(PermissionCheckingAdminMixin,self).get_actions(request)
Siobhan Tullycf04fb62014-01-11 11:25:57 -050097
98 if self.__user_is_readonly(request):
99 if 'delete_selected' in actions:
100 del actions['delete_selected']
101
102 return actions
103
104 def change_view(self,request,object_id, extra_context=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500105 if self.__user_is_readonly(request):
Scott Bakeraf73e102014-04-22 22:40:07 -0700106 if not hasattr(self, "readonly_save"):
107 # save the original readonly fields
108 self.readonly_save = self.readonly_fields
109 self.inlines_save = self.inlines
Scott Bakere8859f92014-05-23 12:42:40 -0700110 if hasattr(self, "user_readonly_fields"):
111 self.readonly_fields=self.user_readonly_fields
112 if hasattr(self, "user_readonly_inlines"):
113 self.inlines = self.user_readonly_inlines
Scott Bakeraf73e102014-04-22 22:40:07 -0700114 else:
115 if hasattr(self, "readonly_save"):
116 # restore the original readonly fields
117 self.readonly_fields = self.readonly_save
Scott Bakere8859f92014-05-23 12:42:40 -0700118 if hasattr(self, "inlines_save"):
Scott Bakeraf73e102014-04-22 22:40:07 -0700119 self.inlines = self.inlines_save
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500120
121 try:
Scott Baker86c83ab2014-10-03 13:10:47 -0700122 return super(PermissionCheckingAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500123 except PermissionDenied:
124 pass
125 if request.method == 'POST':
126 raise PermissionDenied
127 request.readonly = True
Scott Baker86c83ab2014-10-03 13:10:47 -0700128 return super(PermissionCheckingAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500129
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500130 def __user_is_readonly(self, request):
131 return request.user.isReadOnlyUser()
132
Scott Baker40c00762014-08-21 16:55:59 -0700133 def backend_status_text(self, obj):
134 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -0700135
Scott Baker63d1a552014-08-21 15:19:07 -0700136 def backend_status_icon(self, obj):
Scott Baker40c00762014-08-21 16:55:59 -0700137 return mark_safe(backend_icon(obj))
Scott Baker63d1a552014-08-21 15:19:07 -0700138 backend_status_icon.short_description = ""
139
Scott Baker86c83ab2014-10-03 13:10:47 -0700140class ReadOnlyAwareAdmin(PermissionCheckingAdminMixin, admin.ModelAdmin):
141 # Note: Make sure PermissionCheckingAdminMixin is listed before
142 # admin.ModelAdmin in the class declaration.
143
Scott Bakercbfb6002014-10-03 00:32:37 -0700144 pass
145
146class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
147 save_on_top = False
Scott Baker36f50872014-08-21 13:01:25 -0700148
Scott Bakere8859f92014-05-23 12:42:40 -0700149class SingletonAdmin (ReadOnlyAwareAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400150 def has_add_permission(self, request):
Scott Bakere8859f92014-05-23 12:42:40 -0700151 if not super(SingletonAdmin, self).has_add_permission(request):
152 return False
153
Siobhan Tullyce652d02013-10-08 21:52:35 -0400154 num_objects = self.model.objects.count()
155 if num_objects >= 1:
156 return False
157 else:
158 return True
159
Siobhan Tullyd3515752013-06-21 16:34:53 -0400160class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -0800161 def __init__(self, *args, **kwargs):
162 super(PlStackTabularInline, self).__init__(*args, **kwargs)
163
164 # InlineModelAdmin as no get_fields() method, so in order to add
165 # the selflink field, we override __init__ to modify self.fields and
166 # self.readonly_fields.
167
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800168 self.setup_selflink()
169
Scott Baker874936e2014-01-13 18:15:34 -0800170 def get_change_url(self, model, id):
171 """ Get the URL to a change form in the admin for this model """
172 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800173 try:
Scott Baker874936e2014-01-13 18:15:34 -0800174 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800175 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -0800176 return None
177
178 return url
179
180 def setup_selflink(self):
181 if hasattr(self, "selflink_fieldname"):
182 """ self.selflink_model can be defined to punch through a relation
183 to its target object. For example, in SliceNetworkInline, set
184 selflink_model = "network", and the URL will lead to the Network
185 object instead of trying to bring up a change view of the
186 SliceNetwork object.
187 """
188 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
189 else:
190 self.selflink_model = self.model
191
192 url = self.get_change_url(self.selflink_model, 0)
193
194 # We don't have an admin for this object, so don't create the
195 # selflink.
196 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800197 return
198
Scott Baker874936e2014-01-13 18:15:34 -0800199 # Since we need to add "selflink" to the field list, we need to create
200 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800201 if (self.fields is None):
202 self.fields = []
203 for f in self.model._meta.fields:
204 if f.editable and f.name != "id":
205 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800206
Scott Baker874936e2014-01-13 18:15:34 -0800207 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800208
Scott Baker874936e2014-01-13 18:15:34 -0800209 if self.readonly_fields is None:
210 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800211
Scott Baker874936e2014-01-13 18:15:34 -0800212 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800213
214 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800215 if hasattr(self, "selflink_fieldname"):
216 obj = getattr(obj, self.selflink_fieldname)
217
Scott Baker86568322014-01-12 16:53:31 -0800218 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800219 url = self.get_change_url(self.selflink_model, obj.id)
220 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800221 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800222 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800223
224 selflink.allow_tags = True
225 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400226
Scott Bakerb27b62c2014-08-15 16:29:16 -0700227 def has_add_permission(self, request):
228 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500229
230 def get_readonly_fields(self, request, obj=None):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700231 readonly_fields = list(self.readonly_fields)[:]
232 if request.user.isReadOnlyUser():
233 for field in self.fields:
234 if not field in readonly_fields:
235 readonly_fields.append(field)
236 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500237
Scott Baker40c00762014-08-21 16:55:59 -0700238 def backend_status_icon(self, obj):
239 return mark_safe(backend_icon(obj))
240 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -0700241
Scott Bakerb27b62c2014-08-15 16:29:16 -0700242class PlStackGenericTabularInline(generic.GenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500243 def has_add_permission(self, request):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700244 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500245
Scott Bakerb27b62c2014-08-15 16:29:16 -0700246 def get_readonly_fields(self, request, obj=None):
247 readonly_fields = list(self.readonly_fields)[:]
248 if request.user.isReadOnlyUser():
249 for field in self.fields:
250 if not field in readonly_fields:
251 readonly_fields.append(field)
252 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500253
Scott Baker40c00762014-08-21 16:55:59 -0700254 def backend_status_icon(self, obj):
255 return mark_safe(backend_icon(obj))
256 backend_status_icon.short_description = ""
257
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400258class ReservationInline(PlStackTabularInline):
259 model = Reservation
260 extra = 0
261 suit_classes = 'suit-tab suit-tab-reservations'
Scott Baker36f50872014-08-21 13:01:25 -0700262
Tony Mack5b061472014-02-04 07:57:10 -0500263 def queryset(self, request):
264 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400265
Scott Bakerb27b62c2014-08-15 16:29:16 -0700266class TagInline(PlStackGenericTabularInline):
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400267 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400268 extra = 0
269 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500270 fields = ['service', 'name', 'value']
271
272 def queryset(self, request):
273 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400274
Scott Baker74d8e622013-07-29 16:04:22 -0700275class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400276 """ This is a callable that looks up a network name in a sliver and returns
277 the ip address for that network.
278 """
279
Scott Baker434ca7e2014-08-15 12:29:20 -0700280 byNetworkName = {} # class variable
281
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400282 def __init__(self, name):
283 self.short_description = name
284 self.__name__ = name
285 self.network_name = name
286
287 def __call__(self, obj):
288 if obj is not None:
289 for nbs in obj.networksliver_set.all():
290 if (nbs.network.name == self.network_name):
291 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700292 return ""
293
294 def __str__(self):
295 return self.network_name
296
Scott Baker434ca7e2014-08-15 12:29:20 -0700297 @staticmethod
298 def get(network_name):
299 """ We want to make sure we alwars return the same NetworkLookerUpper
300 because sometimes django will cause them to be instantiated multiple
301 times (and we don't want different ones in form.fields vs
302 SliverInline.readonly_fields).
303 """
304 if network_name not in NetworkLookerUpper.byNetworkName:
305 NetworkLookerUpper.byNetworkName[network_name] = NetworkLookerUpper(network_name)
306 return NetworkLookerUpper.byNetworkName[network_name]
307
Siobhan Tullyd3515752013-06-21 16:34:53 -0400308class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400309 model = Sliver
Scott Baker7a61dc42014-09-02 17:08:20 -0700310 fields = ['backend_status_icon', 'all_ips_string', 'instance_name', 'slice', 'deploymentNetwork', 'flavor', 'image', 'node']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400311 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700312 readonly_fields = ['backend_status_icon', 'all_ips_string', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400313 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700314
Tony Mack5b061472014-02-04 07:57:10 -0500315 def queryset(self, request):
316 return Sliver.select_by_user(request.user)
317
Scott Bakerb24cc932014-06-09 10:51:16 -0700318 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
Scott Bakerb24cc932014-06-09 10:51:16 -0700319 if db_field.name == 'deploymentNetwork':
Scott Baker3b678742014-06-09 13:11:54 -0700320 kwargs['queryset'] = Deployment.select_by_acl(request.user)
Scott Baker7a61dc42014-09-02 17:08:20 -0700321 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_deployment_changed(this);"})
Scott Baker32481312014-09-08 12:14:14 -0700322 elif db_field.name == 'flavor':
323 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_flavor_changed(this);"})
Scott Baker3b678742014-06-09 13:11:54 -0700324
325 field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700326
327 return field
328
Siobhan Tullyd3515752013-06-21 16:34:53 -0400329class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400330 model = Site
331 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400332 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400333
Tony Mack5b061472014-02-04 07:57:10 -0500334 def queryset(self, request):
335 return Site.select_by_user(request.user)
336
Siobhan Tullyd3515752013-06-21 16:34:53 -0400337class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400338 model = User
Scott Baker40c00762014-08-21 16:55:59 -0700339 fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
340 readonly_fields = ('backend_status_icon', )
Siobhan Tully30fd4292013-05-10 08:59:56 -0400341 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400342 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400343
Tony Mack5b061472014-02-04 07:57:10 -0500344 def queryset(self, request):
345 return User.select_by_user(request.user)
346
Siobhan Tullyd3515752013-06-21 16:34:53 -0400347class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400348 model = Slice
Scott Baker40c00762014-08-21 16:55:59 -0700349 fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
350 readonly_fields = ('backend_status_icon', )
Tony Mack00d361f2013-04-28 10:28:42 -0400351 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400352 suit_classes = 'suit-tab suit-tab-slices'
353
Tony Mack5b061472014-02-04 07:57:10 -0500354 def queryset(self, request):
355 return Slice.select_by_user(request.user)
356
Siobhan Tullyd3515752013-06-21 16:34:53 -0400357class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400358 model = Node
359 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400360 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker40c00762014-08-21 16:55:59 -0700361 fields = ['backend_status_icon', 'name','deployment','site']
362 readonly_fields = ('backend_status_icon', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400363
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400364class DeploymentPrivilegeInline(PlStackTabularInline):
365 model = DeploymentPrivilege
366 extra = 0
367 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700368 fields = ['backend_status_icon', 'user','role','deployment']
369 readonly_fields = ('backend_status_icon', )
Tony Mack5b061472014-02-04 07:57:10 -0500370
371 def queryset(self, request):
372 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400373
Siobhan Tullyd3515752013-06-21 16:34:53 -0400374class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400375 model = SitePrivilege
376 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400377 suit_classes = 'suit-tab suit-tab-siteprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700378 fields = ['backend_status_icon', 'user','site', 'role']
379 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400380
Tony Mackc2835a92013-05-28 09:18:49 -0400381 def formfield_for_foreignkey(self, db_field, request, **kwargs):
382 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500383 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400384
385 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500386 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400387 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
388
Tony Mack5b061472014-02-04 07:57:10 -0500389 def queryset(self, request):
390 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400391
Tony Macke4be32f2014-03-11 20:45:25 -0400392class SiteDeploymentInline(PlStackTabularInline):
393 model = SiteDeployments
Tony Macke4be32f2014-03-11 20:45:25 -0400394 extra = 0
395 suit_classes = 'suit-tab suit-tab-deployments'
Scott Baker40c00762014-08-21 16:55:59 -0700396 fields = ['backend_status_icon', 'deployment','site']
397 readonly_fields = ('backend_status_icon', )
Tony Macke4be32f2014-03-11 20:45:25 -0400398
399 def formfield_for_foreignkey(self, db_field, request, **kwargs):
400 if db_field.name == 'site':
401 kwargs['queryset'] = Site.select_by_user(request.user)
402
403 if db_field.name == 'deployment':
404 kwargs['queryset'] = Deployment.select_by_user(request.user)
405 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
406
407 def queryset(self, request):
408 return SiteDeployments.select_by_user(request.user)
409
410
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400411class SlicePrivilegeInline(PlStackTabularInline):
412 model = SlicePrivilege
413 suit_classes = 'suit-tab suit-tab-sliceprivileges'
414 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700415 fields = ('backend_status_icon', 'user', 'slice', 'role')
416 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400417
Tony Mackc2835a92013-05-28 09:18:49 -0400418 def formfield_for_foreignkey(self, db_field, request, **kwargs):
419 if db_field.name == 'slice':
Scott Baker36f50872014-08-21 13:01:25 -0700420 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400421 if db_field.name == 'user':
Scott Baker36f50872014-08-21 13:01:25 -0700422 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400423
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400424 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400425
Tony Mack5b061472014-02-04 07:57:10 -0500426 def queryset(self, request):
427 return SlicePrivilege.select_by_user(request.user)
428
Scott Bakera0015eb2013-08-14 17:28:14 -0700429class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700430 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800431 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700432 extra = 0
433 verbose_name = "Network Connection"
434 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400435 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker40c00762014-08-21 16:55:59 -0700436 fields = ['backend_status_icon', 'network']
437 readonly_fields = ('backend_status_icon', )
Scott Baker2170b972014-06-03 12:14:07 -0700438
439class ImageDeploymentsInline(PlStackTabularInline):
440 model = ImageDeployments
441 extra = 0
442 verbose_name = "Image Deployments"
443 verbose_name_plural = "Image Deployments"
444 suit_classes = 'suit-tab suit-tab-imagedeployments'
Scott Baker40c00762014-08-21 16:55:59 -0700445 fields = ['backend_status_icon', 'image', 'deployment', 'glance_image_id']
446 readonly_fields = ['backend_status_icon', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700447
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400448class SliceRoleAdmin(PlanetStackBaseAdmin):
449 model = SliceRole
450 pass
451
452class SiteRoleAdmin(PlanetStackBaseAdmin):
453 model = SiteRole
454 pass
455
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400456class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400457 sites = forms.ModelMultipleChoiceField(
458 queryset=Site.objects.all(),
459 required=False,
Scott Baker70983182014-06-09 22:10:00 -0700460 help_text="Select which sites are allowed to host nodes in this deployment",
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400461 widget=FilteredSelectMultiple(
462 verbose_name=('Sites'), is_stacked=False
463 )
464 )
Scott Bakerde0f4412014-06-11 15:40:26 -0700465 images = forms.ModelMultipleChoiceField(
466 queryset=Image.objects.all(),
467 required=False,
468 help_text="Select which images should be deployed on this deployment",
469 widget=FilteredSelectMultiple(
470 verbose_name=('Images'), is_stacked=False
471 )
472 )
Scott Baker37b47902014-09-02 14:37:41 -0700473 flavors = forms.ModelMultipleChoiceField(
474 queryset=Flavor.objects.all(),
475 required=False,
476 help_text="Select which flavors should be usable on this deployment",
477 widget=FilteredSelectMultiple(
478 verbose_name=('Flavors'), is_stacked=False
479 )
480 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400481 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400482 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700483 many_to_many = ["flavors",]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400484
Siobhan Tully320b4622014-01-17 15:11:14 -0500485 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700486 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500487 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
488
Scott Baker5380c522014-06-06 14:49:43 -0700489 self.fields['accessControl'].initial = "allow site " + request.user.site.name
490
Siobhan Tully320b4622014-01-17 15:11:14 -0500491 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700492 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Scott Bakerde0f4412014-06-11 15:40:26 -0700493 self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
Scott Baker37b47902014-09-02 14:37:41 -0700494 self.fields['flavors'].initial = self.instance.flavors.all()
Scott Bakerde0f4412014-06-11 15:40:26 -0700495
496 def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
497 """ helper function for handling m2m relations from the MultipleChoiceField
498
499 this_obj: the source object we want to link from
500
501 selected_objs: a list of destination objects we want to link to
502
503 all_relations: the full set of relations involving this_obj, including ones we don't want
504
505 relation_class: the class that implements the relation from source to dest
506
507 local_attrname: field name representing this_obj in relation_class
508
509 foreign_attrname: field name representing selected_objs in relation_class
510
511 This function will remove all newobjclass relations from this_obj
512 that are not contained in selected_objs, and add any relations that
513 are in selected_objs but don't exist in the data model yet.
514 """
515
516 existing_dest_objs = []
517 for relation in list(all_relations):
518 if getattr(relation, foreign_attrname) not in selected_objs:
519 #print "deleting site", sdp.site
520 relation.delete()
521 else:
522 existing_dest_objs.append(getattr(relation, foreign_attrname))
523
524 for dest_obj in selected_objs:
525 if dest_obj not in existing_dest_objs:
526 #print "adding site", site
527 kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
528 relation = relation_class(**kwargs)
529 relation.save()
Siobhan Tully320b4622014-01-17 15:11:14 -0500530
531 def save(self, commit=True):
532 deployment = super(DeploymentAdminForm, self).save(commit=False)
533
534 if commit:
535 deployment.save()
Scott Baker61b6aec2014-10-06 17:17:40 -0700536 # this has to be done after save() if/when a deployment is first created
537 deployment.flavors = self.cleaned_data['flavors']
Siobhan Tully320b4622014-01-17 15:11:14 -0500538
539 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700540 # save_m2m() doesn't seem to work with 'through' relations. So we
541 # create/destroy the through models ourselves. There has to be
542 # a better way...
543
Scott Bakerde0f4412014-06-11 15:40:26 -0700544 self.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
545 self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
Scott Bakerc9b14f72014-05-22 13:44:20 -0700546
Scott Baker37b47902014-09-02 14:37:41 -0700547 self.save_m2m()
Siobhan Tully320b4622014-01-17 15:11:14 -0500548
549 return deployment
550
Scott Bakerff5e0f32014-05-22 14:40:27 -0700551class DeploymentAdminROForm(DeploymentAdminForm):
552 def save(self, commit=True):
553 raise PermissionDenied
554
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500555class SiteAssocInline(PlStackTabularInline):
556 model = Site.deployments.through
557 extra = 0
558 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400559
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400560class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500561 model = Deployment
Tony Mack2cbd3802014-09-29 16:10:52 -0400562 fieldList = ['backend_status_text', 'name', 'availability_zone', 'sites', 'images', 'flavors', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500563 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Scott Bakerde0f4412014-06-11 15:40:26 -0700564 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
Scott Baker63d1a552014-08-21 15:19:07 -0700565 list_display = ['backend_status_icon', 'name']
566 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700567 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500568
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500569 user_readonly_fields = ['name']
570
Scott Bakerde0f4412014-06-11 15:40:26 -0700571 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags')) # ,('imagedeployments','Images'))
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500572
Scott Bakerff5e0f32014-05-22 14:40:27 -0700573 def get_form(self, request, obj=None, **kwargs):
574 if request.user.isReadOnlyUser():
575 kwargs["form"] = DeploymentAdminROForm
576 else:
577 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700578 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
579
580 # from stackexchange: pass the request object into the form
581
582 class AdminFormMetaClass(adminForm):
583 def __new__(cls, *args, **kwargs):
584 kwargs['request'] = request
585 return adminForm(*args, **kwargs)
586
587 return AdminFormMetaClass
588
Siobhan Tullyce652d02013-10-08 21:52:35 -0400589class ServiceAttrAsTabInline(PlStackTabularInline):
590 model = ServiceAttribute
591 fields = ['name','value']
592 extra = 0
593 suit_classes = 'suit-tab suit-tab-serviceattrs'
594
Siobhan Tullyce652d02013-10-08 21:52:35 -0400595class ServiceAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700596 list_display = ("backend_status_icon","name","description","versionNumber","enabled","published")
597 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700598 fieldList = ["backend_status_text","name","description","versionNumber","enabled","published"]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500599 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
600 inlines = [ServiceAttrAsTabInline,SliceInline]
Scott Baker40c00762014-08-21 16:55:59 -0700601 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500602
603 user_readonly_fields = fieldList
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500604
605 suit_form_tabs =(('general', 'Service Details'),
606 ('slices','Slices'),
607 ('serviceattrs','Additional Attributes'),
608 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400609
Tony Mack0553f282013-06-10 22:54:50 -0400610class SiteAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700611 fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400612 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500613 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400614 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400615 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400616 suit_form_tabs =(('general', 'Site Details'),
617 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400618 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400619 ('deployments','Deployments'),
620 ('slices','Slices'),
Scott Baker36f50872014-08-21 13:01:25 -0700621 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400622 ('tags','Tags'),
623 )
Scott Baker40c00762014-08-21 16:55:59 -0700624 readonly_fields = ['backend_status_text', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500625
626 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500627
Scott Baker63d1a552014-08-21 15:19:07 -0700628 list_display = ('backend_status_icon', 'name', 'login_base','site_url', 'enabled')
629 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400630 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400631 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400632 search_fields = ['name']
633
Tony Mack04062832013-05-10 08:22:44 -0400634 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500635 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400636
Tony Mack5cd13202013-05-01 21:48:38 -0400637 def get_formsets(self, request, obj=None):
638 for inline in self.get_inline_instances(request, obj):
639 # hide MyInline in the add view
640 if obj is None:
641 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400642 if isinstance(inline, SliceInline):
643 inline.model.caller = request.user
644 yield inline.get_formset(request, obj)
645
646 def get_formsets(self, request, obj=None):
647 for inline in self.get_inline_instances(request, obj):
648 # hide MyInline in the add view
649 if obj is None:
650 continue
651 if isinstance(inline, SliverInline):
652 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400653 yield inline.get_formset(request, obj)
654
Scott Baker545db2a2013-12-09 18:44:43 -0800655 def accountLink(self, obj):
656 link_obj = obj.accounts.all()
657 if link_obj:
658 reverse_path = "admin:core_account_change"
659 url = reverse(reverse_path, args =(link_obj[0].id,))
660 return "<a href='%s'>%s</a>" % (url, "view billing details")
661 else:
662 return "no billing data for this site"
663 accountLink.allow_tags = True
664 accountLink.short_description = "Billing"
665
Tony Mack332ee1d2014-02-04 15:33:45 -0500666 def save_model(self, request, obj, form, change):
667 # update openstack connection to use this site/tenant
668 obj.save_by_user(request.user)
669
670 def delete_model(self, request, obj):
671 obj.delete_by_user(request.user)
672
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500673
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400674class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700675 fieldList = ['backend_status_text', 'user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400676 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500677 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400678 ]
Scott Baker40c00762014-08-21 16:55:59 -0700679 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700680 list_display = ('backend_status_icon', 'user', 'site', 'role')
681 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500682 user_readonly_fields = fieldList
683 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400684
Tony Mackc2835a92013-05-28 09:18:49 -0400685 def formfield_for_foreignkey(self, db_field, request, **kwargs):
686 if db_field.name == 'site':
687 if not request.user.is_admin:
688 # only show sites where user is an admin or pi
689 sites = set()
690 for site_privilege in SitePrivilege.objects.filer(user=request.user):
691 if site_privilege.role.role_type in ['admin', 'pi']:
692 sites.add(site_privilege.site)
693 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
694
695 if db_field.name == 'user':
696 if not request.user.is_admin:
697 # only show users from sites where caller has admin or pi role
698 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
699 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
700 sites = [site_privilege.site for site_privilege in site_privileges]
701 site_privileges = SitePrivilege.objects.filter(site__in=sites)
702 emails = [site_privilege.user.email for site_privilege in site_privileges]
703 users = User.objects.filter(email__in=emails)
704 kwargs['queryset'] = users
705
706 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
707
Tony Mack04062832013-05-10 08:22:44 -0400708 def queryset(self, request):
709 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400710 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400711 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500712 #if not request.user.is_admin:
713 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
714 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
715 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
716 # sites = Site.objects.filter(login_base__in=login_bases)
717 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400718 return qs
719
Siobhan Tullyce652d02013-10-08 21:52:35 -0400720class SliceForm(forms.ModelForm):
721 class Meta:
722 model = Slice
723 widgets = {
Scott Baker36f50872014-08-21 13:01:25 -0700724 'service': LinkedSelect
Siobhan Tullyce652d02013-10-08 21:52:35 -0400725 }
726
Tony Mack2cbd3802014-09-29 16:10:52 -0400727 def clean(self):
728 cleaned_data = super(SliceForm, self).clean()
729 name = cleaned_data.get('name')
Scott Baker6efad462014-10-06 23:09:59 -0700730 site = cleaned_data.get('site')
731 if (not isinstance(site,Site)):
732 # previous code indicates 'site' could be a site_id and not a site?
733 site = Slice.objects.get(id=site.id)
Tony Mack2cbd3802014-09-29 16:10:52 -0400734 if not name.startswith(site.login_base):
735 raise forms.ValidationError('slice name must begin with %s' % site.login_base)
736 return cleaned_data
737
Scott Bakerc4efdc72014-10-15 16:54:04 -0700738class SliceDeploymentsInline(PlStackTabularInline):
739 model = SliceDeployments
740 extra = 0
741 verbose_name = "Slice Deployment"
742 verbose_name_plural = "Slice Deployments"
743 suit_classes = 'suit-tab suit-tab-admin-only'
744 fields = ['backend_status_icon', 'deployment', 'tenant_id']
745 readonly_fields = ('backend_status_icon', )
746
Tony Mack2bd5b412013-06-11 21:05:06 -0400747class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400748 form = SliceForm
Tony Mackfbb26fc2014-09-02 07:03:27 -0400749 fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500750 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Scott Baker40c00762014-08-21 16:55:59 -0700751 readonly_fields = ('backend_status_text', )
Tony Mack7d459902014-09-03 13:18:57 -0400752 list_display = ('backend_status_icon', 'name', 'site','serviceClass', 'slice_url', 'max_slivers')
753 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully2d95e482013-09-06 10:56:06 -0400754 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Scott Bakerc4efdc72014-10-15 16:54:04 -0700755 admin_inlines = [SliceDeploymentsInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400756
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500757 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400758
Scott Bakerc4efdc72014-10-15 16:54:04 -0700759# suit_form_tabs =(('general', 'Slice Details'),
760# ('slicenetworks','Networks'),
761# ('sliceprivileges','Privileges'),
762# ('slivers','Slivers'),
763# ('tags','Tags'),
764# ('reservations','Reservations'),
765# )
766
767 def get_form(self, request, obj=None):
768 # Save obj in thread-local storage, so suit_form_tabs can use it to
769 # determine whether we're in edit or add mode.
770 _thread_locals.request = request
771 _thread_locals.obj = obj
772 return super(SliceAdmin, self).get_form(request, obj)
773
774 @property
775 def suit_form_tabs(self):
776 tabs =[('general', 'Slice Details'),
777 ('slicenetworks','Networks'),
778 ('sliceprivileges','Privileges'),
779 ('slivers','Slivers'),
780 ('tags','Tags'),
781 ('reservations','Reservations'),
782 ]
783
784 request=getattr(_thread_locals, "request", None)
785 if request and request.user.is_admin:
786 tabs.append( ('admin-only', 'Admin-Only') )
787
788 return tabs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400789
Scott Baker510fdbb2014-08-05 17:19:24 -0700790 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
Scott Baker510fdbb2014-08-05 17:19:24 -0700791 deployment_nodes = []
792 for node in Node.objects.all():
793 deployment_nodes.append( (node.deployment.id, node.id, node.name) )
794
Scott Baker7a61dc42014-09-02 17:08:20 -0700795 deployment_flavors = []
796 for flavor in Flavor.objects.all():
797 for deployment in flavor.deployments.all():
798 deployment_flavors.append( (deployment.id, flavor.id, flavor.name) )
799
Scott Baker93e80cd2014-09-09 09:58:49 -0700800 deployment_images = []
801 for image in Image.objects.all():
802 for imageDeployment in image.imagedeployments_set.all():
803 deployment_images.append( (imageDeployment.deployment.id, image.id, image.name) )
804
Tony Mackec23b992014-09-02 21:18:45 -0400805 site_login_bases = []
806 for site in Site.objects.all():
Scott Baker93e80cd2014-09-09 09:58:49 -0700807 site_login_bases.append((site.id, site.login_base))
808
Scott Baker510fdbb2014-08-05 17:19:24 -0700809 context["deployment_nodes"] = deployment_nodes
Scott Baker7a61dc42014-09-02 17:08:20 -0700810 context["deployment_flavors"] = deployment_flavors
Scott Baker93e80cd2014-09-09 09:58:49 -0700811 context["deployment_images"] = deployment_images
Tony Mackec23b992014-09-02 21:18:45 -0400812 context["site_login_bases"] = site_login_bases
Scott Baker510fdbb2014-08-05 17:19:24 -0700813 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
814
Tony Mackc2835a92013-05-28 09:18:49 -0400815 def formfield_for_foreignkey(self, db_field, request, **kwargs):
816 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500817 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackec23b992014-09-02 21:18:45 -0400818 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 -0700819
Tony Mackc2835a92013-05-28 09:18:49 -0400820 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
821
Tony Mack04062832013-05-10 08:22:44 -0400822 def queryset(self, request):
823 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500824 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400825
Tony Mack79748612013-05-01 14:52:03 -0400826 def get_formsets(self, request, obj=None):
827 for inline in self.get_inline_instances(request, obj):
828 # hide MyInline in the add view
829 if obj is None:
830 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400831 if isinstance(inline, SliverInline):
832 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400833 yield inline.get_formset(request, obj)
834
Scott Bakerc4efdc72014-10-15 16:54:04 -0700835 def get_inline_instances(self, request, obj=None):
836 inlines = super(SliceAdmin, self).get_inline_instances(request, obj)
837
838 if request.user.is_admin:
839 for inline_class in self.admin_inlines:
840 inlines.append(inline_class(self.model, self.admin_site))
841
842 return inlines
Tony Mack2bd5b412013-06-11 21:05:06 -0400843
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400844class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400845 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700846 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -0400847 ]
Scott Baker40c00762014-08-21 16:55:59 -0700848 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700849 list_display = ('backend_status_icon', 'user', 'slice', 'role')
850 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -0400851
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500852 user_readonly_fields = ['user', 'slice', 'role']
853 user_readonly_inlines = []
854
Tony Mackc2835a92013-05-28 09:18:49 -0400855 def formfield_for_foreignkey(self, db_field, request, **kwargs):
856 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500857 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400858
859 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500860 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400861
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400862 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400863
Tony Mack04062832013-05-10 08:22:44 -0400864 def queryset(self, request):
865 # admins can see all memberships. Users can only see memberships of
866 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500867 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400868
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400869 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400870 # update openstack connection to use this site/tenant
871 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400872 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400873 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400874 obj.save()
875
876 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400877 # update openstack connection to use this site/tenant
878 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400879 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400880 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400881 obj.delete()
882
Siobhan Tully567e3e62013-06-21 18:03:16 -0400883
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400884class ImageAdmin(PlanetStackBaseAdmin):
885
Scott Baker36f50872014-08-21 13:01:25 -0700886 fieldsets = [('Image Details',
Scott Baker40c00762014-08-21 16:55:59 -0700887 {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400888 'classes': ['suit-tab suit-tab-general']})
889 ]
Scott Baker40c00762014-08-21 16:55:59 -0700890 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400891
Scott Baker2170b972014-06-03 12:14:07 -0700892 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400893
Scott Baker2170b972014-06-03 12:14:07 -0700894 inlines = [SliverInline, ImageDeploymentsInline]
Scott Bakerb6f99242014-06-11 11:34:44 -0700895
Tony Mack32e1ce32014-05-07 13:29:41 -0400896 user_readonly_fields = ['name', 'disk_format', 'container_format']
Scott Bakerb27b62c2014-08-15 16:29:16 -0700897
Scott Baker63d1a552014-08-21 15:19:07 -0700898 list_display = ['backend_status_icon', 'name']
899 list_display_links = ('backend_status_icon', 'name', )
900
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400901class NodeForm(forms.ModelForm):
902 class Meta:
903 widgets = {
904 'site': LinkedSelect,
905 'deployment': LinkedSelect
906 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400907
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500908class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400909 form = NodeForm
Scott Baker63d1a552014-08-21 15:19:07 -0700910 list_display = ('backend_status_icon', 'name', 'site', 'deployment')
911 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400912 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500913
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400914 inlines = [TagInline,SliverInline]
Scott Baker40c00762014-08-21 16:55:59 -0700915 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
916 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400917
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500918 user_readonly_fields = ['name','site','deployment']
919 user_readonly_inlines = [TagInline,SliverInline]
920
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400921 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400922
Siobhan Tully567e3e62013-06-21 18:03:16 -0400923
Tony Mackd90cdbf2013-04-16 22:48:40 -0400924class SliverForm(forms.ModelForm):
925 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400926 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400927 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400928 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400929 widgets = {
930 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400931 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400932 'slice': LinkedSelect,
933 'deploymentNetwork': LinkedSelect,
934 'node': LinkedSelect,
935 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400936 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400937
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500938class TagAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700939 list_display = ['backend_status_icon', 'service', 'name', 'value', 'content_type', 'content_object',]
940 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500941 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
942 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400943
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400944class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400945 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400946 fieldsets = [
Scott Baker7a61dc42014-09-02 17:08:20 -0700947 ('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 -0400948 ]
Scott Baker40c00762014-08-21 16:55:59 -0700949 readonly_fields = ('backend_status_text', )
Scott Baker7a61dc42014-09-02 17:08:20 -0700950 list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deploymentNetwork']
Scott Baker63d1a552014-08-21 15:19:07 -0700951 list_display_links = ('backend_status_icon', 'ip',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400952
953 suit_form_tabs =(('general', 'Sliver Details'),
954 ('tags','Tags'),
955 )
956
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400957 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400958
Scott Baker7a61dc42014-09-02 17:08:20 -0700959 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500960
Tony Mackc2835a92013-05-28 09:18:49 -0400961 def formfield_for_foreignkey(self, db_field, request, **kwargs):
962 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500963 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400964
965 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
966
Tony Mack04062832013-05-10 08:22:44 -0400967 def queryset(self, request):
Scott Baker36f50872014-08-21 13:01:25 -0700968 # admins can see all slivers. Users can only see slivers of
Tony Mack04062832013-05-10 08:22:44 -0400969 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500970 return Sliver.select_by_user(request.user)
971
Tony Mack04062832013-05-10 08:22:44 -0400972
Tony Mack1d6b85f2013-05-07 18:49:14 -0400973 def get_formsets(self, request, obj=None):
974 # make some fields read only if we are updating an existing record
975 if obj == None:
Scott Baker36f50872014-08-21 13:01:25 -0700976 #self.readonly_fields = ('ip', 'instance_name')
Scott Baker40c00762014-08-21 16:55:59 -0700977 self.readonly_fields = ('backend_status_text')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400978 else:
Scott Baker40c00762014-08-21 16:55:59 -0700979 self.readonly_fields = ('backend_status_text')
Scott Baker36f50872014-08-21 13:01:25 -0700980 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400981
982 for inline in self.get_inline_instances(request, obj):
983 # hide MyInline in the add view
984 if obj is None:
985 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700986 if isinstance(inline, SliverInline):
987 inline.model.caller = request.user
988 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400989
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500990 #def save_model(self, request, obj, form, change):
991 # # update openstack connection to use this site/tenant
992 # auth = request.session.get('auth', {})
993 # auth['tenant'] = obj.slice.name
994 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
995 # obj.creator = request.user
996 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400997
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500998 #def delete_model(self, request, obj):
999 # # update openstack connection to use this site/tenant
1000 # auth = request.session.get('auth', {})
1001 # auth['tenant'] = obj.slice.name
1002 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
1003 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -04001004
Siobhan Tully53437282013-04-26 19:30:27 -04001005class UserCreationForm(forms.ModelForm):
1006 """A form for creating new users. Includes all the required
1007 fields, plus a repeated password."""
1008 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
1009 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
1010
1011 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -04001012 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001013 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -04001014
1015 def clean_password2(self):
1016 # Check that the two password entries match
1017 password1 = self.cleaned_data.get("password1")
1018 password2 = self.cleaned_data.get("password2")
1019 if password1 and password2 and password1 != password2:
1020 raise forms.ValidationError("Passwords don't match")
1021 return password2
1022
1023 def save(self, commit=True):
1024 # Save the provided password in hashed format
1025 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -04001026 user.password = self.cleaned_data["password1"]
1027 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -04001028 if commit:
1029 user.save()
1030 return user
1031
Siobhan Tully567e3e62013-06-21 18:03:16 -04001032
Siobhan Tully53437282013-04-26 19:30:27 -04001033class UserChangeForm(forms.ModelForm):
1034 """A form for updating users. Includes all the fields on
1035 the user, but replaces the password field with admin's
1036 password hash display field.
1037 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -05001038 password = ReadOnlyPasswordHashField(label='Password',
1039 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -04001040
1041 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -04001042 model = User
Siobhan Tully53437282013-04-26 19:30:27 -04001043
1044 def clean_password(self):
1045 # Regardless of what the user provides, return the initial value.
1046 # This is done here, rather than on the field, because the
1047 # field does not have access to the initial value
1048 return self.initial["password"]
1049
Scott Baker2c3cb642014-05-19 17:55:56 -07001050class UserDashboardViewInline(PlStackTabularInline):
1051 model = UserDashboardView
1052 extra = 0
1053 suit_classes = 'suit-tab suit-tab-dashboards'
1054 fields = ['user', 'dashboardView', 'order']
1055
Scott Baker86c83ab2014-10-03 13:10:47 -07001056class UserAdmin(PermissionCheckingAdminMixin, UserAdmin):
1057 # Note: Make sure PermissionCheckingAdminMixin is listed before
1058 # admin.ModelAdmin in the class declaration.
1059
Siobhan Tully53437282013-04-26 19:30:27 -04001060 class Meta:
1061 app_label = "core"
1062
1063 # The forms to add and change user instances
1064 form = UserChangeForm
1065 add_form = UserCreationForm
1066
1067 # The fields to be used in displaying the User model.
1068 # These override the definitions on the base UserAdmin
1069 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001070 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001071 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -07001072 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001073
Scott Bakercbfb6002014-10-03 00:32:37 -07001074 fieldListLoginDetails = ['backend_status_text', 'email','site','password','is_active','is_readonly','is_admin','public_key']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001075 fieldListContactInfo = ['firstname','lastname','phone','timezone']
1076
Siobhan Tully53437282013-04-26 19:30:27 -04001077 fieldsets = (
Scott Baker40c00762014-08-21 16:55:59 -07001078 ('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 -04001079 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -07001080 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001081 #('Important dates', {'fields': ('last_login',)}),
1082 )
1083 add_fieldsets = (
1084 (None, {
1085 'classes': ('wide',),
Scott Baker0a5633b2014-10-06 17:51:20 -07001086 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')},
Siobhan Tully53437282013-04-26 19:30:27 -04001087 ),
1088 )
Scott Baker40c00762014-08-21 16:55:59 -07001089 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001090 search_fields = ('email',)
1091 ordering = ('email',)
1092 filter_horizontal = ()
1093
Scott Baker3ca51f62014-05-23 12:05:11 -07001094 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001095
Scott Baker0a5633b2014-10-06 17:51:20 -07001096 def get_form(self, request, obj=None):
1097 # Save obj in thread-local storage, so suit_form_tabs can use it to
1098 # determine whether we're in edit or add mode.
1099 _thread_locals.request = request
1100 _thread_locals.obj = obj
1101 return super(UserAdmin, self).get_form(request, obj)
1102
1103 @property
1104 def suit_form_tabs(self):
1105 if getattr(_thread_locals, "obj", None) is None:
1106 return []
1107 else:
1108 return (('general','Login Details'),
1109 ('contact','Contact Information'),
1110 ('sliceprivileges','Slice Privileges'),
1111 ('siteprivileges','Site Privileges'),
1112 ('deploymentprivileges','Deployment Privileges'),
1113 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001114
Tony Mackc2835a92013-05-28 09:18:49 -04001115 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1116 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001117 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001118
1119 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1120
Tony Mack5b061472014-02-04 07:57:10 -05001121 def queryset(self, request):
1122 return User.select_by_user(request.user)
1123
Scott Baker2c3cb642014-05-19 17:55:56 -07001124class DashboardViewAdmin(PlanetStackBaseAdmin):
1125 fieldsets = [('Dashboard View Details',
Scott Baker40c00762014-08-21 16:55:59 -07001126 {'fields': ['backend_status_text', 'name', 'url'],
Scott Baker2c3cb642014-05-19 17:55:56 -07001127 'classes': ['suit-tab suit-tab-general']})
1128 ]
Scott Baker40c00762014-08-21 16:55:59 -07001129 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001130
Scott Baker2c3cb642014-05-19 17:55:56 -07001131 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001132
Scott Baker0165fac2014-01-13 11:49:26 -08001133class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001134 model = ServiceResource
1135 extra = 0
1136
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001137class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001138 list_display = ('backend_status_icon', 'name', 'commitment', 'membershipFee')
1139 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001140 inlines = [ServiceResourceInline]
1141
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001142 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1143 user_readonly_inlines = []
1144
Scott Baker0165fac2014-01-13 11:49:26 -08001145class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001146 model = ReservedResource
1147 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001148 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001149
1150 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1151 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1152
1153 if db_field.name == 'resource':
1154 # restrict resources to those that the slice's service class allows
1155 if request._slice is not None:
1156 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1157 if len(field.queryset) > 0:
1158 field.initial = field.queryset.all()[0]
1159 else:
1160 field.queryset = field.queryset.none()
1161 elif db_field.name == 'sliver':
1162 # restrict slivers to those that belong to the slice
1163 if request._slice is not None:
1164 field.queryset = field.queryset.filter(slice = request._slice)
1165 else:
1166 field.queryset = field.queryset.none()
1167
1168 return field
1169
Tony Mack5b061472014-02-04 07:57:10 -05001170 def queryset(self, request):
1171 return ReservedResource.select_by_user(request.user)
1172
Scott Baker133c9212013-05-17 09:09:11 -07001173class ReservationChangeForm(forms.ModelForm):
1174 class Meta:
1175 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001176 widgets = {
1177 'slice' : LinkedSelect
1178 }
Scott Baker133c9212013-05-17 09:09:11 -07001179
1180class ReservationAddForm(forms.ModelForm):
1181 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1182 refresh = forms.CharField(widget=forms.HiddenInput())
1183
1184 class Media:
1185 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1186
1187 def clean_slice(self):
1188 slice = self.cleaned_data.get("slice")
1189 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1190 if len(x) == 0:
1191 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1192 return slice
1193
1194 class Meta:
1195 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001196 widgets = {
1197 'slice' : LinkedSelect
1198 }
1199
Scott Baker133c9212013-05-17 09:09:11 -07001200
1201class ReservationAddRefreshForm(ReservationAddForm):
1202 """ This form is displayed when the Reservation Form receives an update
1203 from the Slice dropdown onChange handler. It doesn't validate the
1204 data and doesn't save the data. This will cause the form to be
1205 redrawn.
1206 """
1207
Scott Baker8737e5f2013-05-17 09:35:32 -07001208 """ don't validate anything other than slice """
1209 dont_validate_fields = ("startTime", "duration")
1210
Scott Baker133c9212013-05-17 09:09:11 -07001211 def full_clean(self):
1212 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001213
1214 for fieldname in self.dont_validate_fields:
1215 if fieldname in self._errors:
1216 del self._errors[fieldname]
1217
Scott Baker133c9212013-05-17 09:09:11 -07001218 return result
1219
1220 """ don't save anything """
1221 def is_valid(self):
1222 return False
1223
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001224class ReservationAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001225 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001226 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001227 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001228 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001229 form = ReservationAddForm
1230
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001231 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1232
1233 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001234 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001235
Scott Baker133c9212013-05-17 09:09:11 -07001236 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001237 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001238 request._refresh = False
1239 request._slice = None
1240 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001241 # "refresh" will be set to "1" if the form was submitted due to
1242 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001243 if request.POST.get("refresh","1") == "1":
1244 request._refresh = True
1245 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001246
1247 # Keep track of the slice that was selected, so the
1248 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001249 request._slice = request.POST.get("slice",None)
1250 if (request._slice is not None):
1251 request._slice = Slice.objects.get(id=request._slice)
1252
1253 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1254 return result
1255
Scott Bakeracd45142013-05-19 16:19:16 -07001256 def changelist_view(self, request, extra_context = None):
1257 timezone.activate(request.user.timezone)
1258 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1259
Scott Baker133c9212013-05-17 09:09:11 -07001260 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001261 request._obj_ = obj
1262 if obj is not None:
1263 # For changes, set request._slice to the slice already set in the
1264 # object.
1265 request._slice = obj.slice
1266 self.form = ReservationChangeForm
1267 else:
1268 if getattr(request, "_refresh", False):
1269 self.form = ReservationAddRefreshForm
1270 else:
1271 self.form = ReservationAddForm
1272 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1273
Scott Baker133c9212013-05-17 09:09:11 -07001274 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001275 if (obj is not None):
1276 # Prevent slice from being changed after the reservation has been
1277 # created.
1278 return ['slice']
1279 else:
Scott Baker133c9212013-05-17 09:09:11 -07001280 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001281
Tony Mack5b061472014-02-04 07:57:10 -05001282 def queryset(self, request):
1283 return Reservation.select_by_user(request.user)
1284
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001285class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001286 list_display = ("backend_status_icon", "name", )
1287 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001288 user_readonly_fields = ['name']
1289 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001290
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001291class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001292 list_display = ("backend_status_icon", "name", )
1293 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001294 user_readonly_fields = ['name']
1295 user_readonly_inlines = []
1296
Scott Baker0165fac2014-01-13 11:49:26 -08001297class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001298 model = Router.networks.through
1299 extra = 0
1300 verbose_name_plural = "Routers"
1301 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001302 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001303
Scott Bakerb27b62c2014-08-15 16:29:16 -07001304class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001305 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07001306 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001307 verbose_name_plural = "Parameters"
1308 verbose_name = "Parameter"
1309 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07001310 fields = ['backend_status_icon', 'parameter', 'value']
1311 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001312
Scott Baker0165fac2014-01-13 11:49:26 -08001313class NetworkSliversInline(PlStackTabularInline):
Scott Baker40c00762014-08-21 16:55:59 -07001314 fields = ['backend_status_icon', 'network','sliver','ip']
1315 readonly_fields = ("backend_status_icon", "ip", )
Scott Baker74d8e622013-07-29 16:04:22 -07001316 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001317 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001318 extra = 0
1319 verbose_name_plural = "Slivers"
1320 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001321 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001322
Scott Baker0165fac2014-01-13 11:49:26 -08001323class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001324 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001325 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001326 extra = 0
1327 verbose_name_plural = "Slices"
1328 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001329 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Baker40c00762014-08-21 16:55:59 -07001330 fields = ['backend_status_icon', 'network','slice']
1331 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07001332
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001333class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001334 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
1335 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07001336 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001337
Scott Bakerd7d2a392013-08-06 08:57:30 -07001338 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001339
Siobhan Tully2d95e482013-09-06 10:56:06 -04001340 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001341 (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 -05001342
Scott Baker40c00762014-08-21 16:55:59 -07001343 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001344 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 -04001345
1346 suit_form_tabs =(
1347 ('general','Network Details'),
1348 ('netparams', 'Parameters'),
1349 ('networkslivers','Slivers'),
1350 ('networkslices','Slices'),
1351 ('routers','Routers'),
1352 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001353class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001354 list_display = ("backend_status_icon", "name", "guaranteedBandwidth", "visibility")
1355 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001356 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1357 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001358
Scott Baker37b47902014-09-02 14:37:41 -07001359class FlavorAdmin(PlanetStackBaseAdmin):
1360 list_display = ("backend_status_icon", "name", "flavor", "order", "default")
1361 list_display_links = ("backend_status_icon", "name")
1362 user_readonly_fields = ("name", "flavor")
1363 fields = ("name", "description", "flavor", "order", "default")
1364
Tony Mack31c2b8f2013-04-26 20:01:42 -04001365# register a signal that caches the user's credentials when they log in
1366def cache_credentials(sender, user, request, **kwds):
1367 auth = {'username': request.POST['username'],
1368 'password': request.POST['password']}
1369 request.session['auth'] = auth
1370user_logged_in.connect(cache_credentials)
1371
Scott Baker15cddfa2013-12-09 13:45:19 -08001372def dollar_field(fieldName, short_description):
1373 def newFunc(self, obj):
1374 try:
1375 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1376 except:
1377 x=getattr(obj, fieldName, 0.0)
1378 return x
1379 newFunc.short_description = short_description
1380 return newFunc
1381
1382def right_dollar_field(fieldName, short_description):
1383 def newFunc(self, obj):
1384 try:
1385 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1386 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1387 except:
1388 x=getattr(obj, fieldName, 0.0)
1389 return x
1390 newFunc.short_description = short_description
1391 newFunc.allow_tags = True
1392 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001393
Scott Baker0165fac2014-01-13 11:49:26 -08001394class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001395 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001396 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001397 verbose_name_plural = "Charges"
1398 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001399 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001400 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1401 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1402 can_delete = False
1403 max_num = 0
1404
1405 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001406
1407class InvoiceAdmin(admin.ModelAdmin):
1408 list_display = ("date", "account")
1409
1410 inlines = [InvoiceChargeInline]
1411
Scott Baker9cb88a22013-12-09 18:56:00 -08001412 fields = ["date", "account", "dollar_amount"]
1413 readonly_fields = ["date", "account", "dollar_amount"]
1414
1415 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001416
Scott Baker0165fac2014-01-13 11:49:26 -08001417class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001418 model = Invoice
1419 extra = 0
1420 verbose_name_plural = "Invoices"
1421 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001422 fields = ["date", "dollar_amount"]
1423 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001424 suit_classes = 'suit-tab suit-tab-accountinvoice'
1425 can_delete=False
1426 max_num=0
1427
1428 dollar_amount = right_dollar_field("amount", "Amount")
1429
Scott Baker0165fac2014-01-13 11:49:26 -08001430class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001431 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001432 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001433 verbose_name_plural = "Charges"
1434 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001435 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001436 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1437 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001438 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001439 can_delete=False
1440 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001441
1442 def queryset(self, request):
1443 qs = super(PendingChargeInline, self).queryset(request)
1444 qs = qs.filter(state="pending")
1445 return qs
1446
Scott Baker15cddfa2013-12-09 13:45:19 -08001447 dollar_amount = right_dollar_field("amount", "Amount")
1448
Scott Baker0165fac2014-01-13 11:49:26 -08001449class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001450 model=Payment
1451 extra = 1
1452 verbose_name_plural = "Payments"
1453 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001454 fields = ["date", "dollar_amount"]
1455 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001456 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001457 can_delete=False
1458 max_num=0
1459
1460 dollar_amount = right_dollar_field("amount", "Amount")
1461
Scott Baker43105042013-12-06 23:23:36 -08001462class AccountAdmin(admin.ModelAdmin):
1463 list_display = ("site", "balance_due")
1464
1465 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1466
1467 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001468 (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 -08001469
Scott Baker15cddfa2013-12-09 13:45:19 -08001470 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001471
1472 suit_form_tabs =(
1473 ('general','Account Details'),
1474 ('accountinvoice', 'Invoices'),
1475 ('accountpayments', 'Payments'),
1476 ('accountpendingcharges','Pending Charges'),
1477 )
1478
Scott Baker15cddfa2013-12-09 13:45:19 -08001479 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1480 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1481 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1482
Siobhan Tully53437282013-04-26 19:30:27 -04001483# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001484admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001485# ... and, since we're not using Django's builtin permissions,
1486# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001487#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001488
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001489#Do not show django evolution in the admin interface
1490from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001491#admin.site.unregister(Version)
1492#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001493
1494
1495# When debugging it is often easier to see all the classes, but for regular use
1496# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001497showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001498
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001499admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001500admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001501admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001502admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001503admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001504admin.site.register(Network, NetworkAdmin)
1505admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001506admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001507admin.site.register(Account, AccountAdmin)
1508admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001509
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001510if True:
1511 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1512 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001513 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001514 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001515 admin.site.register(DeploymentRole)
1516 admin.site.register(SiteRole)
1517 admin.site.register(SliceRole)
1518 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001519 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001520 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1521 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001522 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001523 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001524 admin.site.register(DashboardView, DashboardViewAdmin)
Scott Baker37b47902014-09-02 14:37:41 -07001525 admin.site.register(Flavor, FlavorAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001526