blob: e9b7737839011780ab6c200396f3e9747ca2000f [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 Baker5c432692014-10-16 00:57:55 -0700140 def get_form(self, request, obj=None):
141 # Save obj and request in thread-local storage, so suit_form_tabs can
142 # use it to determine whether we're in edit or add mode, and can
143 # determine whether the user is an admin.
144 _thread_locals.request = request
145 _thread_locals.obj = obj
146 return super(PermissionCheckingAdminMixin, self).get_form(request, obj)
147
148 def get_inline_instances(self, request, obj=None):
149 inlines = super(PermissionCheckingAdminMixin, self).get_inline_instances(request, obj)
150
151 # inlines that should only be shown to an admin user
152 if request.user.is_admin:
153 for inline_class in getattr(self, "admin_inlines", []):
154 inlines.append(inline_class(self.model, self.admin_site))
155
156 return inlines
157
Scott Baker86c83ab2014-10-03 13:10:47 -0700158class ReadOnlyAwareAdmin(PermissionCheckingAdminMixin, admin.ModelAdmin):
159 # Note: Make sure PermissionCheckingAdminMixin is listed before
160 # admin.ModelAdmin in the class declaration.
161
Scott Bakercbfb6002014-10-03 00:32:37 -0700162 pass
163
164class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
165 save_on_top = False
Scott Baker36f50872014-08-21 13:01:25 -0700166
Scott Bakere8859f92014-05-23 12:42:40 -0700167class SingletonAdmin (ReadOnlyAwareAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400168 def has_add_permission(self, request):
Scott Bakere8859f92014-05-23 12:42:40 -0700169 if not super(SingletonAdmin, self).has_add_permission(request):
170 return False
171
Siobhan Tullyce652d02013-10-08 21:52:35 -0400172 num_objects = self.model.objects.count()
173 if num_objects >= 1:
174 return False
175 else:
176 return True
177
Siobhan Tullyd3515752013-06-21 16:34:53 -0400178class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -0800179 def __init__(self, *args, **kwargs):
180 super(PlStackTabularInline, self).__init__(*args, **kwargs)
181
182 # InlineModelAdmin as no get_fields() method, so in order to add
183 # the selflink field, we override __init__ to modify self.fields and
184 # self.readonly_fields.
185
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800186 self.setup_selflink()
187
Scott Baker874936e2014-01-13 18:15:34 -0800188 def get_change_url(self, model, id):
189 """ Get the URL to a change form in the admin for this model """
190 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800191 try:
Scott Baker874936e2014-01-13 18:15:34 -0800192 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800193 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -0800194 return None
195
196 return url
197
198 def setup_selflink(self):
199 if hasattr(self, "selflink_fieldname"):
200 """ self.selflink_model can be defined to punch through a relation
201 to its target object. For example, in SliceNetworkInline, set
202 selflink_model = "network", and the URL will lead to the Network
203 object instead of trying to bring up a change view of the
204 SliceNetwork object.
205 """
206 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
207 else:
208 self.selflink_model = self.model
209
210 url = self.get_change_url(self.selflink_model, 0)
211
212 # We don't have an admin for this object, so don't create the
213 # selflink.
214 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800215 return
216
Scott Baker874936e2014-01-13 18:15:34 -0800217 # Since we need to add "selflink" to the field list, we need to create
218 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800219 if (self.fields is None):
220 self.fields = []
221 for f in self.model._meta.fields:
222 if f.editable and f.name != "id":
223 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800224
Scott Baker874936e2014-01-13 18:15:34 -0800225 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800226
Scott Baker874936e2014-01-13 18:15:34 -0800227 if self.readonly_fields is None:
228 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800229
Scott Baker874936e2014-01-13 18:15:34 -0800230 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800231
232 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800233 if hasattr(self, "selflink_fieldname"):
234 obj = getattr(obj, self.selflink_fieldname)
235
Scott Baker86568322014-01-12 16:53:31 -0800236 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800237 url = self.get_change_url(self.selflink_model, obj.id)
238 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800239 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800240 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800241
242 selflink.allow_tags = True
243 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400244
Scott Bakerb27b62c2014-08-15 16:29:16 -0700245 def has_add_permission(self, request):
246 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500247
248 def get_readonly_fields(self, request, obj=None):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700249 readonly_fields = list(self.readonly_fields)[:]
250 if request.user.isReadOnlyUser():
251 for field in self.fields:
252 if not field in readonly_fields:
253 readonly_fields.append(field)
254 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500255
Scott Baker40c00762014-08-21 16:55:59 -0700256 def backend_status_icon(self, obj):
257 return mark_safe(backend_icon(obj))
258 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -0700259
Scott Bakerb27b62c2014-08-15 16:29:16 -0700260class PlStackGenericTabularInline(generic.GenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500261 def has_add_permission(self, request):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700262 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500263
Scott Bakerb27b62c2014-08-15 16:29:16 -0700264 def get_readonly_fields(self, request, obj=None):
265 readonly_fields = list(self.readonly_fields)[:]
266 if request.user.isReadOnlyUser():
267 for field in self.fields:
268 if not field in readonly_fields:
269 readonly_fields.append(field)
270 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500271
Scott Baker40c00762014-08-21 16:55:59 -0700272 def backend_status_icon(self, obj):
273 return mark_safe(backend_icon(obj))
274 backend_status_icon.short_description = ""
275
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400276class ReservationInline(PlStackTabularInline):
277 model = Reservation
278 extra = 0
279 suit_classes = 'suit-tab suit-tab-reservations'
Scott Baker36f50872014-08-21 13:01:25 -0700280
Tony Mack5b061472014-02-04 07:57:10 -0500281 def queryset(self, request):
282 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400283
Scott Bakerb27b62c2014-08-15 16:29:16 -0700284class TagInline(PlStackGenericTabularInline):
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400285 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400286 extra = 0
287 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500288 fields = ['service', 'name', 'value']
289
290 def queryset(self, request):
291 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400292
Scott Baker74d8e622013-07-29 16:04:22 -0700293class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400294 """ This is a callable that looks up a network name in a sliver and returns
295 the ip address for that network.
296 """
297
Scott Baker434ca7e2014-08-15 12:29:20 -0700298 byNetworkName = {} # class variable
299
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400300 def __init__(self, name):
301 self.short_description = name
302 self.__name__ = name
303 self.network_name = name
304
305 def __call__(self, obj):
306 if obj is not None:
307 for nbs in obj.networksliver_set.all():
308 if (nbs.network.name == self.network_name):
309 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700310 return ""
311
312 def __str__(self):
313 return self.network_name
314
Scott Baker434ca7e2014-08-15 12:29:20 -0700315 @staticmethod
316 def get(network_name):
317 """ We want to make sure we alwars return the same NetworkLookerUpper
318 because sometimes django will cause them to be instantiated multiple
319 times (and we don't want different ones in form.fields vs
320 SliverInline.readonly_fields).
321 """
322 if network_name not in NetworkLookerUpper.byNetworkName:
323 NetworkLookerUpper.byNetworkName[network_name] = NetworkLookerUpper(network_name)
324 return NetworkLookerUpper.byNetworkName[network_name]
325
Siobhan Tullyd3515752013-06-21 16:34:53 -0400326class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400327 model = Sliver
Scott Baker7a61dc42014-09-02 17:08:20 -0700328 fields = ['backend_status_icon', 'all_ips_string', 'instance_name', 'slice', 'deploymentNetwork', 'flavor', 'image', 'node']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400329 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700330 readonly_fields = ['backend_status_icon', 'all_ips_string', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400331 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700332
Tony Mack5b061472014-02-04 07:57:10 -0500333 def queryset(self, request):
334 return Sliver.select_by_user(request.user)
335
Scott Bakerb24cc932014-06-09 10:51:16 -0700336 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
Scott Bakerb24cc932014-06-09 10:51:16 -0700337 if db_field.name == 'deploymentNetwork':
Scott Baker3b678742014-06-09 13:11:54 -0700338 kwargs['queryset'] = Deployment.select_by_acl(request.user)
Scott Baker7a61dc42014-09-02 17:08:20 -0700339 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_deployment_changed(this);"})
Scott Baker32481312014-09-08 12:14:14 -0700340 elif db_field.name == 'flavor':
341 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_flavor_changed(this);"})
Scott Baker3b678742014-06-09 13:11:54 -0700342
343 field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700344
345 return field
346
Siobhan Tullyd3515752013-06-21 16:34:53 -0400347class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400348 model = Site
349 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400350 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400351
Tony Mack5b061472014-02-04 07:57:10 -0500352 def queryset(self, request):
353 return Site.select_by_user(request.user)
354
Siobhan Tullyd3515752013-06-21 16:34:53 -0400355class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400356 model = User
Scott Baker40c00762014-08-21 16:55:59 -0700357 fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
358 readonly_fields = ('backend_status_icon', )
Siobhan Tully30fd4292013-05-10 08:59:56 -0400359 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400360 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400361
Tony Mack5b061472014-02-04 07:57:10 -0500362 def queryset(self, request):
363 return User.select_by_user(request.user)
364
Siobhan Tullyd3515752013-06-21 16:34:53 -0400365class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400366 model = Slice
Scott Baker40c00762014-08-21 16:55:59 -0700367 fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
368 readonly_fields = ('backend_status_icon', )
Tony Mack00d361f2013-04-28 10:28:42 -0400369 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400370 suit_classes = 'suit-tab suit-tab-slices'
371
Tony Mack5b061472014-02-04 07:57:10 -0500372 def queryset(self, request):
373 return Slice.select_by_user(request.user)
374
Siobhan Tullyd3515752013-06-21 16:34:53 -0400375class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400376 model = Node
377 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400378 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker40c00762014-08-21 16:55:59 -0700379 fields = ['backend_status_icon', 'name','deployment','site']
380 readonly_fields = ('backend_status_icon', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400381
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400382class DeploymentPrivilegeInline(PlStackTabularInline):
383 model = DeploymentPrivilege
384 extra = 0
385 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700386 fields = ['backend_status_icon', 'user','role','deployment']
387 readonly_fields = ('backend_status_icon', )
Tony Mack5b061472014-02-04 07:57:10 -0500388
389 def queryset(self, request):
390 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400391
Siobhan Tullyd3515752013-06-21 16:34:53 -0400392class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400393 model = SitePrivilege
394 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400395 suit_classes = 'suit-tab suit-tab-siteprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700396 fields = ['backend_status_icon', 'user','site', 'role']
397 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400398
Tony Mackc2835a92013-05-28 09:18:49 -0400399 def formfield_for_foreignkey(self, db_field, request, **kwargs):
400 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500401 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400402
403 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500404 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400405 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
406
Tony Mack5b061472014-02-04 07:57:10 -0500407 def queryset(self, request):
408 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400409
Tony Macke4be32f2014-03-11 20:45:25 -0400410class SiteDeploymentInline(PlStackTabularInline):
411 model = SiteDeployments
Tony Macke4be32f2014-03-11 20:45:25 -0400412 extra = 0
413 suit_classes = 'suit-tab suit-tab-deployments'
Scott Baker40c00762014-08-21 16:55:59 -0700414 fields = ['backend_status_icon', 'deployment','site']
415 readonly_fields = ('backend_status_icon', )
Tony Macke4be32f2014-03-11 20:45:25 -0400416
417 def formfield_for_foreignkey(self, db_field, request, **kwargs):
418 if db_field.name == 'site':
419 kwargs['queryset'] = Site.select_by_user(request.user)
420
421 if db_field.name == 'deployment':
422 kwargs['queryset'] = Deployment.select_by_user(request.user)
423 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
424
425 def queryset(self, request):
426 return SiteDeployments.select_by_user(request.user)
427
428
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400429class SlicePrivilegeInline(PlStackTabularInline):
430 model = SlicePrivilege
431 suit_classes = 'suit-tab suit-tab-sliceprivileges'
432 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700433 fields = ('backend_status_icon', 'user', 'slice', 'role')
434 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400435
Tony Mackc2835a92013-05-28 09:18:49 -0400436 def formfield_for_foreignkey(self, db_field, request, **kwargs):
437 if db_field.name == 'slice':
Scott Baker36f50872014-08-21 13:01:25 -0700438 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400439 if db_field.name == 'user':
Scott Baker36f50872014-08-21 13:01:25 -0700440 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400441
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400442 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400443
Tony Mack5b061472014-02-04 07:57:10 -0500444 def queryset(self, request):
445 return SlicePrivilege.select_by_user(request.user)
446
Scott Bakera0015eb2013-08-14 17:28:14 -0700447class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700448 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800449 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700450 extra = 0
451 verbose_name = "Network Connection"
452 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400453 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker40c00762014-08-21 16:55:59 -0700454 fields = ['backend_status_icon', 'network']
455 readonly_fields = ('backend_status_icon', )
Scott Baker2170b972014-06-03 12:14:07 -0700456
457class ImageDeploymentsInline(PlStackTabularInline):
458 model = ImageDeployments
459 extra = 0
460 verbose_name = "Image Deployments"
461 verbose_name_plural = "Image Deployments"
462 suit_classes = 'suit-tab suit-tab-imagedeployments'
Scott Baker40c00762014-08-21 16:55:59 -0700463 fields = ['backend_status_icon', 'image', 'deployment', 'glance_image_id']
464 readonly_fields = ['backend_status_icon', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700465
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400466class SliceRoleAdmin(PlanetStackBaseAdmin):
467 model = SliceRole
468 pass
469
470class SiteRoleAdmin(PlanetStackBaseAdmin):
471 model = SiteRole
472 pass
473
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400474class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400475 sites = forms.ModelMultipleChoiceField(
476 queryset=Site.objects.all(),
477 required=False,
Scott Baker70983182014-06-09 22:10:00 -0700478 help_text="Select which sites are allowed to host nodes in this deployment",
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400479 widget=FilteredSelectMultiple(
480 verbose_name=('Sites'), is_stacked=False
481 )
482 )
Scott Bakerde0f4412014-06-11 15:40:26 -0700483 images = forms.ModelMultipleChoiceField(
484 queryset=Image.objects.all(),
485 required=False,
486 help_text="Select which images should be deployed on this deployment",
487 widget=FilteredSelectMultiple(
488 verbose_name=('Images'), is_stacked=False
489 )
490 )
Scott Baker37b47902014-09-02 14:37:41 -0700491 flavors = forms.ModelMultipleChoiceField(
492 queryset=Flavor.objects.all(),
493 required=False,
494 help_text="Select which flavors should be usable on this deployment",
495 widget=FilteredSelectMultiple(
496 verbose_name=('Flavors'), is_stacked=False
497 )
498 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400499 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400500 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700501 many_to_many = ["flavors",]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400502
Siobhan Tully320b4622014-01-17 15:11:14 -0500503 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700504 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500505 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
506
Scott Baker5380c522014-06-06 14:49:43 -0700507 self.fields['accessControl'].initial = "allow site " + request.user.site.name
508
Siobhan Tully320b4622014-01-17 15:11:14 -0500509 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700510 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Scott Bakerde0f4412014-06-11 15:40:26 -0700511 self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
Scott Baker37b47902014-09-02 14:37:41 -0700512 self.fields['flavors'].initial = self.instance.flavors.all()
Scott Bakerde0f4412014-06-11 15:40:26 -0700513
514 def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
515 """ helper function for handling m2m relations from the MultipleChoiceField
516
517 this_obj: the source object we want to link from
518
519 selected_objs: a list of destination objects we want to link to
520
521 all_relations: the full set of relations involving this_obj, including ones we don't want
522
523 relation_class: the class that implements the relation from source to dest
524
525 local_attrname: field name representing this_obj in relation_class
526
527 foreign_attrname: field name representing selected_objs in relation_class
528
529 This function will remove all newobjclass relations from this_obj
530 that are not contained in selected_objs, and add any relations that
531 are in selected_objs but don't exist in the data model yet.
532 """
533
534 existing_dest_objs = []
535 for relation in list(all_relations):
536 if getattr(relation, foreign_attrname) not in selected_objs:
537 #print "deleting site", sdp.site
538 relation.delete()
539 else:
540 existing_dest_objs.append(getattr(relation, foreign_attrname))
541
542 for dest_obj in selected_objs:
543 if dest_obj not in existing_dest_objs:
544 #print "adding site", site
545 kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
546 relation = relation_class(**kwargs)
547 relation.save()
Siobhan Tully320b4622014-01-17 15:11:14 -0500548
549 def save(self, commit=True):
550 deployment = super(DeploymentAdminForm, self).save(commit=False)
551
552 if commit:
553 deployment.save()
Scott Baker61b6aec2014-10-06 17:17:40 -0700554 # this has to be done after save() if/when a deployment is first created
555 deployment.flavors = self.cleaned_data['flavors']
Siobhan Tully320b4622014-01-17 15:11:14 -0500556
557 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700558 # save_m2m() doesn't seem to work with 'through' relations. So we
559 # create/destroy the through models ourselves. There has to be
560 # a better way...
561
Scott Bakerde0f4412014-06-11 15:40:26 -0700562 self.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
563 self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
Scott Bakerc9b14f72014-05-22 13:44:20 -0700564
Scott Baker37b47902014-09-02 14:37:41 -0700565 self.save_m2m()
Siobhan Tully320b4622014-01-17 15:11:14 -0500566
567 return deployment
568
Scott Bakerff5e0f32014-05-22 14:40:27 -0700569class DeploymentAdminROForm(DeploymentAdminForm):
570 def save(self, commit=True):
571 raise PermissionDenied
572
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500573class SiteAssocInline(PlStackTabularInline):
574 model = Site.deployments.through
575 extra = 0
576 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400577
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400578class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500579 model = Deployment
Tony Mack2cbd3802014-09-29 16:10:52 -0400580 fieldList = ['backend_status_text', 'name', 'availability_zone', 'sites', 'images', 'flavors', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500581 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Scott Bakerde0f4412014-06-11 15:40:26 -0700582 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
Scott Baker63d1a552014-08-21 15:19:07 -0700583 list_display = ['backend_status_icon', 'name']
584 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700585 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500586
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500587 user_readonly_fields = ['name']
588
Scott Bakerde0f4412014-06-11 15:40:26 -0700589 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags')) # ,('imagedeployments','Images'))
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500590
Scott Bakerff5e0f32014-05-22 14:40:27 -0700591 def get_form(self, request, obj=None, **kwargs):
592 if request.user.isReadOnlyUser():
593 kwargs["form"] = DeploymentAdminROForm
594 else:
595 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700596 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
597
598 # from stackexchange: pass the request object into the form
599
600 class AdminFormMetaClass(adminForm):
601 def __new__(cls, *args, **kwargs):
602 kwargs['request'] = request
603 return adminForm(*args, **kwargs)
604
605 return AdminFormMetaClass
606
Siobhan Tullyce652d02013-10-08 21:52:35 -0400607class ServiceAttrAsTabInline(PlStackTabularInline):
608 model = ServiceAttribute
609 fields = ['name','value']
610 extra = 0
611 suit_classes = 'suit-tab suit-tab-serviceattrs'
612
Siobhan Tullyce652d02013-10-08 21:52:35 -0400613class ServiceAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700614 list_display = ("backend_status_icon","name","description","versionNumber","enabled","published")
615 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700616 fieldList = ["backend_status_text","name","description","versionNumber","enabled","published"]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500617 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
618 inlines = [ServiceAttrAsTabInline,SliceInline]
Scott Baker40c00762014-08-21 16:55:59 -0700619 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500620
621 user_readonly_fields = fieldList
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500622
623 suit_form_tabs =(('general', 'Service Details'),
624 ('slices','Slices'),
625 ('serviceattrs','Additional Attributes'),
626 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400627
Tony Mack0553f282013-06-10 22:54:50 -0400628class SiteAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700629 fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400630 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500631 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400632 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400633 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400634 suit_form_tabs =(('general', 'Site Details'),
635 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400636 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400637 ('deployments','Deployments'),
638 ('slices','Slices'),
Scott Baker36f50872014-08-21 13:01:25 -0700639 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400640 ('tags','Tags'),
641 )
Scott Baker40c00762014-08-21 16:55:59 -0700642 readonly_fields = ['backend_status_text', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500643
644 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500645
Scott Baker63d1a552014-08-21 15:19:07 -0700646 list_display = ('backend_status_icon', 'name', 'login_base','site_url', 'enabled')
647 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400648 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400649 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400650 search_fields = ['name']
651
Tony Mack04062832013-05-10 08:22:44 -0400652 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500653 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400654
Tony Mack5cd13202013-05-01 21:48:38 -0400655 def get_formsets(self, request, obj=None):
656 for inline in self.get_inline_instances(request, obj):
657 # hide MyInline in the add view
658 if obj is None:
659 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400660 if isinstance(inline, SliverInline):
661 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400662 yield inline.get_formset(request, obj)
663
Scott Baker545db2a2013-12-09 18:44:43 -0800664 def accountLink(self, obj):
665 link_obj = obj.accounts.all()
666 if link_obj:
667 reverse_path = "admin:core_account_change"
668 url = reverse(reverse_path, args =(link_obj[0].id,))
669 return "<a href='%s'>%s</a>" % (url, "view billing details")
670 else:
671 return "no billing data for this site"
672 accountLink.allow_tags = True
673 accountLink.short_description = "Billing"
674
Tony Mack332ee1d2014-02-04 15:33:45 -0500675 def save_model(self, request, obj, form, change):
676 # update openstack connection to use this site/tenant
677 obj.save_by_user(request.user)
678
679 def delete_model(self, request, obj):
680 obj.delete_by_user(request.user)
681
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500682
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400683class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700684 fieldList = ['backend_status_text', 'user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400685 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500686 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400687 ]
Scott Baker40c00762014-08-21 16:55:59 -0700688 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700689 list_display = ('backend_status_icon', 'user', 'site', 'role')
690 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500691 user_readonly_fields = fieldList
692 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400693
Tony Mackc2835a92013-05-28 09:18:49 -0400694 def formfield_for_foreignkey(self, db_field, request, **kwargs):
695 if db_field.name == 'site':
696 if not request.user.is_admin:
697 # only show sites where user is an admin or pi
698 sites = set()
699 for site_privilege in SitePrivilege.objects.filer(user=request.user):
700 if site_privilege.role.role_type in ['admin', 'pi']:
701 sites.add(site_privilege.site)
702 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
703
704 if db_field.name == 'user':
705 if not request.user.is_admin:
706 # only show users from sites where caller has admin or pi role
707 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
708 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
709 sites = [site_privilege.site for site_privilege in site_privileges]
710 site_privileges = SitePrivilege.objects.filter(site__in=sites)
711 emails = [site_privilege.user.email for site_privilege in site_privileges]
712 users = User.objects.filter(email__in=emails)
713 kwargs['queryset'] = users
714
715 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
716
Tony Mack04062832013-05-10 08:22:44 -0400717 def queryset(self, request):
718 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400719 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400720 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500721 #if not request.user.is_admin:
722 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
723 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
724 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
725 # sites = Site.objects.filter(login_base__in=login_bases)
726 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400727 return qs
728
Siobhan Tullyce652d02013-10-08 21:52:35 -0400729class SliceForm(forms.ModelForm):
730 class Meta:
731 model = Slice
732 widgets = {
Scott Baker36f50872014-08-21 13:01:25 -0700733 'service': LinkedSelect
Siobhan Tullyce652d02013-10-08 21:52:35 -0400734 }
735
Tony Mack2cbd3802014-09-29 16:10:52 -0400736 def clean(self):
737 cleaned_data = super(SliceForm, self).clean()
738 name = cleaned_data.get('name')
Scott Baker6efad462014-10-06 23:09:59 -0700739 site = cleaned_data.get('site')
740 if (not isinstance(site,Site)):
741 # previous code indicates 'site' could be a site_id and not a site?
742 site = Slice.objects.get(id=site.id)
Tony Mack2cbd3802014-09-29 16:10:52 -0400743 if not name.startswith(site.login_base):
744 raise forms.ValidationError('slice name must begin with %s' % site.login_base)
745 return cleaned_data
746
Scott Bakerc4efdc72014-10-15 16:54:04 -0700747class SliceDeploymentsInline(PlStackTabularInline):
748 model = SliceDeployments
749 extra = 0
750 verbose_name = "Slice Deployment"
751 verbose_name_plural = "Slice Deployments"
752 suit_classes = 'suit-tab suit-tab-admin-only'
753 fields = ['backend_status_icon', 'deployment', 'tenant_id']
754 readonly_fields = ('backend_status_icon', )
755
Tony Mack2bd5b412013-06-11 21:05:06 -0400756class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400757 form = SliceForm
Tony Mackfbb26fc2014-09-02 07:03:27 -0400758 fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500759 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Scott Baker40c00762014-08-21 16:55:59 -0700760 readonly_fields = ('backend_status_text', )
Tony Mack7d459902014-09-03 13:18:57 -0400761 list_display = ('backend_status_icon', 'name', 'site','serviceClass', 'slice_url', 'max_slivers')
762 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully2d95e482013-09-06 10:56:06 -0400763 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Scott Bakerc4efdc72014-10-15 16:54:04 -0700764 admin_inlines = [SliceDeploymentsInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400765
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500766 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400767
Scott Bakerc4efdc72014-10-15 16:54:04 -0700768 @property
769 def suit_form_tabs(self):
770 tabs =[('general', 'Slice Details'),
771 ('slicenetworks','Networks'),
772 ('sliceprivileges','Privileges'),
773 ('slivers','Slivers'),
774 ('tags','Tags'),
775 ('reservations','Reservations'),
776 ]
777
778 request=getattr(_thread_locals, "request", None)
779 if request and request.user.is_admin:
780 tabs.append( ('admin-only', 'Admin-Only') )
781
782 return tabs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400783
Scott Baker510fdbb2014-08-05 17:19:24 -0700784 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
Scott Baker510fdbb2014-08-05 17:19:24 -0700785 deployment_nodes = []
786 for node in Node.objects.all():
787 deployment_nodes.append( (node.deployment.id, node.id, node.name) )
788
Scott Baker7a61dc42014-09-02 17:08:20 -0700789 deployment_flavors = []
790 for flavor in Flavor.objects.all():
791 for deployment in flavor.deployments.all():
792 deployment_flavors.append( (deployment.id, flavor.id, flavor.name) )
793
Scott Baker93e80cd2014-09-09 09:58:49 -0700794 deployment_images = []
795 for image in Image.objects.all():
796 for imageDeployment in image.imagedeployments_set.all():
797 deployment_images.append( (imageDeployment.deployment.id, image.id, image.name) )
798
Tony Mackec23b992014-09-02 21:18:45 -0400799 site_login_bases = []
800 for site in Site.objects.all():
Scott Baker93e80cd2014-09-09 09:58:49 -0700801 site_login_bases.append((site.id, site.login_base))
802
Scott Baker510fdbb2014-08-05 17:19:24 -0700803 context["deployment_nodes"] = deployment_nodes
Scott Baker7a61dc42014-09-02 17:08:20 -0700804 context["deployment_flavors"] = deployment_flavors
Scott Baker93e80cd2014-09-09 09:58:49 -0700805 context["deployment_images"] = deployment_images
Tony Mackec23b992014-09-02 21:18:45 -0400806 context["site_login_bases"] = site_login_bases
Scott Baker510fdbb2014-08-05 17:19:24 -0700807 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
808
Tony Mackc2835a92013-05-28 09:18:49 -0400809 def formfield_for_foreignkey(self, db_field, request, **kwargs):
810 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500811 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackec23b992014-09-02 21:18:45 -0400812 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 -0700813
Tony Mackc2835a92013-05-28 09:18:49 -0400814 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
815
Tony Mack04062832013-05-10 08:22:44 -0400816 def queryset(self, request):
817 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500818 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400819
Tony Mack79748612013-05-01 14:52:03 -0400820 def get_formsets(self, request, obj=None):
821 for inline in self.get_inline_instances(request, obj):
822 # hide MyInline in the add view
823 if obj is None:
824 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400825 if isinstance(inline, SliverInline):
826 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400827 yield inline.get_formset(request, obj)
828
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400829class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400830 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700831 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -0400832 ]
Scott Baker40c00762014-08-21 16:55:59 -0700833 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700834 list_display = ('backend_status_icon', 'user', 'slice', 'role')
835 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -0400836
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500837 user_readonly_fields = ['user', 'slice', 'role']
838 user_readonly_inlines = []
839
Tony Mackc2835a92013-05-28 09:18:49 -0400840 def formfield_for_foreignkey(self, db_field, request, **kwargs):
841 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500842 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400843
844 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500845 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400846
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400847 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400848
Tony Mack04062832013-05-10 08:22:44 -0400849 def queryset(self, request):
850 # admins can see all memberships. Users can only see memberships of
851 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500852 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400853
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400854 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400855 # update openstack connection to use this site/tenant
856 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400857 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400858 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400859 obj.save()
860
861 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400862 # update openstack connection to use this site/tenant
863 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400864 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400865 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400866 obj.delete()
867
Siobhan Tully567e3e62013-06-21 18:03:16 -0400868
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400869class ImageAdmin(PlanetStackBaseAdmin):
870
Scott Baker36f50872014-08-21 13:01:25 -0700871 fieldsets = [('Image Details',
Scott Baker40c00762014-08-21 16:55:59 -0700872 {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400873 'classes': ['suit-tab suit-tab-general']})
874 ]
Scott Baker40c00762014-08-21 16:55:59 -0700875 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400876
Scott Baker2170b972014-06-03 12:14:07 -0700877 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400878
Scott Baker2170b972014-06-03 12:14:07 -0700879 inlines = [SliverInline, ImageDeploymentsInline]
Scott Bakerb6f99242014-06-11 11:34:44 -0700880
Tony Mack32e1ce32014-05-07 13:29:41 -0400881 user_readonly_fields = ['name', 'disk_format', 'container_format']
Scott Bakerb27b62c2014-08-15 16:29:16 -0700882
Scott Baker63d1a552014-08-21 15:19:07 -0700883 list_display = ['backend_status_icon', 'name']
884 list_display_links = ('backend_status_icon', 'name', )
885
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400886class NodeForm(forms.ModelForm):
887 class Meta:
888 widgets = {
889 'site': LinkedSelect,
890 'deployment': LinkedSelect
891 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400892
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500893class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400894 form = NodeForm
Scott Baker63d1a552014-08-21 15:19:07 -0700895 list_display = ('backend_status_icon', 'name', 'site', 'deployment')
896 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400897 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500898
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400899 inlines = [TagInline,SliverInline]
Scott Baker40c00762014-08-21 16:55:59 -0700900 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
901 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400902
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500903 user_readonly_fields = ['name','site','deployment']
904 user_readonly_inlines = [TagInline,SliverInline]
905
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400906 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400907
Siobhan Tully567e3e62013-06-21 18:03:16 -0400908
Tony Mackd90cdbf2013-04-16 22:48:40 -0400909class SliverForm(forms.ModelForm):
910 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400911 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400912 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400913 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400914 widgets = {
915 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400916 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400917 'slice': LinkedSelect,
918 'deploymentNetwork': LinkedSelect,
919 'node': LinkedSelect,
920 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400921 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400922
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500923class TagAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700924 list_display = ['backend_status_icon', 'service', 'name', 'value', 'content_type', 'content_object',]
925 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500926 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
927 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400928
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400929class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400930 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400931 fieldsets = [
Scott Baker7a61dc42014-09-02 17:08:20 -0700932 ('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 -0400933 ]
Scott Baker40c00762014-08-21 16:55:59 -0700934 readonly_fields = ('backend_status_text', )
Scott Baker7a61dc42014-09-02 17:08:20 -0700935 list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deploymentNetwork']
Scott Baker63d1a552014-08-21 15:19:07 -0700936 list_display_links = ('backend_status_icon', 'ip',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400937
938 suit_form_tabs =(('general', 'Sliver Details'),
939 ('tags','Tags'),
940 )
941
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400942 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400943
Scott Baker7a61dc42014-09-02 17:08:20 -0700944 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500945
Tony Mackc2835a92013-05-28 09:18:49 -0400946 def formfield_for_foreignkey(self, db_field, request, **kwargs):
947 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500948 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400949
950 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
951
Tony Mack04062832013-05-10 08:22:44 -0400952 def queryset(self, request):
Scott Baker36f50872014-08-21 13:01:25 -0700953 # admins can see all slivers. Users can only see slivers of
Tony Mack04062832013-05-10 08:22:44 -0400954 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500955 return Sliver.select_by_user(request.user)
956
Tony Mack04062832013-05-10 08:22:44 -0400957
Tony Mack1d6b85f2013-05-07 18:49:14 -0400958 def get_formsets(self, request, obj=None):
959 # make some fields read only if we are updating an existing record
960 if obj == None:
Scott Baker36f50872014-08-21 13:01:25 -0700961 #self.readonly_fields = ('ip', 'instance_name')
Scott Bakerfbb45862014-10-17 16:27:23 -0700962 self.readonly_fields = ('backend_status_text',)
Tony Mack1d6b85f2013-05-07 18:49:14 -0400963 else:
Scott Bakerfbb45862014-10-17 16:27:23 -0700964 self.readonly_fields = ('backend_status_text',)
Scott Baker36f50872014-08-21 13:01:25 -0700965 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400966
967 for inline in self.get_inline_instances(request, obj):
968 # hide MyInline in the add view
969 if obj is None:
970 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700971 if isinstance(inline, SliverInline):
972 inline.model.caller = request.user
973 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400974
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500975 #def save_model(self, request, obj, form, change):
976 # # update openstack connection to use this site/tenant
977 # auth = request.session.get('auth', {})
978 # auth['tenant'] = obj.slice.name
979 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
980 # obj.creator = request.user
981 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400982
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500983 #def delete_model(self, request, obj):
984 # # update openstack connection to use this site/tenant
985 # auth = request.session.get('auth', {})
986 # auth['tenant'] = obj.slice.name
987 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
988 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400989
Siobhan Tully53437282013-04-26 19:30:27 -0400990class UserCreationForm(forms.ModelForm):
991 """A form for creating new users. Includes all the required
992 fields, plus a repeated password."""
993 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
994 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
995
996 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400997 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400998 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400999
1000 def clean_password2(self):
1001 # Check that the two password entries match
1002 password1 = self.cleaned_data.get("password1")
1003 password2 = self.cleaned_data.get("password2")
1004 if password1 and password2 and password1 != password2:
1005 raise forms.ValidationError("Passwords don't match")
1006 return password2
1007
1008 def save(self, commit=True):
1009 # Save the provided password in hashed format
1010 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -04001011 user.password = self.cleaned_data["password1"]
1012 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -04001013 if commit:
1014 user.save()
1015 return user
1016
Siobhan Tully567e3e62013-06-21 18:03:16 -04001017
Siobhan Tully53437282013-04-26 19:30:27 -04001018class UserChangeForm(forms.ModelForm):
1019 """A form for updating users. Includes all the fields on
1020 the user, but replaces the password field with admin's
1021 password hash display field.
1022 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -05001023 password = ReadOnlyPasswordHashField(label='Password',
1024 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -04001025
1026 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -04001027 model = User
Siobhan Tully53437282013-04-26 19:30:27 -04001028
1029 def clean_password(self):
1030 # Regardless of what the user provides, return the initial value.
1031 # This is done here, rather than on the field, because the
1032 # field does not have access to the initial value
1033 return self.initial["password"]
1034
Scott Baker2c3cb642014-05-19 17:55:56 -07001035class UserDashboardViewInline(PlStackTabularInline):
1036 model = UserDashboardView
1037 extra = 0
1038 suit_classes = 'suit-tab suit-tab-dashboards'
1039 fields = ['user', 'dashboardView', 'order']
1040
Scott Baker86c83ab2014-10-03 13:10:47 -07001041class UserAdmin(PermissionCheckingAdminMixin, UserAdmin):
1042 # Note: Make sure PermissionCheckingAdminMixin is listed before
1043 # admin.ModelAdmin in the class declaration.
1044
Siobhan Tully53437282013-04-26 19:30:27 -04001045 class Meta:
1046 app_label = "core"
1047
1048 # The forms to add and change user instances
1049 form = UserChangeForm
1050 add_form = UserCreationForm
1051
1052 # The fields to be used in displaying the User model.
1053 # These override the definitions on the base UserAdmin
1054 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001055 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001056 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -07001057 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001058
Scott Bakercbfb6002014-10-03 00:32:37 -07001059 fieldListLoginDetails = ['backend_status_text', 'email','site','password','is_active','is_readonly','is_admin','public_key']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001060 fieldListContactInfo = ['firstname','lastname','phone','timezone']
1061
Siobhan Tully53437282013-04-26 19:30:27 -04001062 fieldsets = (
Scott Baker40c00762014-08-21 16:55:59 -07001063 ('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 -04001064 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -07001065 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001066 #('Important dates', {'fields': ('last_login',)}),
1067 )
1068 add_fieldsets = (
1069 (None, {
1070 'classes': ('wide',),
Scott Baker0a5633b2014-10-06 17:51:20 -07001071 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')},
Siobhan Tully53437282013-04-26 19:30:27 -04001072 ),
1073 )
Scott Baker40c00762014-08-21 16:55:59 -07001074 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001075 search_fields = ('email',)
1076 ordering = ('email',)
1077 filter_horizontal = ()
1078
Scott Baker3ca51f62014-05-23 12:05:11 -07001079 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001080
Scott Baker0a5633b2014-10-06 17:51:20 -07001081 @property
1082 def suit_form_tabs(self):
1083 if getattr(_thread_locals, "obj", None) is None:
1084 return []
1085 else:
1086 return (('general','Login Details'),
1087 ('contact','Contact Information'),
1088 ('sliceprivileges','Slice Privileges'),
1089 ('siteprivileges','Site Privileges'),
1090 ('deploymentprivileges','Deployment Privileges'),
1091 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001092
Tony Mackc2835a92013-05-28 09:18:49 -04001093 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1094 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001095 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001096
1097 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1098
Tony Mack5b061472014-02-04 07:57:10 -05001099 def queryset(self, request):
1100 return User.select_by_user(request.user)
1101
Scott Baker2c3cb642014-05-19 17:55:56 -07001102class DashboardViewAdmin(PlanetStackBaseAdmin):
1103 fieldsets = [('Dashboard View Details',
Scott Baker40c00762014-08-21 16:55:59 -07001104 {'fields': ['backend_status_text', 'name', 'url'],
Scott Baker2c3cb642014-05-19 17:55:56 -07001105 'classes': ['suit-tab suit-tab-general']})
1106 ]
Scott Baker40c00762014-08-21 16:55:59 -07001107 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001108
Scott Baker2c3cb642014-05-19 17:55:56 -07001109 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001110
Scott Baker0165fac2014-01-13 11:49:26 -08001111class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001112 model = ServiceResource
1113 extra = 0
1114
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001115class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001116 list_display = ('backend_status_icon', 'name', 'commitment', 'membershipFee')
1117 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001118 inlines = [ServiceResourceInline]
1119
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001120 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1121 user_readonly_inlines = []
1122
Scott Baker0165fac2014-01-13 11:49:26 -08001123class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001124 model = ReservedResource
1125 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001126 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001127
1128 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1129 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1130
1131 if db_field.name == 'resource':
1132 # restrict resources to those that the slice's service class allows
1133 if request._slice is not None:
1134 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1135 if len(field.queryset) > 0:
1136 field.initial = field.queryset.all()[0]
1137 else:
1138 field.queryset = field.queryset.none()
1139 elif db_field.name == 'sliver':
1140 # restrict slivers to those that belong to the slice
1141 if request._slice is not None:
1142 field.queryset = field.queryset.filter(slice = request._slice)
1143 else:
1144 field.queryset = field.queryset.none()
1145
1146 return field
1147
Tony Mack5b061472014-02-04 07:57:10 -05001148 def queryset(self, request):
1149 return ReservedResource.select_by_user(request.user)
1150
Scott Baker133c9212013-05-17 09:09:11 -07001151class ReservationChangeForm(forms.ModelForm):
1152 class Meta:
1153 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001154 widgets = {
1155 'slice' : LinkedSelect
1156 }
Scott Baker133c9212013-05-17 09:09:11 -07001157
1158class ReservationAddForm(forms.ModelForm):
1159 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1160 refresh = forms.CharField(widget=forms.HiddenInput())
1161
1162 class Media:
1163 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1164
1165 def clean_slice(self):
1166 slice = self.cleaned_data.get("slice")
1167 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1168 if len(x) == 0:
1169 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1170 return slice
1171
1172 class Meta:
1173 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001174 widgets = {
1175 'slice' : LinkedSelect
1176 }
1177
Scott Baker133c9212013-05-17 09:09:11 -07001178
1179class ReservationAddRefreshForm(ReservationAddForm):
1180 """ This form is displayed when the Reservation Form receives an update
1181 from the Slice dropdown onChange handler. It doesn't validate the
1182 data and doesn't save the data. This will cause the form to be
1183 redrawn.
1184 """
1185
Scott Baker8737e5f2013-05-17 09:35:32 -07001186 """ don't validate anything other than slice """
1187 dont_validate_fields = ("startTime", "duration")
1188
Scott Baker133c9212013-05-17 09:09:11 -07001189 def full_clean(self):
1190 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001191
1192 for fieldname in self.dont_validate_fields:
1193 if fieldname in self._errors:
1194 del self._errors[fieldname]
1195
Scott Baker133c9212013-05-17 09:09:11 -07001196 return result
1197
1198 """ don't save anything """
1199 def is_valid(self):
1200 return False
1201
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001202class ReservationAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001203 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001204 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001205 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001206 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001207 form = ReservationAddForm
1208
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001209 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1210
1211 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001212 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001213
Scott Baker133c9212013-05-17 09:09:11 -07001214 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001215 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001216 request._refresh = False
1217 request._slice = None
1218 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001219 # "refresh" will be set to "1" if the form was submitted due to
1220 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001221 if request.POST.get("refresh","1") == "1":
1222 request._refresh = True
1223 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001224
1225 # Keep track of the slice that was selected, so the
1226 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001227 request._slice = request.POST.get("slice",None)
1228 if (request._slice is not None):
1229 request._slice = Slice.objects.get(id=request._slice)
1230
1231 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1232 return result
1233
Scott Bakeracd45142013-05-19 16:19:16 -07001234 def changelist_view(self, request, extra_context = None):
1235 timezone.activate(request.user.timezone)
1236 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1237
Scott Baker133c9212013-05-17 09:09:11 -07001238 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001239 request._obj_ = obj
1240 if obj is not None:
1241 # For changes, set request._slice to the slice already set in the
1242 # object.
1243 request._slice = obj.slice
1244 self.form = ReservationChangeForm
1245 else:
1246 if getattr(request, "_refresh", False):
1247 self.form = ReservationAddRefreshForm
1248 else:
1249 self.form = ReservationAddForm
1250 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1251
Scott Baker133c9212013-05-17 09:09:11 -07001252 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001253 if (obj is not None):
1254 # Prevent slice from being changed after the reservation has been
1255 # created.
1256 return ['slice']
1257 else:
Scott Baker133c9212013-05-17 09:09:11 -07001258 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001259
Tony Mack5b061472014-02-04 07:57:10 -05001260 def queryset(self, request):
1261 return Reservation.select_by_user(request.user)
1262
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001263class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001264 list_display = ("backend_status_icon", "name", )
1265 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001266 user_readonly_fields = ['name']
1267 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001268
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001269class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001270 list_display = ("backend_status_icon", "name", )
1271 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001272 user_readonly_fields = ['name']
1273 user_readonly_inlines = []
1274
Scott Baker0165fac2014-01-13 11:49:26 -08001275class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001276 model = Router.networks.through
1277 extra = 0
1278 verbose_name_plural = "Routers"
1279 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001280 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001281
Scott Bakerb27b62c2014-08-15 16:29:16 -07001282class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001283 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07001284 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001285 verbose_name_plural = "Parameters"
1286 verbose_name = "Parameter"
1287 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07001288 fields = ['backend_status_icon', 'parameter', 'value']
1289 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001290
Scott Baker0165fac2014-01-13 11:49:26 -08001291class NetworkSliversInline(PlStackTabularInline):
Scott Baker40c00762014-08-21 16:55:59 -07001292 fields = ['backend_status_icon', 'network','sliver','ip']
1293 readonly_fields = ("backend_status_icon", "ip", )
Scott Baker74d8e622013-07-29 16:04:22 -07001294 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001295 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001296 extra = 0
1297 verbose_name_plural = "Slivers"
1298 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001299 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001300
Scott Baker0165fac2014-01-13 11:49:26 -08001301class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001302 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001303 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001304 extra = 0
1305 verbose_name_plural = "Slices"
1306 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001307 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Baker40c00762014-08-21 16:55:59 -07001308 fields = ['backend_status_icon', 'network','slice']
1309 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07001310
Scott Bakerfbb45862014-10-17 16:27:23 -07001311class NetworkDeploymentsInline(PlStackTabularInline):
1312 model = NetworkDeployments
1313 extra = 0
1314 verbose_name_plural = "Network Deployments"
1315 verbose_name = "Network Deployment"
1316 suit_classes = 'suit-tab suit-tab-admin-only'
1317 fields = ['backend_status_icon', 'deployment','net_id','subnet_id']
1318 readonly_fields = ('backend_status_icon', )
1319
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001320class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001321 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
1322 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07001323 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001324
Scott Bakerd7d2a392013-08-06 08:57:30 -07001325 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Bakerfbb45862014-10-17 16:27:23 -07001326 admin_inlines = [NetworkDeploymentsInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001327
Siobhan Tully2d95e482013-09-06 10:56:06 -04001328 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001329 (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 -05001330
Scott Baker40c00762014-08-21 16:55:59 -07001331 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001332 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 -04001333
Scott Bakerfbb45862014-10-17 16:27:23 -07001334 @property
1335 def suit_form_tabs(self):
1336 tabs=[('general','Network Details'),
1337 ('netparams', 'Parameters'),
1338 ('networkslivers','Slivers'),
1339 ('networkslices','Slices'),
1340 ('routers','Routers'),
1341 ]
1342
1343 request=getattr(_thread_locals, "request", None)
1344 if request and request.user.is_admin:
1345 tabs.append( ('admin-only', 'Admin-Only') )
1346
1347 return tabs
1348
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