blob: 1952890daadd115f386946eb1ce3b3bac7a523fd [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
Scott Baker3cde7372014-10-21 21:03:08 -070018from cgi import escape as html_escape
Tony Mack7130ac32013-03-22 21:58:00 -040019
Scott Baker36f50872014-08-21 13:01:25 -070020import django_evolution
Scott Baker0a5633b2014-10-06 17:51:20 -070021import threading
22
23# thread locals necessary to work around a django-suit issue
24_thread_locals = threading.local()
Scott Baker36f50872014-08-21 13:01:25 -070025
Scott Baker40c00762014-08-21 16:55:59 -070026def backend_icon(obj): # backend_status, enacted, updated):
27 #return "%s %s %s" % (str(obj.updated), str(obj.enacted), str(obj.backend_status))
28 if (obj.enacted is not None) and obj.enacted >= obj.updated:
Scott Bakerfbf06642014-09-09 10:38:15 -070029 return '<span style="min-width:16px;"><img src="/static/admin/img/icon_success.gif"></span>'
Scott Baker40c00762014-08-21 16:55:59 -070030 else:
31 if obj.backend_status == "Provisioning in progress" or obj.backend_status=="":
Scott Bakerfbf06642014-09-09 10:38:15 -070032 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 -070033 else:
Scott Baker3cde7372014-10-21 21:03:08 -070034 return '<span style="min-width:16px;" title="%s"><img src="/static/admin/img/icon_error.gif"></span>' % html_escape(obj.backend_status, quote=True)
Scott Baker40c00762014-08-21 16:55:59 -070035
36def backend_text(obj):
37 icon = backend_icon(obj)
38 if (obj.enacted is not None) and obj.enacted >= obj.updated:
Scott Baker3cde7372014-10-21 21:03:08 -070039 return "%s %s" % (icon, "successfully enacted")
Scott Baker40c00762014-08-21 16:55:59 -070040 else:
Scott Baker3cde7372014-10-21 21:03:08 -070041 return "%s %s" % (icon, html_escape(obj.backend_status, quote=True))
Scott Baker63d1a552014-08-21 15:19:07 -070042
Scott Baker36f50872014-08-21 13:01:25 -070043class PlainTextWidget(forms.HiddenInput):
44 input_type = 'hidden'
45
46 def render(self, name, value, attrs=None):
47 if value is None:
48 value = ''
49 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
50
Scott Baker86c83ab2014-10-03 13:10:47 -070051class PermissionCheckingAdminMixin(object):
Scott Bakercbfb6002014-10-03 00:32:37 -070052 # call save_by_user and delete_by_user instead of save and delete
Siobhan Tullycf04fb62014-01-11 11:25:57 -050053
54 def has_add_permission(self, request, obj=None):
55 return (not self.__user_is_readonly(request))
Scott Baker36f50872014-08-21 13:01:25 -070056
Siobhan Tullycf04fb62014-01-11 11:25:57 -050057 def has_delete_permission(self, request, obj=None):
58 return (not self.__user_is_readonly(request))
59
60 def save_model(self, request, obj, form, change):
61 if self.__user_is_readonly(request):
Scott Bakercbfb6002014-10-03 00:32:37 -070062 # this 'if' might be redundant if save_by_user is implemented right
Siobhan Tullycf04fb62014-01-11 11:25:57 -050063 raise PermissionDenied
Scott Bakercbfb6002014-10-03 00:32:37 -070064
65 obj.caller = request.user
66 # update openstack connection to use this site/tenant
67 obj.save_by_user(request.user)
68
69 def delete_model(self, request, obj):
70 obj.delete_by_user(request.user)
71
72 def save_formset(self, request, form, formset, change):
73 instances = formset.save(commit=False)
74 for instance in instances:
75 instance.save_by_user(request.user)
76
77 # BUG in django 1.7? Objects are not deleted by formset.save if
78 # commit is False. So let's delete them ourselves.
79 #
80 # code from forms/models.py save_existing_objects()
81 try:
82 forms_to_delete = formset.deleted_forms
83 except AttributeError:
84 forms_to_delete = []
85 if formset.initial_forms:
86 for form in formset.initial_forms:
87 obj = form.instance
88 if form in forms_to_delete:
89 if obj.pk is None:
90 continue
91 formset.deleted_objects.append(obj)
92 obj.delete()
93
94 formset.save_m2m()
Siobhan Tullycf04fb62014-01-11 11:25:57 -050095
96 def get_actions(self,request):
Scott Baker86c83ab2014-10-03 13:10:47 -070097 actions = super(PermissionCheckingAdminMixin,self).get_actions(request)
Siobhan Tullycf04fb62014-01-11 11:25:57 -050098
99 if self.__user_is_readonly(request):
100 if 'delete_selected' in actions:
101 del actions['delete_selected']
102
103 return actions
104
105 def change_view(self,request,object_id, extra_context=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500106 if self.__user_is_readonly(request):
Scott Bakeraf73e102014-04-22 22:40:07 -0700107 if not hasattr(self, "readonly_save"):
108 # save the original readonly fields
109 self.readonly_save = self.readonly_fields
110 self.inlines_save = self.inlines
Scott Bakere8859f92014-05-23 12:42:40 -0700111 if hasattr(self, "user_readonly_fields"):
112 self.readonly_fields=self.user_readonly_fields
113 if hasattr(self, "user_readonly_inlines"):
114 self.inlines = self.user_readonly_inlines
Scott Bakeraf73e102014-04-22 22:40:07 -0700115 else:
116 if hasattr(self, "readonly_save"):
117 # restore the original readonly fields
118 self.readonly_fields = self.readonly_save
Scott Bakere8859f92014-05-23 12:42:40 -0700119 if hasattr(self, "inlines_save"):
Scott Bakeraf73e102014-04-22 22:40:07 -0700120 self.inlines = self.inlines_save
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500121
122 try:
Scott Baker86c83ab2014-10-03 13:10:47 -0700123 return super(PermissionCheckingAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500124 except PermissionDenied:
125 pass
126 if request.method == 'POST':
127 raise PermissionDenied
128 request.readonly = True
Scott Baker86c83ab2014-10-03 13:10:47 -0700129 return super(PermissionCheckingAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500130
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500131 def __user_is_readonly(self, request):
132 return request.user.isReadOnlyUser()
133
Scott Baker40c00762014-08-21 16:55:59 -0700134 def backend_status_text(self, obj):
135 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -0700136
Scott Baker63d1a552014-08-21 15:19:07 -0700137 def backend_status_icon(self, obj):
Scott Baker40c00762014-08-21 16:55:59 -0700138 return mark_safe(backend_icon(obj))
Scott Baker63d1a552014-08-21 15:19:07 -0700139 backend_status_icon.short_description = ""
140
Scott Baker5c432692014-10-16 00:57:55 -0700141 def get_form(self, request, obj=None):
142 # Save obj and request in thread-local storage, so suit_form_tabs can
143 # use it to determine whether we're in edit or add mode, and can
144 # determine whether the user is an admin.
145 _thread_locals.request = request
146 _thread_locals.obj = obj
147 return super(PermissionCheckingAdminMixin, self).get_form(request, obj)
148
149 def get_inline_instances(self, request, obj=None):
150 inlines = super(PermissionCheckingAdminMixin, self).get_inline_instances(request, obj)
151
152 # inlines that should only be shown to an admin user
153 if request.user.is_admin:
154 for inline_class in getattr(self, "admin_inlines", []):
155 inlines.append(inline_class(self.model, self.admin_site))
156
157 return inlines
158
Scott Baker86c83ab2014-10-03 13:10:47 -0700159class ReadOnlyAwareAdmin(PermissionCheckingAdminMixin, admin.ModelAdmin):
160 # Note: Make sure PermissionCheckingAdminMixin is listed before
161 # admin.ModelAdmin in the class declaration.
162
Scott Bakercbfb6002014-10-03 00:32:37 -0700163 pass
164
165class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
166 save_on_top = False
Scott Baker36f50872014-08-21 13:01:25 -0700167
Scott Bakere8859f92014-05-23 12:42:40 -0700168class SingletonAdmin (ReadOnlyAwareAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400169 def has_add_permission(self, request):
Scott Bakere8859f92014-05-23 12:42:40 -0700170 if not super(SingletonAdmin, self).has_add_permission(request):
171 return False
172
Siobhan Tullyce652d02013-10-08 21:52:35 -0400173 num_objects = self.model.objects.count()
174 if num_objects >= 1:
175 return False
176 else:
177 return True
178
Siobhan Tullyd3515752013-06-21 16:34:53 -0400179class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -0800180 def __init__(self, *args, **kwargs):
181 super(PlStackTabularInline, self).__init__(*args, **kwargs)
182
183 # InlineModelAdmin as no get_fields() method, so in order to add
184 # the selflink field, we override __init__ to modify self.fields and
185 # self.readonly_fields.
186
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800187 self.setup_selflink()
188
Scott Baker874936e2014-01-13 18:15:34 -0800189 def get_change_url(self, model, id):
190 """ Get the URL to a change form in the admin for this model """
191 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800192 try:
Scott Baker874936e2014-01-13 18:15:34 -0800193 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800194 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -0800195 return None
196
197 return url
198
199 def setup_selflink(self):
200 if hasattr(self, "selflink_fieldname"):
201 """ self.selflink_model can be defined to punch through a relation
202 to its target object. For example, in SliceNetworkInline, set
203 selflink_model = "network", and the URL will lead to the Network
204 object instead of trying to bring up a change view of the
205 SliceNetwork object.
206 """
207 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
208 else:
209 self.selflink_model = self.model
210
211 url = self.get_change_url(self.selflink_model, 0)
212
213 # We don't have an admin for this object, so don't create the
214 # selflink.
215 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800216 return
217
Scott Baker874936e2014-01-13 18:15:34 -0800218 # Since we need to add "selflink" to the field list, we need to create
219 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800220 if (self.fields is None):
221 self.fields = []
222 for f in self.model._meta.fields:
223 if f.editable and f.name != "id":
224 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800225
Scott Baker874936e2014-01-13 18:15:34 -0800226 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800227
Scott Baker874936e2014-01-13 18:15:34 -0800228 if self.readonly_fields is None:
229 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800230
Scott Baker874936e2014-01-13 18:15:34 -0800231 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800232
233 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800234 if hasattr(self, "selflink_fieldname"):
235 obj = getattr(obj, self.selflink_fieldname)
236
Scott Baker86568322014-01-12 16:53:31 -0800237 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800238 url = self.get_change_url(self.selflink_model, obj.id)
239 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800240 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800241 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800242
243 selflink.allow_tags = True
244 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400245
Scott Bakerb27b62c2014-08-15 16:29:16 -0700246 def has_add_permission(self, request):
247 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500248
249 def get_readonly_fields(self, request, obj=None):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700250 readonly_fields = list(self.readonly_fields)[:]
251 if request.user.isReadOnlyUser():
252 for field in self.fields:
253 if not field in readonly_fields:
254 readonly_fields.append(field)
255 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500256
Scott Baker40c00762014-08-21 16:55:59 -0700257 def backend_status_icon(self, obj):
258 return mark_safe(backend_icon(obj))
259 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -0700260
Scott Bakerb27b62c2014-08-15 16:29:16 -0700261class PlStackGenericTabularInline(generic.GenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500262 def has_add_permission(self, request):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700263 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500264
Scott Bakerb27b62c2014-08-15 16:29:16 -0700265 def get_readonly_fields(self, request, obj=None):
266 readonly_fields = list(self.readonly_fields)[:]
267 if request.user.isReadOnlyUser():
268 for field in self.fields:
269 if not field in readonly_fields:
270 readonly_fields.append(field)
271 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500272
Scott Baker40c00762014-08-21 16:55:59 -0700273 def backend_status_icon(self, obj):
274 return mark_safe(backend_icon(obj))
275 backend_status_icon.short_description = ""
276
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400277class ReservationInline(PlStackTabularInline):
278 model = Reservation
279 extra = 0
280 suit_classes = 'suit-tab suit-tab-reservations'
Scott Baker36f50872014-08-21 13:01:25 -0700281
Tony Mack5b061472014-02-04 07:57:10 -0500282 def queryset(self, request):
283 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400284
Scott Bakerb27b62c2014-08-15 16:29:16 -0700285class TagInline(PlStackGenericTabularInline):
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400286 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400287 extra = 0
288 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500289 fields = ['service', 'name', 'value']
290
291 def queryset(self, request):
292 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400293
Scott Baker74d8e622013-07-29 16:04:22 -0700294class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400295 """ This is a callable that looks up a network name in a sliver and returns
296 the ip address for that network.
297 """
298
Scott Baker434ca7e2014-08-15 12:29:20 -0700299 byNetworkName = {} # class variable
300
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400301 def __init__(self, name):
302 self.short_description = name
303 self.__name__ = name
304 self.network_name = name
305
306 def __call__(self, obj):
307 if obj is not None:
308 for nbs in obj.networksliver_set.all():
309 if (nbs.network.name == self.network_name):
310 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700311 return ""
312
313 def __str__(self):
314 return self.network_name
315
Scott Baker434ca7e2014-08-15 12:29:20 -0700316 @staticmethod
317 def get(network_name):
318 """ We want to make sure we alwars return the same NetworkLookerUpper
319 because sometimes django will cause them to be instantiated multiple
320 times (and we don't want different ones in form.fields vs
321 SliverInline.readonly_fields).
322 """
323 if network_name not in NetworkLookerUpper.byNetworkName:
324 NetworkLookerUpper.byNetworkName[network_name] = NetworkLookerUpper(network_name)
325 return NetworkLookerUpper.byNetworkName[network_name]
326
Siobhan Tullyd3515752013-06-21 16:34:53 -0400327class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400328 model = Sliver
Scott Baker7a61dc42014-09-02 17:08:20 -0700329 fields = ['backend_status_icon', 'all_ips_string', 'instance_name', 'slice', 'deploymentNetwork', 'flavor', 'image', 'node']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400330 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700331 readonly_fields = ['backend_status_icon', 'all_ips_string', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400332 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700333
Tony Mack5b061472014-02-04 07:57:10 -0500334 def queryset(self, request):
335 return Sliver.select_by_user(request.user)
336
Scott Bakerb24cc932014-06-09 10:51:16 -0700337 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
Scott Bakerb24cc932014-06-09 10:51:16 -0700338 if db_field.name == 'deploymentNetwork':
Scott Baker3b678742014-06-09 13:11:54 -0700339 kwargs['queryset'] = Deployment.select_by_acl(request.user)
Scott Baker7a61dc42014-09-02 17:08:20 -0700340 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_deployment_changed(this);"})
Scott Baker32481312014-09-08 12:14:14 -0700341 elif db_field.name == 'flavor':
342 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_flavor_changed(this);"})
Scott Baker3b678742014-06-09 13:11:54 -0700343
344 field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700345
346 return field
347
Siobhan Tullyd3515752013-06-21 16:34:53 -0400348class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400349 model = Site
350 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400351 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400352
Tony Mack5b061472014-02-04 07:57:10 -0500353 def queryset(self, request):
354 return Site.select_by_user(request.user)
355
Siobhan Tullyd3515752013-06-21 16:34:53 -0400356class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400357 model = User
Scott Baker40c00762014-08-21 16:55:59 -0700358 fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
359 readonly_fields = ('backend_status_icon', )
Siobhan Tully30fd4292013-05-10 08:59:56 -0400360 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400361 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400362
Tony Mack5b061472014-02-04 07:57:10 -0500363 def queryset(self, request):
364 return User.select_by_user(request.user)
365
Siobhan Tullyd3515752013-06-21 16:34:53 -0400366class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400367 model = Slice
Scott Baker40c00762014-08-21 16:55:59 -0700368 fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
369 readonly_fields = ('backend_status_icon', )
Tony Mack00d361f2013-04-28 10:28:42 -0400370 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400371 suit_classes = 'suit-tab suit-tab-slices'
372
Tony Mack5b061472014-02-04 07:57:10 -0500373 def queryset(self, request):
374 return Slice.select_by_user(request.user)
375
Siobhan Tullyd3515752013-06-21 16:34:53 -0400376class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400377 model = Node
378 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400379 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker40c00762014-08-21 16:55:59 -0700380 fields = ['backend_status_icon', 'name','deployment','site']
381 readonly_fields = ('backend_status_icon', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400382
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400383class DeploymentPrivilegeInline(PlStackTabularInline):
384 model = DeploymentPrivilege
385 extra = 0
386 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700387 fields = ['backend_status_icon', 'user','role','deployment']
388 readonly_fields = ('backend_status_icon', )
Tony Mack5b061472014-02-04 07:57:10 -0500389
390 def queryset(self, request):
391 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400392
Siobhan Tullyd3515752013-06-21 16:34:53 -0400393class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400394 model = SitePrivilege
395 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400396 suit_classes = 'suit-tab suit-tab-siteprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700397 fields = ['backend_status_icon', 'user','site', 'role']
398 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400399
Tony Mackc2835a92013-05-28 09:18:49 -0400400 def formfield_for_foreignkey(self, db_field, request, **kwargs):
401 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500402 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400403
404 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500405 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400406 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
407
Tony Mack5b061472014-02-04 07:57:10 -0500408 def queryset(self, request):
409 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400410
Tony Macke4be32f2014-03-11 20:45:25 -0400411class SiteDeploymentInline(PlStackTabularInline):
412 model = SiteDeployments
Tony Macke4be32f2014-03-11 20:45:25 -0400413 extra = 0
414 suit_classes = 'suit-tab suit-tab-deployments'
Scott Baker40c00762014-08-21 16:55:59 -0700415 fields = ['backend_status_icon', 'deployment','site']
416 readonly_fields = ('backend_status_icon', )
Tony Macke4be32f2014-03-11 20:45:25 -0400417
418 def formfield_for_foreignkey(self, db_field, request, **kwargs):
419 if db_field.name == 'site':
420 kwargs['queryset'] = Site.select_by_user(request.user)
421
422 if db_field.name == 'deployment':
423 kwargs['queryset'] = Deployment.select_by_user(request.user)
424 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
425
426 def queryset(self, request):
427 return SiteDeployments.select_by_user(request.user)
428
429
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400430class SlicePrivilegeInline(PlStackTabularInline):
431 model = SlicePrivilege
432 suit_classes = 'suit-tab suit-tab-sliceprivileges'
433 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700434 fields = ('backend_status_icon', 'user', 'slice', 'role')
435 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400436
Tony Mackc2835a92013-05-28 09:18:49 -0400437 def formfield_for_foreignkey(self, db_field, request, **kwargs):
438 if db_field.name == 'slice':
Scott Baker36f50872014-08-21 13:01:25 -0700439 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400440 if db_field.name == 'user':
Scott Baker36f50872014-08-21 13:01:25 -0700441 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400442
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400443 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400444
Tony Mack5b061472014-02-04 07:57:10 -0500445 def queryset(self, request):
446 return SlicePrivilege.select_by_user(request.user)
447
Scott Bakera0015eb2013-08-14 17:28:14 -0700448class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700449 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800450 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700451 extra = 0
452 verbose_name = "Network Connection"
453 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400454 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker40c00762014-08-21 16:55:59 -0700455 fields = ['backend_status_icon', 'network']
456 readonly_fields = ('backend_status_icon', )
Scott Baker2170b972014-06-03 12:14:07 -0700457
458class ImageDeploymentsInline(PlStackTabularInline):
459 model = ImageDeployments
460 extra = 0
461 verbose_name = "Image Deployments"
462 verbose_name_plural = "Image Deployments"
463 suit_classes = 'suit-tab suit-tab-imagedeployments'
Scott Baker40c00762014-08-21 16:55:59 -0700464 fields = ['backend_status_icon', 'image', 'deployment', 'glance_image_id']
465 readonly_fields = ['backend_status_icon', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700466
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400467class SliceRoleAdmin(PlanetStackBaseAdmin):
468 model = SliceRole
469 pass
470
471class SiteRoleAdmin(PlanetStackBaseAdmin):
472 model = SiteRole
473 pass
474
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400475class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400476 sites = forms.ModelMultipleChoiceField(
477 queryset=Site.objects.all(),
478 required=False,
Scott Baker70983182014-06-09 22:10:00 -0700479 help_text="Select which sites are allowed to host nodes in this deployment",
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400480 widget=FilteredSelectMultiple(
481 verbose_name=('Sites'), is_stacked=False
482 )
483 )
Scott Bakerde0f4412014-06-11 15:40:26 -0700484 images = forms.ModelMultipleChoiceField(
485 queryset=Image.objects.all(),
486 required=False,
487 help_text="Select which images should be deployed on this deployment",
488 widget=FilteredSelectMultiple(
489 verbose_name=('Images'), is_stacked=False
490 )
491 )
Scott Baker37b47902014-09-02 14:37:41 -0700492 flavors = forms.ModelMultipleChoiceField(
493 queryset=Flavor.objects.all(),
494 required=False,
495 help_text="Select which flavors should be usable on this deployment",
496 widget=FilteredSelectMultiple(
497 verbose_name=('Flavors'), is_stacked=False
498 )
499 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400500 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400501 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700502 many_to_many = ["flavors",]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400503
Siobhan Tully320b4622014-01-17 15:11:14 -0500504 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700505 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500506 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
507
Scott Baker5380c522014-06-06 14:49:43 -0700508 self.fields['accessControl'].initial = "allow site " + request.user.site.name
509
Siobhan Tully320b4622014-01-17 15:11:14 -0500510 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700511 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Scott Bakerde0f4412014-06-11 15:40:26 -0700512 self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
Scott Baker37b47902014-09-02 14:37:41 -0700513 self.fields['flavors'].initial = self.instance.flavors.all()
Scott Bakerde0f4412014-06-11 15:40:26 -0700514
515 def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
516 """ helper function for handling m2m relations from the MultipleChoiceField
517
518 this_obj: the source object we want to link from
519
520 selected_objs: a list of destination objects we want to link to
521
522 all_relations: the full set of relations involving this_obj, including ones we don't want
523
524 relation_class: the class that implements the relation from source to dest
525
526 local_attrname: field name representing this_obj in relation_class
527
528 foreign_attrname: field name representing selected_objs in relation_class
529
530 This function will remove all newobjclass relations from this_obj
531 that are not contained in selected_objs, and add any relations that
532 are in selected_objs but don't exist in the data model yet.
533 """
534
535 existing_dest_objs = []
536 for relation in list(all_relations):
537 if getattr(relation, foreign_attrname) not in selected_objs:
538 #print "deleting site", sdp.site
539 relation.delete()
540 else:
541 existing_dest_objs.append(getattr(relation, foreign_attrname))
542
543 for dest_obj in selected_objs:
544 if dest_obj not in existing_dest_objs:
545 #print "adding site", site
546 kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
547 relation = relation_class(**kwargs)
548 relation.save()
Siobhan Tully320b4622014-01-17 15:11:14 -0500549
550 def save(self, commit=True):
551 deployment = super(DeploymentAdminForm, self).save(commit=False)
552
553 if commit:
554 deployment.save()
Scott Baker61b6aec2014-10-06 17:17:40 -0700555 # this has to be done after save() if/when a deployment is first created
556 deployment.flavors = self.cleaned_data['flavors']
Siobhan Tully320b4622014-01-17 15:11:14 -0500557
558 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700559 # save_m2m() doesn't seem to work with 'through' relations. So we
560 # create/destroy the through models ourselves. There has to be
561 # a better way...
562
Scott Bakerde0f4412014-06-11 15:40:26 -0700563 self.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
564 self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
Scott Bakerc9b14f72014-05-22 13:44:20 -0700565
Scott Baker37b47902014-09-02 14:37:41 -0700566 self.save_m2m()
Siobhan Tully320b4622014-01-17 15:11:14 -0500567
568 return deployment
569
Scott Bakerff5e0f32014-05-22 14:40:27 -0700570class DeploymentAdminROForm(DeploymentAdminForm):
571 def save(self, commit=True):
572 raise PermissionDenied
573
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500574class SiteAssocInline(PlStackTabularInline):
575 model = Site.deployments.through
576 extra = 0
577 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400578
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400579class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500580 model = Deployment
Tony Mack2cbd3802014-09-29 16:10:52 -0400581 fieldList = ['backend_status_text', 'name', 'availability_zone', 'sites', 'images', 'flavors', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500582 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Scott Bakerde0f4412014-06-11 15:40:26 -0700583 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
Scott Baker63d1a552014-08-21 15:19:07 -0700584 list_display = ['backend_status_icon', 'name']
585 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700586 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500587
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500588 user_readonly_fields = ['name']
589
Scott Bakerde0f4412014-06-11 15:40:26 -0700590 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags')) # ,('imagedeployments','Images'))
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500591
Scott Bakerff5e0f32014-05-22 14:40:27 -0700592 def get_form(self, request, obj=None, **kwargs):
593 if request.user.isReadOnlyUser():
594 kwargs["form"] = DeploymentAdminROForm
595 else:
596 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700597 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
598
599 # from stackexchange: pass the request object into the form
600
601 class AdminFormMetaClass(adminForm):
602 def __new__(cls, *args, **kwargs):
603 kwargs['request'] = request
604 return adminForm(*args, **kwargs)
605
606 return AdminFormMetaClass
607
Siobhan Tullyce652d02013-10-08 21:52:35 -0400608class ServiceAttrAsTabInline(PlStackTabularInline):
609 model = ServiceAttribute
610 fields = ['name','value']
611 extra = 0
612 suit_classes = 'suit-tab suit-tab-serviceattrs'
613
Siobhan Tullyce652d02013-10-08 21:52:35 -0400614class ServiceAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700615 list_display = ("backend_status_icon","name","description","versionNumber","enabled","published")
616 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700617 fieldList = ["backend_status_text","name","description","versionNumber","enabled","published"]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500618 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
619 inlines = [ServiceAttrAsTabInline,SliceInline]
Scott Baker40c00762014-08-21 16:55:59 -0700620 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500621
622 user_readonly_fields = fieldList
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500623
624 suit_form_tabs =(('general', 'Service Details'),
625 ('slices','Slices'),
626 ('serviceattrs','Additional Attributes'),
627 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400628
Tony Mack0553f282013-06-10 22:54:50 -0400629class SiteAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700630 fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400631 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500632 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400633 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400634 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400635 suit_form_tabs =(('general', 'Site Details'),
636 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400637 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400638 ('deployments','Deployments'),
639 ('slices','Slices'),
Scott Baker36f50872014-08-21 13:01:25 -0700640 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400641 ('tags','Tags'),
642 )
Scott Baker40c00762014-08-21 16:55:59 -0700643 readonly_fields = ['backend_status_text', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500644
645 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500646
Scott Baker63d1a552014-08-21 15:19:07 -0700647 list_display = ('backend_status_icon', 'name', 'login_base','site_url', 'enabled')
648 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400649 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400650 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400651 search_fields = ['name']
652
Tony Mack04062832013-05-10 08:22:44 -0400653 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500654 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400655
Tony Mack5cd13202013-05-01 21:48:38 -0400656 def get_formsets(self, request, obj=None):
657 for inline in self.get_inline_instances(request, obj):
658 # hide MyInline in the add view
659 if obj is None:
660 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400661 if isinstance(inline, SliverInline):
662 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400663 yield inline.get_formset(request, obj)
664
Scott Baker545db2a2013-12-09 18:44:43 -0800665 def accountLink(self, obj):
666 link_obj = obj.accounts.all()
667 if link_obj:
668 reverse_path = "admin:core_account_change"
669 url = reverse(reverse_path, args =(link_obj[0].id,))
670 return "<a href='%s'>%s</a>" % (url, "view billing details")
671 else:
672 return "no billing data for this site"
673 accountLink.allow_tags = True
674 accountLink.short_description = "Billing"
675
Tony Mack332ee1d2014-02-04 15:33:45 -0500676 def save_model(self, request, obj, form, change):
677 # update openstack connection to use this site/tenant
678 obj.save_by_user(request.user)
679
680 def delete_model(self, request, obj):
681 obj.delete_by_user(request.user)
682
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500683
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400684class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700685 fieldList = ['backend_status_text', 'user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400686 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500687 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400688 ]
Scott Baker40c00762014-08-21 16:55:59 -0700689 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700690 list_display = ('backend_status_icon', 'user', 'site', 'role')
691 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500692 user_readonly_fields = fieldList
693 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400694
Tony Mackc2835a92013-05-28 09:18:49 -0400695 def formfield_for_foreignkey(self, db_field, request, **kwargs):
696 if db_field.name == 'site':
697 if not request.user.is_admin:
698 # only show sites where user is an admin or pi
699 sites = set()
700 for site_privilege in SitePrivilege.objects.filer(user=request.user):
701 if site_privilege.role.role_type in ['admin', 'pi']:
702 sites.add(site_privilege.site)
703 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
704
705 if db_field.name == 'user':
706 if not request.user.is_admin:
707 # only show users from sites where caller has admin or pi role
708 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
709 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
710 sites = [site_privilege.site for site_privilege in site_privileges]
711 site_privileges = SitePrivilege.objects.filter(site__in=sites)
712 emails = [site_privilege.user.email for site_privilege in site_privileges]
713 users = User.objects.filter(email__in=emails)
714 kwargs['queryset'] = users
715
716 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
717
Tony Mack04062832013-05-10 08:22:44 -0400718 def queryset(self, request):
719 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400720 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400721 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500722 #if not request.user.is_admin:
723 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
724 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
725 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
726 # sites = Site.objects.filter(login_base__in=login_bases)
727 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400728 return qs
729
Siobhan Tullyce652d02013-10-08 21:52:35 -0400730class SliceForm(forms.ModelForm):
731 class Meta:
732 model = Slice
733 widgets = {
Scott Baker36f50872014-08-21 13:01:25 -0700734 'service': LinkedSelect
Siobhan Tullyce652d02013-10-08 21:52:35 -0400735 }
736
Tony Mack2cbd3802014-09-29 16:10:52 -0400737 def clean(self):
738 cleaned_data = super(SliceForm, self).clean()
739 name = cleaned_data.get('name')
Scott Baker6efad462014-10-06 23:09:59 -0700740 site = cleaned_data.get('site')
741 if (not isinstance(site,Site)):
742 # previous code indicates 'site' could be a site_id and not a site?
743 site = Slice.objects.get(id=site.id)
Tony Mack2cbd3802014-09-29 16:10:52 -0400744 if not name.startswith(site.login_base):
745 raise forms.ValidationError('slice name must begin with %s' % site.login_base)
746 return cleaned_data
747
Scott Bakerc4efdc72014-10-15 16:54:04 -0700748class SliceDeploymentsInline(PlStackTabularInline):
749 model = SliceDeployments
750 extra = 0
751 verbose_name = "Slice Deployment"
752 verbose_name_plural = "Slice Deployments"
753 suit_classes = 'suit-tab suit-tab-admin-only'
754 fields = ['backend_status_icon', 'deployment', 'tenant_id']
755 readonly_fields = ('backend_status_icon', )
756
Tony Mack2bd5b412013-06-11 21:05:06 -0400757class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400758 form = SliceForm
Tony Mackfbb26fc2014-09-02 07:03:27 -0400759 fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500760 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Scott Baker40c00762014-08-21 16:55:59 -0700761 readonly_fields = ('backend_status_text', )
Tony Mack7d459902014-09-03 13:18:57 -0400762 list_display = ('backend_status_icon', 'name', 'site','serviceClass', 'slice_url', 'max_slivers')
763 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully2d95e482013-09-06 10:56:06 -0400764 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Scott Bakerc4efdc72014-10-15 16:54:04 -0700765 admin_inlines = [SliceDeploymentsInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400766
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500767 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400768
Scott Bakerc4efdc72014-10-15 16:54:04 -0700769 @property
770 def suit_form_tabs(self):
771 tabs =[('general', 'Slice Details'),
772 ('slicenetworks','Networks'),
773 ('sliceprivileges','Privileges'),
774 ('slivers','Slivers'),
775 ('tags','Tags'),
776 ('reservations','Reservations'),
777 ]
778
779 request=getattr(_thread_locals, "request", None)
780 if request and request.user.is_admin:
781 tabs.append( ('admin-only', 'Admin-Only') )
782
783 return tabs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400784
Scott Baker510fdbb2014-08-05 17:19:24 -0700785 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
Scott Baker510fdbb2014-08-05 17:19:24 -0700786 deployment_nodes = []
787 for node in Node.objects.all():
788 deployment_nodes.append( (node.deployment.id, node.id, node.name) )
789
Scott Baker7a61dc42014-09-02 17:08:20 -0700790 deployment_flavors = []
791 for flavor in Flavor.objects.all():
792 for deployment in flavor.deployments.all():
793 deployment_flavors.append( (deployment.id, flavor.id, flavor.name) )
794
Scott Baker93e80cd2014-09-09 09:58:49 -0700795 deployment_images = []
796 for image in Image.objects.all():
797 for imageDeployment in image.imagedeployments_set.all():
798 deployment_images.append( (imageDeployment.deployment.id, image.id, image.name) )
799
Tony Mackec23b992014-09-02 21:18:45 -0400800 site_login_bases = []
801 for site in Site.objects.all():
Scott Baker93e80cd2014-09-09 09:58:49 -0700802 site_login_bases.append((site.id, site.login_base))
803
Scott Baker510fdbb2014-08-05 17:19:24 -0700804 context["deployment_nodes"] = deployment_nodes
Scott Baker7a61dc42014-09-02 17:08:20 -0700805 context["deployment_flavors"] = deployment_flavors
Scott Baker93e80cd2014-09-09 09:58:49 -0700806 context["deployment_images"] = deployment_images
Tony Mackec23b992014-09-02 21:18:45 -0400807 context["site_login_bases"] = site_login_bases
Scott Baker510fdbb2014-08-05 17:19:24 -0700808 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
809
Tony Mackc2835a92013-05-28 09:18:49 -0400810 def formfield_for_foreignkey(self, db_field, request, **kwargs):
811 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500812 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackec23b992014-09-02 21:18:45 -0400813 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 -0700814
Tony Mackc2835a92013-05-28 09:18:49 -0400815 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
816
Tony Mack04062832013-05-10 08:22:44 -0400817 def queryset(self, request):
818 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500819 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400820
Tony Mack79748612013-05-01 14:52:03 -0400821 def get_formsets(self, request, obj=None):
822 for inline in self.get_inline_instances(request, obj):
823 # hide MyInline in the add view
824 if obj is None:
825 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400826 if isinstance(inline, SliverInline):
827 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400828 yield inline.get_formset(request, obj)
829
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400830class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400831 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700832 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -0400833 ]
Scott Baker40c00762014-08-21 16:55:59 -0700834 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700835 list_display = ('backend_status_icon', 'user', 'slice', 'role')
836 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -0400837
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500838 user_readonly_fields = ['user', 'slice', 'role']
839 user_readonly_inlines = []
840
Tony Mackc2835a92013-05-28 09:18:49 -0400841 def formfield_for_foreignkey(self, db_field, request, **kwargs):
842 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500843 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400844
845 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500846 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400847
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400848 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400849
Tony Mack04062832013-05-10 08:22:44 -0400850 def queryset(self, request):
851 # admins can see all memberships. Users can only see memberships of
852 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500853 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400854
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400855 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400856 # update openstack connection to use this site/tenant
857 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400858 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400859 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400860 obj.save()
861
862 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400863 # update openstack connection to use this site/tenant
864 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400865 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400866 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400867 obj.delete()
868
Siobhan Tully567e3e62013-06-21 18:03:16 -0400869
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400870class ImageAdmin(PlanetStackBaseAdmin):
871
Scott Baker36f50872014-08-21 13:01:25 -0700872 fieldsets = [('Image Details',
Scott Baker40c00762014-08-21 16:55:59 -0700873 {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400874 'classes': ['suit-tab suit-tab-general']})
875 ]
Scott Baker40c00762014-08-21 16:55:59 -0700876 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400877
Scott Baker2170b972014-06-03 12:14:07 -0700878 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400879
Scott Baker2170b972014-06-03 12:14:07 -0700880 inlines = [SliverInline, ImageDeploymentsInline]
Scott Bakerb6f99242014-06-11 11:34:44 -0700881
Tony Mack32e1ce32014-05-07 13:29:41 -0400882 user_readonly_fields = ['name', 'disk_format', 'container_format']
Scott Bakerb27b62c2014-08-15 16:29:16 -0700883
Scott Baker63d1a552014-08-21 15:19:07 -0700884 list_display = ['backend_status_icon', 'name']
885 list_display_links = ('backend_status_icon', 'name', )
886
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400887class NodeForm(forms.ModelForm):
888 class Meta:
889 widgets = {
890 'site': LinkedSelect,
891 'deployment': LinkedSelect
892 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400893
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500894class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400895 form = NodeForm
Scott Baker63d1a552014-08-21 15:19:07 -0700896 list_display = ('backend_status_icon', 'name', 'site', 'deployment')
897 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400898 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500899
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400900 inlines = [TagInline,SliverInline]
Scott Baker40c00762014-08-21 16:55:59 -0700901 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
902 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400903
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500904 user_readonly_fields = ['name','site','deployment']
905 user_readonly_inlines = [TagInline,SliverInline]
906
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400907 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400908
Siobhan Tully567e3e62013-06-21 18:03:16 -0400909
Tony Mackd90cdbf2013-04-16 22:48:40 -0400910class SliverForm(forms.ModelForm):
911 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400912 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400913 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400914 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400915 widgets = {
916 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400917 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400918 'slice': LinkedSelect,
919 'deploymentNetwork': LinkedSelect,
920 'node': LinkedSelect,
921 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400922 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400923
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500924class TagAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700925 list_display = ['backend_status_icon', 'service', 'name', 'value', 'content_type', 'content_object',]
926 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500927 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
928 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400929
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400930class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400931 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400932 fieldsets = [
Scott Baker7a61dc42014-09-02 17:08:20 -0700933 ('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 -0400934 ]
Scott Baker40c00762014-08-21 16:55:59 -0700935 readonly_fields = ('backend_status_text', )
Scott Baker7a61dc42014-09-02 17:08:20 -0700936 list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deploymentNetwork']
Scott Baker63d1a552014-08-21 15:19:07 -0700937 list_display_links = ('backend_status_icon', 'ip',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400938
939 suit_form_tabs =(('general', 'Sliver Details'),
940 ('tags','Tags'),
941 )
942
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400943 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400944
Scott Baker7a61dc42014-09-02 17:08:20 -0700945 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500946
Tony Mackc2835a92013-05-28 09:18:49 -0400947 def formfield_for_foreignkey(self, db_field, request, **kwargs):
948 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500949 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400950
951 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
952
Tony Mack04062832013-05-10 08:22:44 -0400953 def queryset(self, request):
Scott Baker36f50872014-08-21 13:01:25 -0700954 # admins can see all slivers. Users can only see slivers of
Tony Mack04062832013-05-10 08:22:44 -0400955 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500956 return Sliver.select_by_user(request.user)
957
Tony Mack04062832013-05-10 08:22:44 -0400958
Tony Mack1d6b85f2013-05-07 18:49:14 -0400959 def get_formsets(self, request, obj=None):
960 # make some fields read only if we are updating an existing record
961 if obj == None:
Scott Baker36f50872014-08-21 13:01:25 -0700962 #self.readonly_fields = ('ip', 'instance_name')
Scott Bakerfbb45862014-10-17 16:27:23 -0700963 self.readonly_fields = ('backend_status_text',)
Tony Mack1d6b85f2013-05-07 18:49:14 -0400964 else:
Scott Bakerfbb45862014-10-17 16:27:23 -0700965 self.readonly_fields = ('backend_status_text',)
Scott Baker36f50872014-08-21 13:01:25 -0700966 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400967
968 for inline in self.get_inline_instances(request, obj):
969 # hide MyInline in the add view
970 if obj is None:
971 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700972 if isinstance(inline, SliverInline):
973 inline.model.caller = request.user
974 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400975
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500976 #def save_model(self, request, obj, form, change):
977 # # update openstack connection to use this site/tenant
978 # auth = request.session.get('auth', {})
979 # auth['tenant'] = obj.slice.name
980 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
981 # obj.creator = request.user
982 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400983
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500984 #def delete_model(self, request, obj):
985 # # update openstack connection to use this site/tenant
986 # auth = request.session.get('auth', {})
987 # auth['tenant'] = obj.slice.name
988 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
989 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400990
Siobhan Tully53437282013-04-26 19:30:27 -0400991class UserCreationForm(forms.ModelForm):
992 """A form for creating new users. Includes all the required
993 fields, plus a repeated password."""
994 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
995 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
996
997 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400998 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400999 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -04001000
1001 def clean_password2(self):
1002 # Check that the two password entries match
1003 password1 = self.cleaned_data.get("password1")
1004 password2 = self.cleaned_data.get("password2")
1005 if password1 and password2 and password1 != password2:
1006 raise forms.ValidationError("Passwords don't match")
1007 return password2
1008
1009 def save(self, commit=True):
1010 # Save the provided password in hashed format
1011 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -04001012 user.password = self.cleaned_data["password1"]
1013 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -04001014 if commit:
1015 user.save()
1016 return user
1017
Siobhan Tully567e3e62013-06-21 18:03:16 -04001018
Siobhan Tully53437282013-04-26 19:30:27 -04001019class UserChangeForm(forms.ModelForm):
1020 """A form for updating users. Includes all the fields on
1021 the user, but replaces the password field with admin's
1022 password hash display field.
1023 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -05001024 password = ReadOnlyPasswordHashField(label='Password',
1025 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -04001026
1027 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -04001028 model = User
Siobhan Tully53437282013-04-26 19:30:27 -04001029
1030 def clean_password(self):
1031 # Regardless of what the user provides, return the initial value.
1032 # This is done here, rather than on the field, because the
1033 # field does not have access to the initial value
1034 return self.initial["password"]
1035
Scott Baker2c3cb642014-05-19 17:55:56 -07001036class UserDashboardViewInline(PlStackTabularInline):
1037 model = UserDashboardView
1038 extra = 0
1039 suit_classes = 'suit-tab suit-tab-dashboards'
1040 fields = ['user', 'dashboardView', 'order']
1041
Scott Baker86c83ab2014-10-03 13:10:47 -07001042class UserAdmin(PermissionCheckingAdminMixin, UserAdmin):
1043 # Note: Make sure PermissionCheckingAdminMixin is listed before
1044 # admin.ModelAdmin in the class declaration.
1045
Siobhan Tully53437282013-04-26 19:30:27 -04001046 class Meta:
1047 app_label = "core"
1048
1049 # The forms to add and change user instances
1050 form = UserChangeForm
1051 add_form = UserCreationForm
1052
1053 # The fields to be used in displaying the User model.
1054 # These override the definitions on the base UserAdmin
1055 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001056 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001057 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -07001058 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001059
Scott Bakercbfb6002014-10-03 00:32:37 -07001060 fieldListLoginDetails = ['backend_status_text', 'email','site','password','is_active','is_readonly','is_admin','public_key']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001061 fieldListContactInfo = ['firstname','lastname','phone','timezone']
1062
Siobhan Tully53437282013-04-26 19:30:27 -04001063 fieldsets = (
Scott Baker40c00762014-08-21 16:55:59 -07001064 ('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 -04001065 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -07001066 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001067 #('Important dates', {'fields': ('last_login',)}),
1068 )
1069 add_fieldsets = (
1070 (None, {
1071 'classes': ('wide',),
Scott Baker0a5633b2014-10-06 17:51:20 -07001072 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')},
Siobhan Tully53437282013-04-26 19:30:27 -04001073 ),
1074 )
Scott Baker40c00762014-08-21 16:55:59 -07001075 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001076 search_fields = ('email',)
1077 ordering = ('email',)
1078 filter_horizontal = ()
1079
Scott Baker3ca51f62014-05-23 12:05:11 -07001080 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001081
Scott Baker0a5633b2014-10-06 17:51:20 -07001082 @property
1083 def suit_form_tabs(self):
1084 if getattr(_thread_locals, "obj", None) is None:
1085 return []
1086 else:
1087 return (('general','Login Details'),
1088 ('contact','Contact Information'),
1089 ('sliceprivileges','Slice Privileges'),
1090 ('siteprivileges','Site Privileges'),
1091 ('deploymentprivileges','Deployment Privileges'),
1092 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001093
Tony Mackc2835a92013-05-28 09:18:49 -04001094 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1095 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001096 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001097
1098 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1099
Tony Mack5b061472014-02-04 07:57:10 -05001100 def queryset(self, request):
1101 return User.select_by_user(request.user)
1102
Scott Baker2c3cb642014-05-19 17:55:56 -07001103class DashboardViewAdmin(PlanetStackBaseAdmin):
1104 fieldsets = [('Dashboard View Details',
Scott Baker40c00762014-08-21 16:55:59 -07001105 {'fields': ['backend_status_text', 'name', 'url'],
Scott Baker2c3cb642014-05-19 17:55:56 -07001106 'classes': ['suit-tab suit-tab-general']})
1107 ]
Scott Baker40c00762014-08-21 16:55:59 -07001108 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001109
Scott Baker2c3cb642014-05-19 17:55:56 -07001110 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001111
Scott Baker0165fac2014-01-13 11:49:26 -08001112class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001113 model = ServiceResource
1114 extra = 0
1115
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001116class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001117 list_display = ('backend_status_icon', 'name', 'commitment', 'membershipFee')
1118 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001119 inlines = [ServiceResourceInline]
1120
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001121 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1122 user_readonly_inlines = []
1123
Scott Baker0165fac2014-01-13 11:49:26 -08001124class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001125 model = ReservedResource
1126 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001127 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001128
1129 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1130 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1131
1132 if db_field.name == 'resource':
1133 # restrict resources to those that the slice's service class allows
1134 if request._slice is not None:
1135 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1136 if len(field.queryset) > 0:
1137 field.initial = field.queryset.all()[0]
1138 else:
1139 field.queryset = field.queryset.none()
1140 elif db_field.name == 'sliver':
1141 # restrict slivers to those that belong to the slice
1142 if request._slice is not None:
1143 field.queryset = field.queryset.filter(slice = request._slice)
1144 else:
1145 field.queryset = field.queryset.none()
1146
1147 return field
1148
Tony Mack5b061472014-02-04 07:57:10 -05001149 def queryset(self, request):
1150 return ReservedResource.select_by_user(request.user)
1151
Scott Baker133c9212013-05-17 09:09:11 -07001152class ReservationChangeForm(forms.ModelForm):
1153 class Meta:
1154 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001155 widgets = {
1156 'slice' : LinkedSelect
1157 }
Scott Baker133c9212013-05-17 09:09:11 -07001158
1159class ReservationAddForm(forms.ModelForm):
1160 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1161 refresh = forms.CharField(widget=forms.HiddenInput())
1162
1163 class Media:
1164 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1165
1166 def clean_slice(self):
1167 slice = self.cleaned_data.get("slice")
1168 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1169 if len(x) == 0:
1170 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1171 return slice
1172
1173 class Meta:
1174 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001175 widgets = {
1176 'slice' : LinkedSelect
1177 }
1178
Scott Baker133c9212013-05-17 09:09:11 -07001179
1180class ReservationAddRefreshForm(ReservationAddForm):
1181 """ This form is displayed when the Reservation Form receives an update
1182 from the Slice dropdown onChange handler. It doesn't validate the
1183 data and doesn't save the data. This will cause the form to be
1184 redrawn.
1185 """
1186
Scott Baker8737e5f2013-05-17 09:35:32 -07001187 """ don't validate anything other than slice """
1188 dont_validate_fields = ("startTime", "duration")
1189
Scott Baker133c9212013-05-17 09:09:11 -07001190 def full_clean(self):
1191 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001192
1193 for fieldname in self.dont_validate_fields:
1194 if fieldname in self._errors:
1195 del self._errors[fieldname]
1196
Scott Baker133c9212013-05-17 09:09:11 -07001197 return result
1198
1199 """ don't save anything """
1200 def is_valid(self):
1201 return False
1202
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001203class ReservationAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001204 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001205 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001206 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001207 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001208 form = ReservationAddForm
1209
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001210 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1211
1212 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001213 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001214
Scott Baker133c9212013-05-17 09:09:11 -07001215 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001216 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001217 request._refresh = False
1218 request._slice = None
1219 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001220 # "refresh" will be set to "1" if the form was submitted due to
1221 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001222 if request.POST.get("refresh","1") == "1":
1223 request._refresh = True
1224 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001225
1226 # Keep track of the slice that was selected, so the
1227 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001228 request._slice = request.POST.get("slice",None)
1229 if (request._slice is not None):
1230 request._slice = Slice.objects.get(id=request._slice)
1231
1232 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1233 return result
1234
Scott Bakeracd45142013-05-19 16:19:16 -07001235 def changelist_view(self, request, extra_context = None):
1236 timezone.activate(request.user.timezone)
1237 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1238
Scott Baker133c9212013-05-17 09:09:11 -07001239 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001240 request._obj_ = obj
1241 if obj is not None:
1242 # For changes, set request._slice to the slice already set in the
1243 # object.
1244 request._slice = obj.slice
1245 self.form = ReservationChangeForm
1246 else:
1247 if getattr(request, "_refresh", False):
1248 self.form = ReservationAddRefreshForm
1249 else:
1250 self.form = ReservationAddForm
1251 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1252
Scott Baker133c9212013-05-17 09:09:11 -07001253 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001254 if (obj is not None):
1255 # Prevent slice from being changed after the reservation has been
1256 # created.
1257 return ['slice']
1258 else:
Scott Baker133c9212013-05-17 09:09:11 -07001259 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001260
Tony Mack5b061472014-02-04 07:57:10 -05001261 def queryset(self, request):
1262 return Reservation.select_by_user(request.user)
1263
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001264class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001265 list_display = ("backend_status_icon", "name", )
1266 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001267 user_readonly_fields = ['name']
1268 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001269
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001270class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001271 list_display = ("backend_status_icon", "name", )
1272 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001273 user_readonly_fields = ['name']
1274 user_readonly_inlines = []
1275
Scott Baker0165fac2014-01-13 11:49:26 -08001276class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001277 model = Router.networks.through
1278 extra = 0
1279 verbose_name_plural = "Routers"
1280 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001281 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001282
Scott Bakerb27b62c2014-08-15 16:29:16 -07001283class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001284 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07001285 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001286 verbose_name_plural = "Parameters"
1287 verbose_name = "Parameter"
1288 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07001289 fields = ['backend_status_icon', 'parameter', 'value']
1290 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001291
Scott Baker0165fac2014-01-13 11:49:26 -08001292class NetworkSliversInline(PlStackTabularInline):
Scott Baker40c00762014-08-21 16:55:59 -07001293 fields = ['backend_status_icon', 'network','sliver','ip']
1294 readonly_fields = ("backend_status_icon", "ip", )
Scott Baker74d8e622013-07-29 16:04:22 -07001295 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001296 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001297 extra = 0
1298 verbose_name_plural = "Slivers"
1299 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001300 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001301
Scott Baker0165fac2014-01-13 11:49:26 -08001302class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001303 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001304 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001305 extra = 0
1306 verbose_name_plural = "Slices"
1307 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001308 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Baker40c00762014-08-21 16:55:59 -07001309 fields = ['backend_status_icon', 'network','slice']
1310 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07001311
Scott Bakerfbb45862014-10-17 16:27:23 -07001312class NetworkDeploymentsInline(PlStackTabularInline):
1313 model = NetworkDeployments
1314 extra = 0
1315 verbose_name_plural = "Network Deployments"
1316 verbose_name = "Network Deployment"
1317 suit_classes = 'suit-tab suit-tab-admin-only'
1318 fields = ['backend_status_icon', 'deployment','net_id','subnet_id']
1319 readonly_fields = ('backend_status_icon', )
1320
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001321class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001322 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
1323 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07001324 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001325
Scott Bakerd7d2a392013-08-06 08:57:30 -07001326 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Bakerfbb45862014-10-17 16:27:23 -07001327 admin_inlines = [NetworkDeploymentsInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001328
Siobhan Tully2d95e482013-09-06 10:56:06 -04001329 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001330 (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 -05001331
Scott Baker40c00762014-08-21 16:55:59 -07001332 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001333 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 -04001334
Scott Bakerfbb45862014-10-17 16:27:23 -07001335 @property
1336 def suit_form_tabs(self):
1337 tabs=[('general','Network Details'),
1338 ('netparams', 'Parameters'),
1339 ('networkslivers','Slivers'),
1340 ('networkslices','Slices'),
1341 ('routers','Routers'),
1342 ]
1343
1344 request=getattr(_thread_locals, "request", None)
1345 if request and request.user.is_admin:
1346 tabs.append( ('admin-only', 'Admin-Only') )
1347
1348 return tabs
1349
1350
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001351class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001352 list_display = ("backend_status_icon", "name", "guaranteedBandwidth", "visibility")
1353 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001354 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1355 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001356
Scott Baker37b47902014-09-02 14:37:41 -07001357class FlavorAdmin(PlanetStackBaseAdmin):
1358 list_display = ("backend_status_icon", "name", "flavor", "order", "default")
1359 list_display_links = ("backend_status_icon", "name")
1360 user_readonly_fields = ("name", "flavor")
1361 fields = ("name", "description", "flavor", "order", "default")
1362
Tony Mack31c2b8f2013-04-26 20:01:42 -04001363# register a signal that caches the user's credentials when they log in
1364def cache_credentials(sender, user, request, **kwds):
1365 auth = {'username': request.POST['username'],
1366 'password': request.POST['password']}
1367 request.session['auth'] = auth
1368user_logged_in.connect(cache_credentials)
1369
Scott Baker15cddfa2013-12-09 13:45:19 -08001370def dollar_field(fieldName, short_description):
1371 def newFunc(self, obj):
1372 try:
1373 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1374 except:
1375 x=getattr(obj, fieldName, 0.0)
1376 return x
1377 newFunc.short_description = short_description
1378 return newFunc
1379
1380def right_dollar_field(fieldName, short_description):
1381 def newFunc(self, obj):
1382 try:
1383 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1384 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1385 except:
1386 x=getattr(obj, fieldName, 0.0)
1387 return x
1388 newFunc.short_description = short_description
1389 newFunc.allow_tags = True
1390 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001391
Scott Baker0165fac2014-01-13 11:49:26 -08001392class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001393 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001394 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001395 verbose_name_plural = "Charges"
1396 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001397 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001398 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1399 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1400 can_delete = False
1401 max_num = 0
1402
1403 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001404
1405class InvoiceAdmin(admin.ModelAdmin):
1406 list_display = ("date", "account")
1407
1408 inlines = [InvoiceChargeInline]
1409
Scott Baker9cb88a22013-12-09 18:56:00 -08001410 fields = ["date", "account", "dollar_amount"]
1411 readonly_fields = ["date", "account", "dollar_amount"]
1412
1413 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001414
Scott Baker0165fac2014-01-13 11:49:26 -08001415class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001416 model = Invoice
1417 extra = 0
1418 verbose_name_plural = "Invoices"
1419 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001420 fields = ["date", "dollar_amount"]
1421 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001422 suit_classes = 'suit-tab suit-tab-accountinvoice'
1423 can_delete=False
1424 max_num=0
1425
1426 dollar_amount = right_dollar_field("amount", "Amount")
1427
Scott Baker0165fac2014-01-13 11:49:26 -08001428class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001429 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001430 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001431 verbose_name_plural = "Charges"
1432 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001433 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001434 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1435 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001436 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001437 can_delete=False
1438 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001439
1440 def queryset(self, request):
1441 qs = super(PendingChargeInline, self).queryset(request)
1442 qs = qs.filter(state="pending")
1443 return qs
1444
Scott Baker15cddfa2013-12-09 13:45:19 -08001445 dollar_amount = right_dollar_field("amount", "Amount")
1446
Scott Baker0165fac2014-01-13 11:49:26 -08001447class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001448 model=Payment
1449 extra = 1
1450 verbose_name_plural = "Payments"
1451 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001452 fields = ["date", "dollar_amount"]
1453 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001454 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001455 can_delete=False
1456 max_num=0
1457
1458 dollar_amount = right_dollar_field("amount", "Amount")
1459
Scott Baker43105042013-12-06 23:23:36 -08001460class AccountAdmin(admin.ModelAdmin):
1461 list_display = ("site", "balance_due")
1462
1463 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1464
1465 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001466 (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 -08001467
Scott Baker15cddfa2013-12-09 13:45:19 -08001468 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001469
1470 suit_form_tabs =(
1471 ('general','Account Details'),
1472 ('accountinvoice', 'Invoices'),
1473 ('accountpayments', 'Payments'),
1474 ('accountpendingcharges','Pending Charges'),
1475 )
1476
Scott Baker15cddfa2013-12-09 13:45:19 -08001477 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1478 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1479 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1480
Siobhan Tully53437282013-04-26 19:30:27 -04001481# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001482admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001483# ... and, since we're not using Django's builtin permissions,
1484# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001485#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001486
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001487#Do not show django evolution in the admin interface
1488from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001489#admin.site.unregister(Version)
1490#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001491
1492
1493# When debugging it is often easier to see all the classes, but for regular use
1494# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001495showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001496
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001497admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001498admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001499admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001500admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001501admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001502admin.site.register(Network, NetworkAdmin)
1503admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001504admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001505admin.site.register(Account, AccountAdmin)
1506admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001507
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001508if True:
1509 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1510 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001511 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001512 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001513 admin.site.register(DeploymentRole)
1514 admin.site.register(SiteRole)
1515 admin.site.register(SliceRole)
1516 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001517 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001518 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1519 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001520 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001521 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001522 admin.site.register(DashboardView, DashboardViewAdmin)
Scott Baker37b47902014-09-02 14:37:41 -07001523 admin.site.register(Flavor, FlavorAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001524