blob: c5e36be22eb2a3aced15e30a4aeeac14b4d4d97c [file] [log] [blame]
Jeremy Mowery18cde4f2016-04-03 13:04:39 -07001import threading
2from cgi import escape as html_escape
Tony Macke59a7c82013-04-27 11:08:10 -04003
Jeremy Moweryfda63ce2016-04-19 10:30:28 -07004from core.models import *
5from core.models import Site
Siobhan Tully4bc09f22013-04-10 21:15:21 -04006from django import forms
Jeremy Mowery18cde4f2016-04-03 13:04:39 -07007from django.contrib import admin, messages
8from django.contrib.admin.widgets import (AdminTextareaWidget,
9 FilteredSelectMultiple)
Tony Mack7130ac32013-03-22 21:58:00 -040010from django.contrib.auth.admin import UserAdmin
Jeremy Mowery18cde4f2016-04-03 13:04:39 -070011from django.contrib.auth.forms import (AdminPasswordChangeForm,
12 ReadOnlyPasswordHashField)
13from django.contrib.auth.models import Group
Scott Bakeracd45142013-05-19 16:19:16 -070014from django.contrib.auth.signals import user_logged_in
Siobhan Tullyde5450d2013-06-21 11:35:33 -040015from django.contrib.contenttypes import generic
Jeremy Mowery18cde4f2016-04-03 13:04:39 -070016from django.core.exceptions import PermissionDenied, ValidationError
17from django.core.urlresolvers import NoReverseMatch, resolve, reverse
18from django.forms.utils import flatatt, to_current_timezone
19from django.utils import timezone
Scott Baker69e045d2014-11-17 23:44:03 -080020from django.utils.encoding import force_text, python_2_unicode_compatible
21from django.utils.html import conditional_escape, format_html
Jeremy Mowery18cde4f2016-04-03 13:04:39 -070022from django.utils.safestring import mark_safe
Scott Bakera9b8f612015-02-26 20:42:11 -080023from django.utils.text import capfirst
Jeremy Mowery18cde4f2016-04-03 13:04:39 -070024from openstack.manager import OpenStackManager
25from suit.widgets import LinkedSelect
Scott Baker6a995352014-10-06 17:51:20 -070026
27# thread locals necessary to work around a django-suit issue
28_thread_locals = threading.local()
Scott Baker36f50872014-08-21 13:01:25 -070029
Scott Bakere5f9d7d2015-02-10 18:24:20 -080030ICON_URLS = {"success": "/static/admin/img/icon_success.gif",
Jeremy Moweryda57d402016-04-15 17:39:49 -070031 "clock": "/static/admin/img/icon_clock.gif",
32 "error": "/static/admin/img/icon_error.gif"}
33
Scott Bakere5f9d7d2015-02-10 18:24:20 -080034
35def backend_icon(obj):
36 (icon, tooltip) = obj.get_backend_icon()
Sapan Bhatia02dc8332015-12-22 18:37:47 +010037
Scott Bakere5f9d7d2015-02-10 18:24:20 -080038 icon_url = ICON_URLS.get(icon, "unknown")
39
Jeremy Moweryda57d402016-04-15 17:39:49 -070040 (exponent, last_success, last_failure, failures) = obj.get_backend_details()
Sapan Bhatia02dc8332015-12-22 18:37:47 +010041
Sapan Bhatia9f7538e2015-12-22 18:38:36 +010042 # FIXME: Need to clean this up by separating Javascript from Python
Sapan Bhatia02dc8332015-12-22 18:37:47 +010043 if (obj.pk):
44 script = """
Matteo Scandolo81c752f2016-02-11 13:12:47 -080045 <script type="text/javascript">$(document).ready(function () {$("#show_details_%d").click(function () {$("#status%d").dialog({modal: true, height: 200, width: 200 });});});</script>
Jeremy Moweryda57d402016-04-15 17:39:49 -070046 """ % (obj.pk, obj.pk)
Sapan Bhatia02dc8332015-12-22 18:37:47 +010047
48 div = """
49 <div style="display:none;" id="status%d" title="Details">
50 <p>Backoff Exponent: %r</p>
51 <p>Last Success: %r</p>
52 <p>Failures: %r</p>
53 <p>Last Failure: %r</p>
54 </div>
Jeremy Moweryda57d402016-04-15 17:39:49 -070055 """ % (obj.pk, exponent, last_success, failures, last_failure)
56 a = '<a id="show_details_%d" href="#">' % obj.pk
Sapan Bhatia02dc8332015-12-22 18:37:47 +010057 astop = '</a>'
58 else:
59 div = ''
60 script = ''
61 a = ''
62 astop = ''
63
Scott Bakere5f9d7d2015-02-10 18:24:20 -080064 if tooltip:
Sapan Bhatia02dc8332015-12-22 18:37:47 +010065 return '%s %s <span style="min-width:16px;" title="%s">%s<img src="%s">%s</span>' % (script, div, tooltip, a, icon_url, astop)
Scott Baker40c00762014-08-21 16:55:59 -070066 else:
Scott Bakere5f9d7d2015-02-10 18:24:20 -080067 return '<span style="min-width:16px;"><img src="%s"></span>' % icon_url
Scott Baker40c00762014-08-21 16:55:59 -070068
Jeremy Moweryda57d402016-04-15 17:39:49 -070069
Scott Baker40c00762014-08-21 16:55:59 -070070def backend_text(obj):
Scott Bakere5f9d7d2015-02-10 18:24:20 -080071 (icon, tooltip) = obj.get_backend_icon()
72 icon_url = ICON_URLS.get(icon, "unknown")
73
74 return '<img src="%s"> %s' % (icon_url, tooltip)
Scott Baker63d1a552014-08-21 15:19:07 -070075
Jeremy Moweryda57d402016-04-15 17:39:49 -070076
Scott Baker69e045d2014-11-17 23:44:03 -080077class UploadTextareaWidget(AdminTextareaWidget):
Jeremy Moweryda57d402016-04-15 17:39:49 -070078
Scott Baker69e045d2014-11-17 23:44:03 -080079 def render(self, name, value, attrs=None):
80 if value is None:
S.Çağlar Onurb6e63f02015-02-24 17:28:09 -050081 value = ''
82 final_attrs = self.build_attrs(attrs, name=name)
Jeremy Moweryda57d402016-04-15 17:39:49 -070083 return format_html('<input type="file" style="width: 0; height: 0" id="btn_upload_%s" onChange="uploadTextarea(event,\'%s\');">'
84 '<button onClick="$(\'#btn_upload_%s\').click(); return false;">Upload</button>'
85 '<br><textarea{0}>\r\n{1}</textarea>' % (
86 attrs["id"], attrs["id"], attrs["id"]),
S.Çağlar Onurb6e63f02015-02-24 17:28:09 -050087 flatatt(final_attrs),
Scott Baker69e045d2014-11-17 23:44:03 -080088 force_text(value))
89
Jeremy Moweryda57d402016-04-15 17:39:49 -070090
Scott Baker50ac4192015-05-11 16:36:58 -070091class SliderWidget(forms.HiddenInput):
Jeremy Moweryda57d402016-04-15 17:39:49 -070092
Scott Baker50ac4192015-05-11 16:36:58 -070093 def render(self, name, value, attrs=None):
94 if value is None:
95 value = '0'
96 final_attrs = self.build_attrs(attrs, name=name)
97 attrs = attrs or attrs[:]
98 attrs["name"] = name
99 attrs["value"] = value
100 html = """<div style="width:640px"><span id="%(id)s_label">%(value)s</span><div id="%(id)s_slider" style="float:right;width:610px;margin-top:5px"></div></div>
101 <script>
102 $(function() {
103 $("#%(id)s_slider").slider({
104 value: %(value)s,
105 slide: function(event, ui) { $("#%(id)s").val( ui.value ); $("#%(id)s_label").html(ui.value); },
106 });
107 });
108 </script>
109 <input type="hidden" id="%(id)s" name="%(name)s" value="%(value)s"></input>
110 """ % attrs
Jeremy Moweryda57d402016-04-15 17:39:49 -0700111 html = html.replace("{", "{{").replace("}", "}}")
Scott Baker50ac4192015-05-11 16:36:58 -0700112 return format_html(html,
113 flatatt(final_attrs),
114 force_text(value))
115
116
Scott Baker36f50872014-08-21 13:01:25 -0700117class PlainTextWidget(forms.HiddenInput):
118 input_type = 'hidden'
119
120 def render(self, name, value, attrs=None):
121 if value is None:
122 value = ''
123 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
124
Jeremy Moweryda57d402016-04-15 17:39:49 -0700125
Scott Baker3a8aed62015-02-27 12:21:22 -0800126class XOSAdminMixin(object):
Scott Baker1a6a3902014-10-03 00:32:37 -0700127 # call save_by_user and delete_by_user instead of save and delete
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500128
129 def has_add_permission(self, request, obj=None):
130 return (not self.__user_is_readonly(request))
Scott Baker36f50872014-08-21 13:01:25 -0700131
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500132 def has_delete_permission(self, request, obj=None):
133 return (not self.__user_is_readonly(request))
134
135 def save_model(self, request, obj, form, change):
136 if self.__user_is_readonly(request):
Scott Baker1a6a3902014-10-03 00:32:37 -0700137 # this 'if' might be redundant if save_by_user is implemented right
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500138 raise PermissionDenied
Scott Baker1a6a3902014-10-03 00:32:37 -0700139
Scott Baker5ca2a522015-12-01 10:24:01 -0800140 # reset exponential backoff
141 if hasattr(obj, "backend_register"):
142 obj.backend_register = "{}"
143
Scott Baker1a6a3902014-10-03 00:32:37 -0700144 obj.caller = request.user
145 # update openstack connection to use this site/tenant
146 obj.save_by_user(request.user)
147
148 def delete_model(self, request, obj):
149 obj.delete_by_user(request.user)
150
151 def save_formset(self, request, form, formset, change):
152 instances = formset.save(commit=False)
153 for instance in instances:
Scott Bakerf8cbac72015-07-08 18:23:17 -0700154 instance.caller = request.user
Scott Baker1a6a3902014-10-03 00:32:37 -0700155 instance.save_by_user(request.user)
156
157 # BUG in django 1.7? Objects are not deleted by formset.save if
158 # commit is False. So let's delete them ourselves.
159 #
160 # code from forms/models.py save_existing_objects()
161 try:
S.Çağlar Onurb6e63f02015-02-24 17:28:09 -0500162 forms_to_delete = formset.deleted_forms
163 except AttributeError:
Scott Baker1a6a3902014-10-03 00:32:37 -0700164 forms_to_delete = []
165 if formset.initial_forms:
166 for form in formset.initial_forms:
167 obj = form.instance
168 if form in forms_to_delete:
169 if obj.pk is None:
170 continue
171 formset.deleted_objects.append(obj)
172 obj.delete()
173
174 formset.save_m2m()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500175
Jeremy Moweryda57d402016-04-15 17:39:49 -0700176 def get_actions(self, request):
177 actions = super(XOSAdminMixin, self).get_actions(request)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500178
179 if self.__user_is_readonly(request):
180 if 'delete_selected' in actions:
181 del actions['delete_selected']
182
183 return actions
184
Scott Bakerfbe0f652015-04-03 17:44:31 -0700185 def url_for_model_changelist(self, request, model):
186 # used in add_extra_context
187 return reverse('admin:%s_%s_changelist' % (model._meta.app_label, model._meta.model_name), current_app=model._meta.app_label)
188
Scott Bakera8ef2742015-04-02 22:32:40 -0700189 def add_extra_context(self, request, extra_context):
Scott Bakerfbe38ee2015-02-27 12:12:14 -0800190 # allow custom application breadcrumb url and name
Jeremy Moweryda57d402016-04-15 17:39:49 -0700191 extra_context["custom_app_breadcrumb_url"] = getattr(
192 self, "custom_app_breadcrumb_url", None)
193 extra_context["custom_app_breadcrumb_name"] = getattr(
194 self, "custom_app_breadcrumb_name", None)
195 extra_context["custom_changelist_breadcrumb_url"] = getattr(
196 self, "custom_changelist_breadcrumb_url", None)
Scott Bakerfbe38ee2015-02-27 12:12:14 -0800197
198 # for Service admins to render their Administration page
199 if getattr(self, "extracontext_registered_admins", False):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700200 admins = []
Sapan Bhatia16be1432016-01-14 11:41:38 -0500201 for model, model_admin in admin.site._registry.items():
202 if model == self.model:
203 continue
204 if model._meta.app_label == self.model._meta.app_label:
205 info = {"app": model._meta.app_label,
206 "model": model._meta.model_name,
207 "name": capfirst(model._meta.verbose_name_plural),
Jeremy Moweryda57d402016-04-15 17:39:49 -0700208 "url": self.url_for_model_changelist(request, model)}
Sapan Bhatia16be1432016-01-14 11:41:38 -0500209 admins.append(info)
Scott Bakerfbe38ee2015-02-27 12:12:14 -0800210 extra_context["registered_admins"] = admins
211
Jeremy Moweryda57d402016-04-15 17:39:49 -0700212 def change_view(self, request, object_id, extra_context=None):
Scott Bakerfbe38ee2015-02-27 12:12:14 -0800213 extra_context = extra_context or {}
214
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500215 if self.__user_is_readonly(request):
S.Çağlar Onurb6e63f02015-02-24 17:28:09 -0500216 if not hasattr(self, "readonly_save"):
217 # save the original readonly fields
218 self.readonly_save = self.readonly_fields
219 self.inlines_save = self.inlines
220 if hasattr(self, "user_readonly_fields"):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700221 self.readonly_fields = self.user_readonly_fields
S.Çağlar Onurb6e63f02015-02-24 17:28:09 -0500222 if hasattr(self, "user_readonly_inlines"):
223 self.inlines = self.user_readonly_inlines
224 else:
225 if hasattr(self, "readonly_save"):
226 # restore the original readonly fields
227 self.readonly_fields = self.readonly_save
228 if hasattr(self, "inlines_save"):
Scott Bakeraf73e102014-04-22 22:40:07 -0700229 self.inlines = self.inlines_save
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500230
Scott Bakera8ef2742015-04-02 22:32:40 -0700231 self.add_extra_context(request, extra_context)
Scott Bakerfbe38ee2015-02-27 12:12:14 -0800232
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500233 try:
Scott Baker3a8aed62015-02-27 12:21:22 -0800234 return super(XOSAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500235 except PermissionDenied:
236 pass
Scott Bakerf41fe2c2015-07-09 19:06:08 -0700237 except ValidationError as e:
238 if (e.params is None):
239 # Validation errors that don't reference a specific field will
240 # often throw a non-descriptive 500 page to the user. The code
241 # below will cause an error message to be printed and the
242 # page refreshed instead.
243 # As a side-effect it turns the request back into a 'GET' which
244 # may wipe anything the user had changed on the page. But, at
245 # least the user gets a real error message.
246 # TODO: revisit this and display some kind of error view
247 request.method = 'GET'
248 messages.error(request, e.message)
249 return super(XOSAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
250 else:
251 raise
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500252 if request.method == 'POST':
253 raise PermissionDenied
254 request.readonly = True
Scott Baker3a8aed62015-02-27 12:21:22 -0800255 return super(XOSAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500256
Jeremy Moweryda57d402016-04-15 17:39:49 -0700257 def changelist_view(self, request, extra_context=None):
Scott Bakerfbe38ee2015-02-27 12:12:14 -0800258 extra_context = extra_context or {}
259
Scott Bakera8ef2742015-04-02 22:32:40 -0700260 self.add_extra_context(request, extra_context)
Scott Bakerfbe38ee2015-02-27 12:12:14 -0800261
Scott Baker3a8aed62015-02-27 12:21:22 -0800262 return super(XOSAdminMixin, self).changelist_view(request, extra_context=extra_context)
Scott Bakerfbe38ee2015-02-27 12:12:14 -0800263
Jeremy Moweryda57d402016-04-15 17:39:49 -0700264 def add_view(self, request, form_url='', extra_context=None):
Scott Bakerfbe0f652015-04-03 17:44:31 -0700265 extra_context = extra_context or {}
266
267 self.add_extra_context(request, extra_context)
268
Scott Baker88ac9d62015-04-14 17:01:18 -0700269 return super(XOSAdminMixin, self).add_view(request, form_url, extra_context=extra_context)
Scott Bakerfbe0f652015-04-03 17:44:31 -0700270
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500271 def __user_is_readonly(self, request):
272 return request.user.isReadOnlyUser()
273
Scott Baker40c00762014-08-21 16:55:59 -0700274 def backend_status_text(self, obj):
275 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -0700276
Scott Baker63d1a552014-08-21 15:19:07 -0700277 def backend_status_icon(self, obj):
Scott Baker40c00762014-08-21 16:55:59 -0700278 return mark_safe(backend_icon(obj))
Scott Baker63d1a552014-08-21 15:19:07 -0700279 backend_status_icon.short_description = ""
280
Scott Bakerdc4724c2014-11-05 09:05:38 -0800281 def get_form(self, request, obj=None, **kwargs):
Scott Baker9b3c1af2014-10-16 00:57:55 -0700282 # Save obj and request in thread-local storage, so suit_form_tabs can
283 # use it to determine whether we're in edit or add mode, and can
284 # determine whether the user is an admin.
285 _thread_locals.request = request
286 _thread_locals.obj = obj
Scott Baker3a8aed62015-02-27 12:21:22 -0800287 return super(XOSAdminMixin, self).get_form(request, obj, **kwargs)
Scott Baker9b3c1af2014-10-16 00:57:55 -0700288
289 def get_inline_instances(self, request, obj=None):
Scott Baker3a8aed62015-02-27 12:21:22 -0800290 inlines = super(XOSAdminMixin, self).get_inline_instances(request, obj)
Scott Baker9b3c1af2014-10-16 00:57:55 -0700291
292 # inlines that should only be shown to an admin user
293 if request.user.is_admin:
294 for inline_class in getattr(self, "admin_inlines", []):
295 inlines.append(inline_class(self.model, self.admin_site))
296
297 return inlines
298
Jeremy Moweryda57d402016-04-15 17:39:49 -0700299
Scott Baker3a8aed62015-02-27 12:21:22 -0800300class ReadOnlyAwareAdmin(XOSAdminMixin, admin.ModelAdmin):
301 # Note: Make sure XOSAdminMixin is listed before
Scott Bakerf4aeedc2014-10-03 13:10:47 -0700302 # admin.ModelAdmin in the class declaration.
303
Scott Baker1a6a3902014-10-03 00:32:37 -0700304 pass
305
Jeremy Moweryda57d402016-04-15 17:39:49 -0700306
Scott Baker67db95f2015-02-18 15:50:11 -0800307class XOSBaseAdmin(ReadOnlyAwareAdmin):
Scott Baker1a6a3902014-10-03 00:32:37 -0700308 save_on_top = False
Scott Baker36f50872014-08-21 13:01:25 -0700309
Jeremy Moweryda57d402016-04-15 17:39:49 -0700310
Scott Bakere8859f92014-05-23 12:42:40 -0700311class SingletonAdmin (ReadOnlyAwareAdmin):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700312
Siobhan Tullyce652d02013-10-08 21:52:35 -0400313 def has_add_permission(self, request):
Scott Bakere8859f92014-05-23 12:42:40 -0700314 if not super(SingletonAdmin, self).has_add_permission(request):
315 return False
316
Siobhan Tullyce652d02013-10-08 21:52:35 -0400317 num_objects = self.model.objects.count()
318 if num_objects >= 1:
319 return False
320 else:
321 return True
322
Jeremy Moweryda57d402016-04-15 17:39:49 -0700323
Scott Bakera9b8f612015-02-26 20:42:11 -0800324class ServiceAppAdmin (SingletonAdmin):
Scott Bakerfbe38ee2015-02-27 12:12:14 -0800325 extracontext_registered_admins = True
Scott Bakera9b8f612015-02-26 20:42:11 -0800326
Jeremy Moweryda57d402016-04-15 17:39:49 -0700327
Scott Baker67db95f2015-02-18 15:50:11 -0800328class XOSTabularInline(admin.TabularInline):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700329
Scott Baker86568322014-01-12 16:53:31 -0800330 def __init__(self, *args, **kwargs):
Scott Baker67db95f2015-02-18 15:50:11 -0800331 super(XOSTabularInline, self).__init__(*args, **kwargs)
Scott Baker86568322014-01-12 16:53:31 -0800332
333 # InlineModelAdmin as no get_fields() method, so in order to add
334 # the selflink field, we override __init__ to modify self.fields and
335 # self.readonly_fields.
336
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800337 self.setup_selflink()
338
Scott Baker54c9b9b2015-07-24 09:32:14 -0700339 @property
340 def selflink_model(self):
341 if hasattr(self, "selflink_fieldname"):
342 """ self.selflink_model can be defined to punch through a relation
343 to its target object. For example, in SliceNetworkInline, set
344 selflink_model = "network", and the URL will lead to the Network
345 object instead of trying to bring up a change view of the
346 SliceNetwork object.
347 """
Jeremy Moweryda57d402016-04-15 17:39:49 -0700348 return getattr(self.model, self.selflink_fieldname).field.rel.to
Scott Baker54c9b9b2015-07-24 09:32:14 -0700349 else:
350 return self.model
351
352 @property
353 def selflink_reverse_path(self):
354 return "admin:%s_change" % (self.selflink_model._meta.db_table)
355
356 def get_change_url(self, id):
Scott Baker874936e2014-01-13 18:15:34 -0800357 """ Get the URL to a change form in the admin for this model """
Jeremy Moweryda57d402016-04-15 17:39:49 -0700358 reverse_path = self.selflink_reverse_path # "admin:%s_change" % (self.selflink_model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800359 try:
Scott Baker874936e2014-01-13 18:15:34 -0800360 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800361 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -0800362 return None
363
364 return url
365
366 def setup_selflink(self):
Scott Baker54c9b9b2015-07-24 09:32:14 -0700367 url = self.get_change_url(0)
Scott Baker874936e2014-01-13 18:15:34 -0800368
369 # We don't have an admin for this object, so don't create the
370 # selflink.
371 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800372 return
373
Scott Baker874936e2014-01-13 18:15:34 -0800374 # Since we need to add "selflink" to the field list, we need to create
375 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800376 if (self.fields is None):
377 self.fields = []
378 for f in self.model._meta.fields:
379 if f.editable and f.name != "id":
380 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800381
Scott Baker874936e2014-01-13 18:15:34 -0800382 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800383
Scott Baker874936e2014-01-13 18:15:34 -0800384 if self.readonly_fields is None:
385 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800386
Scott Baker874936e2014-01-13 18:15:34 -0800387 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800388
389 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800390 if hasattr(self, "selflink_fieldname"):
391 obj = getattr(obj, self.selflink_fieldname)
392
Scott Baker86568322014-01-12 16:53:31 -0800393 if obj.id:
Scott Baker54c9b9b2015-07-24 09:32:14 -0700394 url = self.get_change_url(obj.id)
Scott Baker874936e2014-01-13 18:15:34 -0800395 return "<a href='%s'>Details</a>" % str(url)
S.Çağlar Onurb6e63f02015-02-24 17:28:09 -0500396 else:
397 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800398
399 selflink.allow_tags = True
400 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400401
Scott Bakerb27b62c2014-08-15 16:29:16 -0700402 def has_add_permission(self, request):
403 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500404
405 def get_readonly_fields(self, request, obj=None):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700406 readonly_fields = list(self.readonly_fields)[:]
407 if request.user.isReadOnlyUser():
408 for field in self.fields:
409 if not field in readonly_fields:
410 readonly_fields.append(field)
411 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500412
Scott Baker40c00762014-08-21 16:55:59 -0700413 def backend_status_icon(self, obj):
414 return mark_safe(backend_icon(obj))
415 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -0700416
Jeremy Moweryda57d402016-04-15 17:39:49 -0700417
Scott Bakerb27b62c2014-08-15 16:29:16 -0700418class PlStackGenericTabularInline(generic.GenericTabularInline):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700419
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500420 def has_add_permission(self, request):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700421 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500422
Scott Bakerb27b62c2014-08-15 16:29:16 -0700423 def get_readonly_fields(self, request, obj=None):
424 readonly_fields = list(self.readonly_fields)[:]
425 if request.user.isReadOnlyUser():
426 for field in self.fields:
427 if not field in readonly_fields:
428 readonly_fields.append(field)
429 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500430
Scott Baker40c00762014-08-21 16:55:59 -0700431 def backend_status_icon(self, obj):
432 return mark_safe(backend_icon(obj))
433 backend_status_icon.short_description = ""
434
Jeremy Moweryda57d402016-04-15 17:39:49 -0700435
Scott Baker67db95f2015-02-18 15:50:11 -0800436class ReservationInline(XOSTabularInline):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400437 model = Reservation
438 extra = 0
439 suit_classes = 'suit-tab suit-tab-reservations'
Scott Baker36f50872014-08-21 13:01:25 -0700440
Tony Mack5b061472014-02-04 07:57:10 -0500441 def queryset(self, request):
442 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400443
Jeremy Moweryda57d402016-04-15 17:39:49 -0700444
Scott Bakerb27b62c2014-08-15 16:29:16 -0700445class TagInline(PlStackGenericTabularInline):
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400446 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400447 extra = 0
448 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500449 fields = ['service', 'name', 'value']
450
451 def queryset(self, request):
452 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400453
Jeremy Moweryda57d402016-04-15 17:39:49 -0700454
Tony Mackd8515472015-08-19 11:58:18 -0400455class InstanceInline(XOSTabularInline):
456 model = Instance
Jeremy Moweryda57d402016-04-15 17:39:49 -0700457 fields = ['backend_status_icon', 'all_ips_string', 'instance_id',
458 'instance_name', 'slice', 'deployment', 'flavor', 'image', 'node']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400459 extra = 0
Scott Bakerebe89232015-09-21 14:52:15 -0700460 max_num = 0
Jeremy Moweryda57d402016-04-15 17:39:49 -0700461 readonly_fields = ['backend_status_icon', 'all_ips_string', 'instance_id',
462 'instance_name', 'slice', 'deployment', 'flavor', 'image', 'node']
Tony Mackd8515472015-08-19 11:58:18 -0400463 suit_classes = 'suit-tab suit-tab-instances'
Scott Baker74d8e622013-07-29 16:04:22 -0700464
Tony Mack5b061472014-02-04 07:57:10 -0500465 def queryset(self, request):
Tony Mackd8515472015-08-19 11:58:18 -0400466 return Instance.select_by_user(request.user)
Tony Mack5b061472014-02-04 07:57:10 -0500467
Scott Bakerb24cc932014-06-09 10:51:16 -0700468 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
Tony Mackb2dba4b2014-12-26 13:38:02 -0500469 if db_field.name == 'deployment':
Jeremy Moweryda57d402016-04-15 17:39:49 -0700470 kwargs['queryset'] = Deployment.select_by_acl(request.user).filter(
471 sitedeployments__nodes__isnull=False).distinct()
472 kwargs['widget'] = forms.Select(
473 attrs={'onChange': "instance_deployment_changed(this);"})
Tony Mackb2dba4b2014-12-26 13:38:02 -0500474 if db_field.name == 'flavor':
Jeremy Moweryda57d402016-04-15 17:39:49 -0700475 kwargs['widget'] = forms.Select(
476 attrs={'onChange': "instance_flavor_changed(this);"})
Scott Baker3b678742014-06-09 13:11:54 -0700477
Jeremy Moweryda57d402016-04-15 17:39:49 -0700478 field = super(InstanceInline, self).formfield_for_foreignkey(
479 db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700480
481 return field
482
Jeremy Moweryda57d402016-04-15 17:39:49 -0700483
Tony Mackd8515472015-08-19 11:58:18 -0400484class CordInstanceInline(XOSTabularInline):
485 model = Instance
Jeremy Moweryda57d402016-04-15 17:39:49 -0700486 fields = ['backend_status_icon', 'all_ips_string', 'instance_id',
487 'instance_name', 'slice', 'flavor', 'image', 'node']
Scott Baker25881992015-06-12 10:40:15 -0700488 extra = 0
Jeremy Moweryda57d402016-04-15 17:39:49 -0700489 readonly_fields = ['backend_status_icon',
490 'all_ips_string', 'instance_id', 'instance_name']
Tony Mackd8515472015-08-19 11:58:18 -0400491 suit_classes = 'suit-tab suit-tab-instances'
Scott Baker25881992015-06-12 10:40:15 -0700492
493 def queryset(self, request):
Tony Mackd8515472015-08-19 11:58:18 -0400494 return Instance.select_by_user(request.user)
Scott Baker25881992015-06-12 10:40:15 -0700495
496 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
497 if db_field.name == 'deployment':
498
Jeremy Moweryda57d402016-04-15 17:39:49 -0700499 kwargs['queryset'] = Deployment.select_by_acl(request.user).filter(
500 sitedeployments__nodes__isnull=False).distinct()
501 kwargs['widget'] = forms.Select(
502 attrs={'onChange': "instance_deployment_changed(this);"})
Scott Baker25881992015-06-12 10:40:15 -0700503 if db_field.name == 'flavor':
Jeremy Moweryda57d402016-04-15 17:39:49 -0700504 kwargs['widget'] = forms.Select(
505 attrs={'onChange': "instance_flavor_changed(this);"})
Scott Baker25881992015-06-12 10:40:15 -0700506
Jeremy Moweryda57d402016-04-15 17:39:49 -0700507 field = super(CordInstanceInline, self).formfield_for_foreignkey(
508 db_field, request, **kwargs)
Scott Baker25881992015-06-12 10:40:15 -0700509
510 return field
511
Jeremy Moweryda57d402016-04-15 17:39:49 -0700512
Scott Baker67db95f2015-02-18 15:50:11 -0800513class SiteInline(XOSTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400514 model = Site
515 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400516 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400517
Tony Mack5b061472014-02-04 07:57:10 -0500518 def queryset(self, request):
519 return Site.select_by_user(request.user)
520
Jeremy Moweryda57d402016-04-15 17:39:49 -0700521
Tony Mack8d60ba32015-08-04 17:53:23 -0400522class SiteHostsNodesInline(SiteInline):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700523
Tony Mack8d60ba32015-08-04 17:53:23 -0400524 def queryset(self, request):
525 return Site.select_by_user(request.user).filter(hosts_nodes=True)
526
Jeremy Moweryda57d402016-04-15 17:39:49 -0700527
Tony Mack8d60ba32015-08-04 17:53:23 -0400528class SiteHostsUsersInline(SiteInline):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700529
Tony Mack8d60ba32015-08-04 17:53:23 -0400530 def queryset(self, request):
Jeremy Moweryc2e8f162016-01-10 20:36:51 -0700531 return Site.select_by_user(request.user).filter(hosts_users=True)
Tony Mack8d60ba32015-08-04 17:53:23 -0400532
Jeremy Moweryda57d402016-04-15 17:39:49 -0700533
Scott Baker67db95f2015-02-18 15:50:11 -0800534class UserInline(XOSTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400535 model = User
Scott Baker40c00762014-08-21 16:55:59 -0700536 fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
537 readonly_fields = ('backend_status_icon', )
Siobhan Tully30fd4292013-05-10 08:59:56 -0400538 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400539 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400540
Tony Mack5b061472014-02-04 07:57:10 -0500541 def queryset(self, request):
542 return User.select_by_user(request.user)
543
Jeremy Moweryda57d402016-04-15 17:39:49 -0700544
Scott Baker67db95f2015-02-18 15:50:11 -0800545class SliceInline(XOSTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400546 model = Slice
Scott Baker40c00762014-08-21 16:55:59 -0700547 fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
548 readonly_fields = ('backend_status_icon', )
Tony Mack00d361f2013-04-28 10:28:42 -0400549 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400550 suit_classes = 'suit-tab suit-tab-slices'
551
Tony Mack5b061472014-02-04 07:57:10 -0500552 def queryset(self, request):
553 return Slice.select_by_user(request.user)
554
Jeremy Moweryda57d402016-04-15 17:39:49 -0700555
Scott Baker67db95f2015-02-18 15:50:11 -0800556class NodeInline(XOSTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400557 model = Node
558 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400559 suit_classes = 'suit-tab suit-tab-nodes'
Tony Mack68a1e422014-12-08 16:43:02 -0500560 fields = ['backend_status_icon', 'name', 'site_deployment']
Scott Baker40c00762014-08-21 16:55:59 -0700561 readonly_fields = ('backend_status_icon', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400562
Jeremy Moweryda57d402016-04-15 17:39:49 -0700563
Scott Baker67db95f2015-02-18 15:50:11 -0800564class DeploymentPrivilegeInline(XOSTabularInline):
Tony Mack68a1e422014-12-08 16:43:02 -0500565 model = DeploymentPrivilege
566 extra = 0
Tony Mack88c89902015-02-09 21:41:57 -0500567 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Jeremy Moweryda57d402016-04-15 17:39:49 -0700568 fields = ['backend_status_icon', 'user', 'role', 'deployment']
Tony Mack68a1e422014-12-08 16:43:02 -0500569 readonly_fields = ('backend_status_icon', )
570
571 def queryset(self, request):
572 return DeploymentPrivilege.select_by_user(request.user)
573
Jeremy Moweryda57d402016-04-15 17:39:49 -0700574
Scott Baker67db95f2015-02-18 15:50:11 -0800575class ControllerSiteInline(XOSTabularInline):
Tony Mack3066a952015-01-05 22:48:11 -0500576 model = ControllerSite
577 extra = 0
578 suit_classes = 'suit-tab suit-tab-admin-only'
Tony Macke2363c12015-01-06 15:08:20 -0500579 fields = ['controller', 'site', 'tenant_id']
Tony Mack3066a952015-01-05 22:48:11 -0500580
581
Scott Baker67db95f2015-02-18 15:50:11 -0800582class SitePrivilegeInline(XOSTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400583 model = SitePrivilege
584 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400585 suit_classes = 'suit-tab suit-tab-siteprivileges'
Jeremy Moweryda57d402016-04-15 17:39:49 -0700586 fields = ['backend_status_icon', 'user', 'site', 'role']
Scott Baker40c00762014-08-21 16:55:59 -0700587 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400588
Tony Mackc2835a92013-05-28 09:18:49 -0400589 def formfield_for_foreignkey(self, db_field, request, **kwargs):
590 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500591 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400592
593 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500594 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400595 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
596
Tony Mack5b061472014-02-04 07:57:10 -0500597 def queryset(self, request):
598 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400599
Tony Mack60789ac2015-05-11 20:39:32 -0400600
601class ServicePrivilegeInline(XOSTabularInline):
602 model = ServicePrivilege
603 extra = 0
604 suit_classes = 'suit-tab suit-tab-serviceprivileges'
Jeremy Moweryda57d402016-04-15 17:39:49 -0700605 fields = ['backend_status_icon', 'user', 'service', 'role']
Tony Mack60789ac2015-05-11 20:39:32 -0400606 readonly_fields = ('backend_status_icon', )
607
608 def formfield_for_foreignkey(self, db_field, request, **kwargs):
609 if db_field.name == 'service':
610 kwargs['queryset'] = Service.select_by_user(request.user)
Tony Mack5fa0f402015-05-15 06:33:45 -0400611 if db_field.name == 'user':
612 kwargs['queryset'] = User.select_by_user(request.user)
Jeremy Moweryc2e8f162016-01-10 20:36:51 -0700613 return super(ServicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mack60789ac2015-05-11 20:39:32 -0400614
615 def queryset(self, request):
616 return ServicePrivilege.select_by_user(request.user)
617
Jeremy Moweryda57d402016-04-15 17:39:49 -0700618
Scott Baker67db95f2015-02-18 15:50:11 -0800619class SiteDeploymentInline(XOSTabularInline):
Tony Mack3066a952015-01-05 22:48:11 -0500620 model = SiteDeployment
Tony Macke4be32f2014-03-11 20:45:25 -0400621 extra = 0
Tony Mackb81d5e42015-01-30 10:58:29 -0500622 suit_classes = 'suit-tab suit-tab-sitedeployments'
Jeremy Moweryda57d402016-04-15 17:39:49 -0700623 fields = ['backend_status_icon', 'deployment', 'site', 'controller']
Scott Baker40c00762014-08-21 16:55:59 -0700624 readonly_fields = ('backend_status_icon', )
Tony Macke4be32f2014-03-11 20:45:25 -0400625
626 def formfield_for_foreignkey(self, db_field, request, **kwargs):
627 if db_field.name == 'site':
628 kwargs['queryset'] = Site.select_by_user(request.user)
629
630 if db_field.name == 'deployment':
631 kwargs['queryset'] = Deployment.select_by_user(request.user)
Tony Mackd14d48f2014-12-05 17:13:08 -0500632
633 if db_field.name == 'controller':
Scott Bakerebe89232015-09-21 14:52:15 -0700634 if len(resolve(request.path).args) > 0:
Jeremy Moweryda57d402016-04-15 17:39:49 -0700635 kwargs['queryset'] = Controller.select_by_user(request.user).filter(
636 deployment__id=int(resolve(request.path).args[0]))
Tony Mackd14d48f2014-12-05 17:13:08 -0500637
Tony Mack3066a952015-01-05 22:48:11 -0500638 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Macke4be32f2014-03-11 20:45:25 -0400639
640 def queryset(self, request):
Tony Mack3066a952015-01-05 22:48:11 -0500641 return SiteDeployment.select_by_user(request.user)
Tony Macke4be32f2014-03-11 20:45:25 -0400642
643
Scott Baker67db95f2015-02-18 15:50:11 -0800644class SlicePrivilegeInline(XOSTabularInline):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400645 model = SlicePrivilege
646 suit_classes = 'suit-tab suit-tab-sliceprivileges'
647 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700648 fields = ('backend_status_icon', 'user', 'slice', 'role')
649 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400650
Tony Mackc2835a92013-05-28 09:18:49 -0400651 def formfield_for_foreignkey(self, db_field, request, **kwargs):
652 if db_field.name == 'slice':
Jeremy Moweryda57d402016-04-15 17:39:49 -0700653 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400654 if db_field.name == 'user':
Jeremy Moweryda57d402016-04-15 17:39:49 -0700655 # all users are available to be granted SlicePrivilege
656 kwargs['queryset'] = User.objects.all()
Tony Mackc2835a92013-05-28 09:18:49 -0400657
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400658 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400659
Tony Mack5b061472014-02-04 07:57:10 -0500660 def queryset(self, request):
661 return SlicePrivilege.select_by_user(request.user)
662
Jeremy Moweryda57d402016-04-15 17:39:49 -0700663
Scott Baker67db95f2015-02-18 15:50:11 -0800664class SliceNetworkInline(XOSTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700665 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800666 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700667 extra = 0
668 verbose_name = "Network Connection"
669 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400670 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker40c00762014-08-21 16:55:59 -0700671 fields = ['backend_status_icon', 'network']
672 readonly_fields = ('backend_status_icon', )
Scott Baker2170b972014-06-03 12:14:07 -0700673
Jeremy Moweryda57d402016-04-15 17:39:49 -0700674
Scott Baker67db95f2015-02-18 15:50:11 -0800675class ImageDeploymentsInline(XOSTabularInline):
Sapan Bhatia1b6bba22014-11-19 15:10:16 -0500676 model = ImageDeployments
Scott Baker2170b972014-06-03 12:14:07 -0700677 extra = 0
678 verbose_name = "Image Deployments"
679 verbose_name_plural = "Image Deployments"
680 suit_classes = 'suit-tab suit-tab-imagedeployments'
Tony Mack06c8e472014-11-30 15:53:08 -0500681 fields = ['backend_status_icon', 'image', 'deployment']
682 readonly_fields = ['backend_status_icon']
683
Jeremy Moweryda57d402016-04-15 17:39:49 -0700684
Scott Baker67db95f2015-02-18 15:50:11 -0800685class ControllerImagesInline(XOSTabularInline):
Tony Mack06c8e472014-11-30 15:53:08 -0500686 model = ControllerImages
687 extra = 0
688 verbose_name = "Controller Images"
689 verbose_name_plural = "Controller Images"
690 suit_classes = 'suit-tab suit-tab-admin-only'
691 fields = ['backend_status_icon', 'image', 'controller', 'glance_image_id']
Scott Baker40c00762014-08-21 16:55:59 -0700692 readonly_fields = ['backend_status_icon', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700693
Jeremy Moweryda57d402016-04-15 17:39:49 -0700694
Scott Baker67db95f2015-02-18 15:50:11 -0800695class SliceRoleAdmin(XOSBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400696 model = SliceRole
697 pass
698
Jeremy Moweryda57d402016-04-15 17:39:49 -0700699
Scott Baker67db95f2015-02-18 15:50:11 -0800700class SiteRoleAdmin(XOSBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400701 model = SiteRole
702 pass
703
Jeremy Moweryda57d402016-04-15 17:39:49 -0700704
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400705class DeploymentAdminForm(forms.ModelForm):
Scott Bakerde0f4412014-06-11 15:40:26 -0700706 images = forms.ModelMultipleChoiceField(
707 queryset=Image.objects.all(),
708 required=False,
709 help_text="Select which images should be deployed on this deployment",
710 widget=FilteredSelectMultiple(
711 verbose_name=('Images'), is_stacked=False
712 )
713 )
Scott Baker37b47902014-09-02 14:37:41 -0700714 flavors = forms.ModelMultipleChoiceField(
715 queryset=Flavor.objects.all(),
716 required=False,
717 help_text="Select which flavors should be usable on this deployment",
718 widget=FilteredSelectMultiple(
719 verbose_name=('Flavors'), is_stacked=False
720 )
721 )
Jeremy Moweryda57d402016-04-15 17:39:49 -0700722
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400723 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400724 model = Deployment
Jeremy Moweryda57d402016-04-15 17:39:49 -0700725 many_to_many = ["flavors", ]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400726
Siobhan Tully320b4622014-01-17 15:11:14 -0500727 def __init__(self, *args, **kwargs):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700728 request = kwargs.pop('request', None)
729 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
Siobhan Tully320b4622014-01-17 15:11:14 -0500730
Jeremy Moweryda57d402016-04-15 17:39:49 -0700731 self.fields['accessControl'].initial = "allow site " + \
732 request.user.site.name
Scott Baker5380c522014-06-06 14:49:43 -0700733
Jeremy Moweryda57d402016-04-15 17:39:49 -0700734 if self.instance and self.instance.pk:
735 self.fields['images'].initial = [
736 x.image for x in self.instance.imagedeployments.all()]
737 self.fields['flavors'].initial = self.instance.flavors.all()
Scott Bakerde0f4412014-06-11 15:40:26 -0700738
739 def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
740 """ helper function for handling m2m relations from the MultipleChoiceField
741
742 this_obj: the source object we want to link from
743
744 selected_objs: a list of destination objects we want to link to
745
746 all_relations: the full set of relations involving this_obj, including ones we don't want
747
748 relation_class: the class that implements the relation from source to dest
749
750 local_attrname: field name representing this_obj in relation_class
751
752 foreign_attrname: field name representing selected_objs in relation_class
753
754 This function will remove all newobjclass relations from this_obj
755 that are not contained in selected_objs, and add any relations that
756 are in selected_objs but don't exist in the data model yet.
757 """
758
759 existing_dest_objs = []
760 for relation in list(all_relations):
761 if getattr(relation, foreign_attrname) not in selected_objs:
Jeremy Moweryda57d402016-04-15 17:39:49 -0700762 # print "deleting site", sdp.site
Scott Bakerde0f4412014-06-11 15:40:26 -0700763 relation.delete()
764 else:
765 existing_dest_objs.append(getattr(relation, foreign_attrname))
766
767 for dest_obj in selected_objs:
768 if dest_obj not in existing_dest_objs:
Jeremy Moweryda57d402016-04-15 17:39:49 -0700769 # print "adding site", site
Scott Bakerde0f4412014-06-11 15:40:26 -0700770 kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
771 relation = relation_class(**kwargs)
772 relation.save()
Siobhan Tully320b4622014-01-17 15:11:14 -0500773
774 def save(self, commit=True):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700775 deployment = super(DeploymentAdminForm, self).save(commit=False)
Siobhan Tully320b4622014-01-17 15:11:14 -0500776
Jeremy Moweryda57d402016-04-15 17:39:49 -0700777 if commit:
778 deployment.save()
779 # this has to be done after save() if/when a deployment is first
780 # created
781 deployment.flavors = self.cleaned_data['flavors']
Siobhan Tully320b4622014-01-17 15:11:14 -0500782
Jeremy Moweryda57d402016-04-15 17:39:49 -0700783 if deployment.pk:
784 # save_m2m() doesn't seem to work with 'through' relations. So we
785 # create/destroy the through models ourselves. There has to be
786 # a better way...
Scott Bakerc9b14f72014-05-22 13:44:20 -0700787
Jeremy Moweryda57d402016-04-15 17:39:49 -0700788 self.manipulate_m2m_objs(deployment, self.cleaned_data[
789 'images'], deployment.imagedeployments.all(), ImageDeployments, "deployment", "image")
790 # manipulate_m2m_objs doesn't work for Flavor/Deployment relationship
791 # so well handle that manually here
792 for flavor in deployment.flavors.all():
793 if getattr(flavor, 'name') not in self.cleaned_data['flavors']:
794 deployment.flavors.remove(flavor)
795 for flavor in self.cleaned_data['flavors']:
796 if flavor not in deployment.flavors.all():
797 flavor.deployments.add(deployment)
Scott Bakerc9b14f72014-05-22 13:44:20 -0700798
Jeremy Moweryda57d402016-04-15 17:39:49 -0700799 self.save_m2m()
Siobhan Tully320b4622014-01-17 15:11:14 -0500800
Jeremy Moweryda57d402016-04-15 17:39:49 -0700801 return deployment
802
Siobhan Tully320b4622014-01-17 15:11:14 -0500803
Scott Bakerff5e0f32014-05-22 14:40:27 -0700804class DeploymentAdminROForm(DeploymentAdminForm):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700805
Scott Bakerff5e0f32014-05-22 14:40:27 -0700806 def save(self, commit=True):
807 raise PermissionDenied
808
Jeremy Moweryda57d402016-04-15 17:39:49 -0700809
Scott Baker67db95f2015-02-18 15:50:11 -0800810class SiteAssocInline(XOSTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500811 model = Site.deployments.through
812 extra = 0
813 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400814
Jeremy Moweryda57d402016-04-15 17:39:49 -0700815
Scott Baker67db95f2015-02-18 15:50:11 -0800816class DeploymentAdmin(XOSBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500817 model = Deployment
Jeremy Moweryda57d402016-04-15 17:39:49 -0700818 fieldList = ['backend_status_text', 'name',
819 'images', 'flavors', 'accessControl']
820 fieldsets = [
821 (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Tony Mack68a1e422014-12-08 16:43:02 -0500822 # node no longer directly connected to deployment
823 #inlines = [DeploymentPrivilegeInline,NodeInline,TagInline,ImageDeploymentsInline]
Jeremy Moweryda57d402016-04-15 17:39:49 -0700824 inlines = [DeploymentPrivilegeInline, TagInline,
825 ImageDeploymentsInline, SiteDeploymentInline]
Scott Baker63d1a552014-08-21 15:19:07 -0700826 list_display = ['backend_status_icon', 'name']
827 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700828 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500829
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500830 user_readonly_fields = ['name']
831
Tony Mack68a1e422014-12-08 16:43:02 -0500832 # nodes no longer direclty connected to deployments
Jeremy Moweryda57d402016-04-15 17:39:49 -0700833 suit_form_tabs = (('general', 'Deployment Details'),
834 ('deploymentprivileges', 'Privileges'), ('sitedeployments', 'Sites'))
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500835
Scott Bakerff5e0f32014-05-22 14:40:27 -0700836 def get_form(self, request, obj=None, **kwargs):
Tony Mackcf29cfa2015-02-05 06:13:04 -0500837 if request.user.isReadOnlyUser() or not request.user.is_admin:
Scott Bakerff5e0f32014-05-22 14:40:27 -0700838 kwargs["form"] = DeploymentAdminROForm
839 else:
840 kwargs["form"] = DeploymentAdminForm
Jeremy Moweryda57d402016-04-15 17:39:49 -0700841 adminForm = super(DeploymentAdmin, self).get_form(
842 request, obj, **kwargs)
Scott Baker5380c522014-06-06 14:49:43 -0700843
844 # from stackexchange: pass the request object into the form
845
846 class AdminFormMetaClass(adminForm):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700847
848 def __new__(cls, *args, **kwargs):
849 kwargs['request'] = request
850 return adminForm(*args, **kwargs)
Scott Baker5380c522014-06-06 14:49:43 -0700851
852 return AdminFormMetaClass
853
Jeremy Moweryda57d402016-04-15 17:39:49 -0700854
Scott Bakerecfbec72016-01-29 12:18:19 -0800855class ControllerAdminForm(forms.ModelForm):
856 backend_disabled = forms.BooleanField(required=False)
Jeremy Moweryda57d402016-04-15 17:39:49 -0700857
Scott Bakerecfbec72016-01-29 12:18:19 -0800858 class Meta:
859 model = Controller
860
861 def __init__(self, *args, **kwargs):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700862 request = kwargs.pop('request', None)
863 super(ControllerAdminForm, self).__init__(*args, **kwargs)
Scott Bakerecfbec72016-01-29 12:18:19 -0800864
Jeremy Moweryda57d402016-04-15 17:39:49 -0700865 if self.instance and self.instance.pk:
866 self.fields['backend_disabled'].initial = self.instance.get_backend_register(
867 'disabled', False)
868 else:
869 # defaults when adding new controller
870 self.fields['backend_disabled'].initial = False
Scott Bakerecfbec72016-01-29 12:18:19 -0800871
872 def save(self, commit=True):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700873 self.instance.set_backend_register(
874 "disabled", self.cleaned_data["backend_disabled"])
875 return super(ControllerAdminForm, self).save(commit=commit)
876
Scott Bakerecfbec72016-01-29 12:18:19 -0800877
Scott Baker67db95f2015-02-18 15:50:11 -0800878class ControllerAdmin(XOSBaseAdmin):
Scott Baker622bcf02015-02-10 08:40:34 -0800879 model = Controller
Jeremy Moweryda57d402016-04-15 17:39:49 -0700880 fieldList = ['deployment', 'name', 'backend_type', 'backend_disabled', 'version', 'auth_url', 'admin_user',
881 'admin_tenant', 'admin_password', 'domain', 'rabbit_host', 'rabbit_user', 'rabbit_password']
882 fieldsets = [
883 (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
884 inlines = [ControllerSiteInline] # ,ControllerImagesInline]
Tony Mackd14d48f2014-12-05 17:13:08 -0500885 list_display = ['backend_status_icon', 'name', 'version', 'backend_type']
886 list_display_links = ('backend_status_icon', 'name', )
887 readonly_fields = ('backend_status_text',)
Scott Bakerecfbec72016-01-29 12:18:19 -0800888 form = ControllerAdminForm
Tony Mackd14d48f2014-12-05 17:13:08 -0500889
890 user_readonly_fields = []
891
Tony Mack2e897fa2015-01-13 17:33:08 -0500892 def save_model(self, request, obj, form, change):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700893 # update openstack connection to use this site/tenant
Tony Mack2e897fa2015-01-13 17:33:08 -0500894 obj.save_by_user(request.user)
Jeremy Moweryc2e8f162016-01-10 20:36:51 -0700895
Tony Mack2e897fa2015-01-13 17:33:08 -0500896 def delete_model(self, request, obj):
Scott Baker622bcf02015-02-10 08:40:34 -0800897 obj.delete_by_user(request.user)
898
Tony Mack78fc1362015-02-18 11:41:36 -0500899 def queryset(self, request):
Jeremy Moweryc2e8f162016-01-10 20:36:51 -0700900 return Controller.select_by_user(request.user)
Tony Mack78fc1362015-02-18 11:41:36 -0500901
Scott Baker622bcf02015-02-10 08:40:34 -0800902 @property
903 def suit_form_tabs(self):
904 tabs = [('general', 'Controller Details'),
Jeremy Moweryda57d402016-04-15 17:39:49 -0700905 ]
Scott Baker622bcf02015-02-10 08:40:34 -0800906
Jeremy Moweryda57d402016-04-15 17:39:49 -0700907 request = getattr(_thread_locals, "request", None)
Scott Baker622bcf02015-02-10 08:40:34 -0800908 if request and request.user.is_admin:
Jeremy Moweryda57d402016-04-15 17:39:49 -0700909 tabs.append(('admin-only', 'Admin-Only'))
Scott Baker622bcf02015-02-10 08:40:34 -0800910
911 return tabs
Tony Mack2e897fa2015-01-13 17:33:08 -0500912
Jeremy Moweryda57d402016-04-15 17:39:49 -0700913
Scott Baker1e7e3482015-10-15 15:59:19 -0700914class TenantAttributeAdmin(XOSBaseAdmin):
915 model = TenantAttribute
916 list_display = ('backend_status_icon', 'tenant', 'name', 'value')
917 list_display_links = ('backend_status_icon', 'name')
918 fieldList = ('backend_status_text', 'tenant', 'name', 'value', )
Jeremy Moweryda57d402016-04-15 17:39:49 -0700919 fieldsets = [
920 (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker1e7e3482015-10-15 15:59:19 -0700921 readonly_fields = ('backend_status_text', )
922
Jeremy Moweryda57d402016-04-15 17:39:49 -0700923 suit_form_tabs = (('general', 'Tenant Root Details'),
924 )
925
Scott Baker1e7e3482015-10-15 15:59:19 -0700926
927class TenantAttrAsTabInline(XOSTabularInline):
928 model = TenantAttribute
Jeremy Moweryda57d402016-04-15 17:39:49 -0700929 fields = ['name', 'value']
Scott Baker1e7e3482015-10-15 15:59:19 -0700930 extra = 0
931 suit_classes = 'suit-tab suit-tab-tenantattrs'
932
Jeremy Moweryda57d402016-04-15 17:39:49 -0700933
Scott Bakerb3cf9212015-07-06 14:40:20 -0700934class TenantRootRoleAdmin(XOSBaseAdmin):
935 model = TenantRootRole
936 fields = ('role',)
937
Jeremy Moweryda57d402016-04-15 17:39:49 -0700938
Scott Bakerb3cf9212015-07-06 14:40:20 -0700939class TenantRootTenantInline(XOSTabularInline):
940 model = Tenant
941 fields = ['provider_service', 'subscriber_root']
942 extra = 0
943 suit_classes = 'suit-tab suit-tab-tenantroots'
944 fk_name = 'subscriber_root'
945 verbose_name = 'subscribed tenant'
946 verbose_name_plural = 'subscribed tenants'
947
Jeremy Moweryda57d402016-04-15 17:39:49 -0700948 # def queryset(self, request):
Scott Bakerb3cf9212015-07-06 14:40:20 -0700949 # qs = super(TenantRootTenantInline, self).queryset(request)
950 # return qs.filter(kind="coarse")
951
Jeremy Moweryda57d402016-04-15 17:39:49 -0700952
Scott Bakerb3cf9212015-07-06 14:40:20 -0700953class TenantRootPrivilegeInline(XOSTabularInline):
954 model = TenantRootPrivilege
955 extra = 0
956 suit_classes = 'suit-tab suit-tab-tenantrootprivileges'
957 fields = ['backend_status_icon', 'user', 'role', 'tenant_root']
958 readonly_fields = ('backend_status_icon', )
959
960 def queryset(self, request):
961 return TenantRootPrivilege.select_by_user(request.user)
962
Jeremy Moweryda57d402016-04-15 17:39:49 -0700963
Scott Bakerb3cf9212015-07-06 14:40:20 -0700964class TenantRootAdmin(XOSBaseAdmin):
965 model = TenantRoot
966 list_display = ('backend_status_icon', 'name', 'kind')
967 list_display_links = ('backend_status_icon', 'name')
968 fieldList = ('backend_status_text', 'name', 'kind', )
Jeremy Moweryda57d402016-04-15 17:39:49 -0700969 fieldsets = [
970 (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Bakerb3cf9212015-07-06 14:40:20 -0700971 inlines = (TenantRootTenantInline, TenantRootPrivilegeInline)
972 readonly_fields = ('backend_status_text', )
973
Jeremy Moweryda57d402016-04-15 17:39:49 -0700974 suit_form_tabs = (('general', 'Tenant Root Details'),
975 ('tenantroots', 'Tenancy'),
976 ('tenantrootprivileges', 'Privileges')
977 )
978
Scott Bakerb3cf9212015-07-06 14:40:20 -0700979
Jeremy Mowery18cde4f2016-04-03 13:04:39 -0700980class TenantRoleAdmin(XOSBaseAdmin):
Jeremy Mowery308e8f02016-04-15 00:05:27 -0700981 """Admin for TenantRoles."""
Jeremy Mowery18cde4f2016-04-03 13:04:39 -0700982 model = TenantRole
Jeremy Mowerya74c31d2016-04-04 22:30:44 -0700983 fields = ('role',)
Jeremy Mowery18cde4f2016-04-03 13:04:39 -0700984
Jeremy Moweryda57d402016-04-15 17:39:49 -0700985
Jeremy Mowery18cde4f2016-04-03 13:04:39 -0700986class TenantPrivilegeInline(XOSTabularInline):
Jeremy Moweryda57d402016-04-15 17:39:49 -0700987 """Inline for adding a TenantPrivilege to a Tenant."""
Jeremy Mowery18cde4f2016-04-03 13:04:39 -0700988 model = TenantPrivilege
989 extra = 0
990 suit_classes = 'suit-tab suit-tab-tenantprivileges'
991 fields = ['backend_status_icon', 'user', 'role', 'tenant']
992 readonly_fields = ('backend_status_icon', )
993
994 def queryset(self, request):
995 return TenantPrivilege.select_by_user(request.user)
996
Jeremy Moweryda57d402016-04-15 17:39:49 -0700997
Scott Bakeref58a842015-04-26 20:30:40 -0700998class ProviderTenantInline(XOSTabularInline):
999 model = CoarseTenant
1000 fields = ['provider_service', 'subscriber_service', 'connect_method']
1001 extra = 0
1002 suit_classes = 'suit-tab suit-tab-servicetenants'
1003 fk_name = 'provider_service'
1004 verbose_name = 'provided tenant'
1005 verbose_name_plural = 'provided tenants'
1006
1007 def queryset(self, request):
1008 qs = super(ProviderTenantInline, self).queryset(request)
1009 return qs.filter(kind="coarse")
1010
Jeremy Moweryda57d402016-04-15 17:39:49 -07001011
Scott Bakeref58a842015-04-26 20:30:40 -07001012class SubscriberTenantInline(XOSTabularInline):
1013 model = CoarseTenant
1014 fields = ['provider_service', 'subscriber_service', 'connect_method']
1015 extra = 0
1016 suit_classes = 'suit-tab suit-tab-servicetenants'
1017 fk_name = 'subscriber_service'
1018 verbose_name = 'subscribed tenant'
1019 verbose_name_plural = 'subscribed tenants'
1020
1021 def queryset(self, request):
1022 qs = super(SubscriberTenantInline, self).queryset(request)
1023 return qs.filter(kind="coarse")
1024
Jeremy Moweryda57d402016-04-15 17:39:49 -07001025
Scott Baker67db95f2015-02-18 15:50:11 -08001026class ServiceAttrAsTabInline(XOSTabularInline):
Siobhan Tullyce652d02013-10-08 21:52:35 -04001027 model = ServiceAttribute
Jeremy Moweryda57d402016-04-15 17:39:49 -07001028 fields = ['name', 'value']
Siobhan Tullyce652d02013-10-08 21:52:35 -04001029 extra = 0
1030 suit_classes = 'suit-tab suit-tab-serviceattrs'
1031
Jeremy Moweryda57d402016-04-15 17:39:49 -07001032
Scott Baker67db95f2015-02-18 15:50:11 -08001033class ServiceAdmin(XOSBaseAdmin):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001034 list_display = ("backend_status_icon", "name", "kind",
1035 "versionNumber", "enabled", "published")
Scott Baker63d1a552014-08-21 15:19:07 -07001036 list_display_links = ('backend_status_icon', 'name', )
Scott Baker04288cd2016-05-26 21:11:37 -07001037 fieldList = ["backend_status_text", "name", "kind", "description", "controller", "versionNumber", "enabled", "published",
Jeremy Moweryda57d402016-04-15 17:39:49 -07001038 "view_url", "icon_url", "public_key", "private_key_fn", "service_specific_attribute", "service_specific_id"]
1039 fieldsets = [
1040 (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
1041 inlines = [ServiceAttrAsTabInline, SliceInline, ProviderTenantInline,
1042 SubscriberTenantInline, ServicePrivilegeInline]
Scott Baker40c00762014-08-21 16:55:59 -07001043 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001044
1045 user_readonly_fields = fieldList
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001046
Jeremy Moweryda57d402016-04-15 17:39:49 -07001047 suit_form_tabs = (('general', 'Service Details'),
1048 ('slices', 'Slices'),
1049 ('serviceattrs', 'Additional Attributes'),
1050 ('servicetenants', 'Tenancy'),
1051 ('serviceprivileges', 'Privileges')
1052 )
1053
Scott Bakerc9117f82016-05-26 20:57:22 -07001054class ServiceControllerResourceInline(XOSTabularInline):
1055 model = ServiceControllerResource
1056 fields = ['name', 'kind', 'format', 'url']
1057 extra = 0
1058 suit_classes = 'suit-tab suit-tab-resources'
1059
1060class ServiceControllerAdmin(XOSBaseAdmin):
1061 list_display = ("backend_status_icon", "name",)
1062 list_display_links = ('backend_status_icon', 'name',)
1063 fieldList = ["backend_status_text", "name", "xos", "base_url"]
1064 fieldsets = [
1065 (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
1066 inlines = [ServiceControllerResourceInline]
1067 readonly_fields = ('backend_status_text', )
1068
1069 user_readonly_fields = fieldList
1070
1071 suit_form_tabs = (('general', 'Service Details'),
1072 ('resources', 'Resources'),
1073 )
1074
Siobhan Tullyce652d02013-10-08 21:52:35 -04001075
Scott Baker67db95f2015-02-18 15:50:11 -08001076class SiteNodeInline(XOSTabularInline):
Tony Mack4f134e62015-01-14 20:58:38 -05001077 model = Node
1078 fields = ['name', 'site_deployment']
1079 extra = 0
1080 suit_classes = 'suit-tab suit-tab-nodes'
1081
Tony Mackc2a0d312015-02-25 11:39:34 -05001082 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1083 # only display site deployments associated with this site
Jeremy Moweryda57d402016-04-15 17:39:49 -07001084 if db_field.name == 'site_deployment':
1085 kwargs['queryset'] = SiteDeployment.objects.filter(
1086 site__id=int(request.path.split('/')[-2]))
Tony Mackc2a0d312015-02-25 11:39:34 -05001087
1088 return super(SiteNodeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1089
Jeremy Moweryda57d402016-04-15 17:39:49 -07001090
Scott Baker67db95f2015-02-18 15:50:11 -08001091class SiteAdmin(XOSBaseAdmin):
Tony Mack450b6e02015-01-25 12:35:29 -05001092 #fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Jeremy Moweryda57d402016-04-15 17:39:49 -07001093 fieldList = ['backend_status_text', 'name', 'site_url', 'enabled',
1094 'login_base', 'location', 'is_public', 'hosts_nodes', 'hosts_users']
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001095 fieldsets = [
Jeremy Moweryda57d402016-04-15 17:39:49 -07001096 (None, {'fields': fieldList, 'classes': [
1097 'suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -04001098 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001099 ]
Tony Mack450b6e02015-01-25 12:35:29 -05001100 #readonly_fields = ['backend_status_text', 'accountLink']
1101 readonly_fields = ['backend_status_text']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001102
Tony Mack450b6e02015-01-25 12:35:29 -05001103 #user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Jeremy Moweryda57d402016-04-15 17:39:49 -07001104 user_readonly_fields = ['name', 'deployments', 'site_url',
1105 'enabled', 'is_public', 'login_base', 'hosts_nodes', 'hosts_users']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001106
Jeremy Moweryda57d402016-04-15 17:39:49 -07001107 list_display = ('backend_status_icon', 'name',
1108 'login_base', 'site_url', 'enabled')
Scott Baker63d1a552014-08-21 15:19:07 -07001109 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001110 filter_horizontal = ('deployments',)
Jeremy Moweryda57d402016-04-15 17:39:49 -07001111 inlines = [SliceInline, UserInline, TagInline,
1112 SitePrivilegeInline, SiteNodeInline]
Tony Mackde100182015-01-14 12:11:05 -05001113 admin_inlines = [ControllerSiteInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001114 search_fields = ['name']
1115
Tony Mack30dfcd72015-01-10 23:08:10 -05001116 @property
1117 def suit_form_tabs(self):
1118 tabs = [('general', 'Site Details'),
Jeremy Moweryda57d402016-04-15 17:39:49 -07001119 ('users', 'Users'),
1120 ('siteprivileges', 'Privileges'),
1121 ('slices', 'Slices'),
1122 ('nodes', 'Nodes'),
1123 ]
Tony Mack30dfcd72015-01-10 23:08:10 -05001124
Jeremy Moweryda57d402016-04-15 17:39:49 -07001125 request = getattr(_thread_locals, "request", None)
Tony Mack30dfcd72015-01-10 23:08:10 -05001126 if request and request.user.is_admin:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001127 tabs.append(('admin-only', 'Admin-Only'))
Tony Mack30dfcd72015-01-10 23:08:10 -05001128
1129 return tabs
1130
Tony Mack04062832013-05-10 08:22:44 -04001131 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -05001132 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -04001133
Tony Mack5cd13202013-05-01 21:48:38 -04001134 def get_formsets(self, request, obj=None):
1135 for inline in self.get_inline_instances(request, obj):
1136 # hide MyInline in the add view
1137 if obj is None:
1138 continue
Tony Mackd8515472015-08-19 11:58:18 -04001139 if isinstance(inline, InstanceInline):
Tony Mack2bd5b412013-06-11 21:05:06 -04001140 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -04001141 yield inline.get_formset(request, obj)
1142
Scott Baker545db2a2013-12-09 18:44:43 -08001143 def accountLink(self, obj):
1144 link_obj = obj.accounts.all()
1145 if link_obj:
1146 reverse_path = "admin:core_account_change"
Jeremy Moweryda57d402016-04-15 17:39:49 -07001147 url = reverse(reverse_path, args=(link_obj[0].id,))
Scott Baker545db2a2013-12-09 18:44:43 -08001148 return "<a href='%s'>%s</a>" % (url, "view billing details")
1149 else:
1150 return "no billing data for this site"
1151 accountLink.allow_tags = True
1152 accountLink.short_description = "Billing"
1153
Tony Mack332ee1d2014-02-04 15:33:45 -05001154 def save_model(self, request, obj, form, change):
1155 # update openstack connection to use this site/tenant
Jeremy Moweryc2e8f162016-01-10 20:36:51 -07001156 obj.save_by_user(request.user)
Tony Mack332ee1d2014-02-04 15:33:45 -05001157
1158 def delete_model(self, request, obj):
1159 obj.delete_by_user(request.user)
Jeremy Moweryc2e8f162016-01-10 20:36:51 -07001160
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001161
Scott Baker67db95f2015-02-18 15:50:11 -08001162class SitePrivilegeAdmin(XOSBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001163 fieldList = ['backend_status_text', 'user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -04001164 fieldsets = [
Jeremy Moweryda57d402016-04-15 17:39:49 -07001165 (None, {'fields': fieldList, 'classes': ['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -04001166 ]
Scott Baker40c00762014-08-21 16:55:59 -07001167 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -07001168 list_display = ('backend_status_icon', 'user', 'site', 'role')
1169 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001170 user_readonly_fields = fieldList
1171 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -04001172
Tony Mackc2835a92013-05-28 09:18:49 -04001173 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1174 if db_field.name == 'site':
1175 if not request.user.is_admin:
1176 # only show sites where user is an admin or pi
1177 sites = set()
1178 for site_privilege in SitePrivilege.objects.filer(user=request.user):
1179 if site_privilege.role.role_type in ['admin', 'pi']:
1180 sites.add(site_privilege.site)
1181 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
1182
1183 if db_field.name == 'user':
1184 if not request.user.is_admin:
1185 # only show users from sites where caller has admin or pi role
1186 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
Jeremy Moweryda57d402016-04-15 17:39:49 -07001187 site_privileges = SitePrivilege.objects.filter(
1188 user=request.user).filter(role__in=roles)
Tony Mackc2835a92013-05-28 09:18:49 -04001189 sites = [site_privilege.site for site_privilege in site_privileges]
1190 site_privileges = SitePrivilege.objects.filter(site__in=sites)
Jeremy Moweryda57d402016-04-15 17:39:49 -07001191 emails = [
1192 site_privilege.user.email for site_privilege in site_privileges]
Tony Mackc2835a92013-05-28 09:18:49 -04001193 users = User.objects.filter(email__in=emails)
1194 kwargs['queryset'] = users
1195
1196 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1197
Tony Mack04062832013-05-10 08:22:44 -04001198 def queryset(self, request):
1199 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -04001200 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -04001201 qs = super(SitePrivilegeAdmin, self).queryset(request)
Jeremy Moweryda57d402016-04-15 17:39:49 -07001202 # if not request.user.is_admin:
Tony Mack5b061472014-02-04 07:57:10 -05001203 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
1204 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
1205 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
1206 # sites = Site.objects.filter(login_base__in=login_bases)
1207 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -04001208 return qs
1209
Jeremy Moweryda57d402016-04-15 17:39:49 -07001210
Siobhan Tullyce652d02013-10-08 21:52:35 -04001211class SliceForm(forms.ModelForm):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001212
Siobhan Tullyce652d02013-10-08 21:52:35 -04001213 class Meta:
1214 model = Slice
1215 widgets = {
Scott Baker36f50872014-08-21 13:01:25 -07001216 'service': LinkedSelect
Siobhan Tullyce652d02013-10-08 21:52:35 -04001217 }
1218
Tony Macke75841e2014-09-29 16:10:52 -04001219 def clean(self):
1220 cleaned_data = super(SliceForm, self).clean()
1221 name = cleaned_data.get('name')
Scott Baker3cb382c2014-10-06 23:09:59 -07001222 site = cleaned_data.get('site')
Tony Mackcc9e2592014-10-22 12:54:19 -04001223 slice_id = self.instance.id
1224 if not site and slice_id:
1225 site = Slice.objects.get(id=slice_id).site
Jeremy Moweryda57d402016-04-15 17:39:49 -07001226 if (not isinstance(site, Site)):
Scott Baker3cb382c2014-10-06 23:09:59 -07001227 # previous code indicates 'site' could be a site_id and not a site?
1228 site = Slice.objects.get(id=site.id)
Tony Macke75841e2014-09-29 16:10:52 -04001229 if not name.startswith(site.login_base):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001230 raise forms.ValidationError(
1231 'slice name must begin with %s' % site.login_base)
Tony Macke75841e2014-09-29 16:10:52 -04001232 return cleaned_data
1233
Jeremy Moweryda57d402016-04-15 17:39:49 -07001234
Scott Baker67db95f2015-02-18 15:50:11 -08001235class ControllerSliceInline(XOSTabularInline):
Tony Mack3066a952015-01-05 22:48:11 -05001236 model = ControllerSlice
Scott Bakerf9f1ef42014-10-15 16:54:04 -07001237 extra = 0
Tony Mack06c8e472014-11-30 15:53:08 -05001238 verbose_name = "Controller Slices"
1239 verbose_name_plural = "Controller Slices"
Scott Bakerf9f1ef42014-10-15 16:54:04 -07001240 suit_classes = 'suit-tab suit-tab-admin-only'
Tony Mack06c8e472014-11-30 15:53:08 -05001241 fields = ['backend_status_icon', 'controller', 'tenant_id']
Jeremy Moweryda57d402016-04-15 17:39:49 -07001242 readonly_fields = ('backend_status_icon', 'controller')
1243
Scott Bakerf9f1ef42014-10-15 16:54:04 -07001244
Scott Baker67db95f2015-02-18 15:50:11 -08001245class SliceAdmin(XOSBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -04001246 form = SliceForm
Jeremy Moweryda57d402016-04-15 17:39:49 -07001247 fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled',
Scott Bakerc2cf8522016-05-19 17:54:52 -07001248 'description', 'service', 'slice_url', 'max_instances', "default_isolation", "default_image", "network"]
Jeremy Moweryda57d402016-04-15 17:39:49 -07001249 fieldsets = [('Slice Details', {'fields': fieldList, 'classes': [
1250 'suit-tab suit-tab-general']}), ]
Scott Baker40c00762014-08-21 16:55:59 -07001251 readonly_fields = ('backend_status_text', )
Jeremy Moweryda57d402016-04-15 17:39:49 -07001252 list_display = ('backend_status_icon', 'name', 'site',
1253 'serviceClass', 'slice_url', 'max_instances')
Tony Mack7d459902014-09-03 13:18:57 -04001254 list_display_links = ('backend_status_icon', 'name', )
Jeremy Moweryda57d402016-04-15 17:39:49 -07001255 normal_inlines = [SlicePrivilegeInline, InstanceInline,
1256 TagInline, ReservationInline, SliceNetworkInline]
Scott Baker25881992015-06-12 10:40:15 -07001257 inlines = normal_inlines
Tony Mack3066a952015-01-05 22:48:11 -05001258 admin_inlines = [ControllerSliceInline]
Scott Baker22beb6a2015-09-15 15:21:50 -07001259 suit_form_includes = (('slice_instance_tab.html', 'bottom', 'instances'),)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001260
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001261 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001262
Scott Bakerf9f1ef42014-10-15 16:54:04 -07001263 @property
1264 def suit_form_tabs(self):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001265 tabs = [('general', 'Slice Details'),
1266 ('slicenetworks', 'Networks'),
1267 ('sliceprivileges', 'Privileges'),
1268 ('instances', 'Instances'),
1269 #('reservations','Reservations'),
1270 ('tags', 'Tags'),
1271 ]
Scott Bakerf9f1ef42014-10-15 16:54:04 -07001272
Jeremy Moweryda57d402016-04-15 17:39:49 -07001273 request = getattr(_thread_locals, "request", None)
Scott Bakerf9f1ef42014-10-15 16:54:04 -07001274 if request and request.user.is_admin:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001275 tabs.append(('admin-only', 'Admin-Only'))
Scott Bakerf9f1ef42014-10-15 16:54:04 -07001276
1277 return tabs
Jeremy Moweryc2e8f162016-01-10 20:36:51 -07001278
Tony Mack0aa732a2014-10-22 11:54:29 -04001279 def add_view(self, request, form_url='', extra_context=None):
Scott Baker25881992015-06-12 10:40:15 -07001280 # Ugly hack for CORD
1281 self.inlines = self.normal_inlines
Tony Mack0aa732a2014-10-22 11:54:29 -04001282 # revert to default read-only fields
1283 self.readonly_fields = ('backend_status_text',)
1284 return super(SliceAdmin, self).add_view(request, form_url, extra_context=extra_context)
1285
1286 def change_view(self, request, object_id, form_url='', extra_context=None):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001287 # cannot change the site of an existing slice so make the site field
1288 # read only
Tony Mack0aa732a2014-10-22 11:54:29 -04001289 if object_id:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001290 self.readonly_fields = ('backend_status_text', 'site')
Scott Baker25881992015-06-12 10:40:15 -07001291
Tony Mack0aa732a2014-10-22 11:54:29 -04001292 return super(SliceAdmin, self).change_view(request, object_id, form_url)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001293
Scott Baker510fdbb2014-08-05 17:19:24 -07001294 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
Scott Baker510fdbb2014-08-05 17:19:24 -07001295 deployment_nodes = []
1296 for node in Node.objects.all():
Jeremy Moweryda57d402016-04-15 17:39:49 -07001297 deployment_nodes.append(
1298 (node.site_deployment.deployment.id, node.id, node.name))
Scott Baker510fdbb2014-08-05 17:19:24 -07001299
Scott Baker7a61dc42014-09-02 17:08:20 -07001300 deployment_flavors = []
1301 for flavor in Flavor.objects.all():
1302 for deployment in flavor.deployments.all():
Jeremy Moweryda57d402016-04-15 17:39:49 -07001303 deployment_flavors.append(
1304 (deployment.id, flavor.id, flavor.name))
Scott Baker7a61dc42014-09-02 17:08:20 -07001305
Tony Mack68a1e422014-12-08 16:43:02 -05001306 deployment_images = []
Scott Bakeraf36c4d2014-09-09 09:58:49 -07001307 for image in Image.objects.all():
Tony Mack68a1e422014-12-08 16:43:02 -05001308 for deployment_image in image.imagedeployments.all():
Jeremy Moweryda57d402016-04-15 17:39:49 -07001309 deployment_images.append(
1310 (deployment_image.deployment.id, image.id, image.name))
Scott Bakeraf36c4d2014-09-09 09:58:49 -07001311
Tony Mackec23b992014-09-02 21:18:45 -04001312 site_login_bases = []
1313 for site in Site.objects.all():
Scott Bakeraf36c4d2014-09-09 09:58:49 -07001314 site_login_bases.append((site.id, site.login_base))
1315
Scott Baker510fdbb2014-08-05 17:19:24 -07001316 context["deployment_nodes"] = deployment_nodes
Scott Baker7a61dc42014-09-02 17:08:20 -07001317 context["deployment_flavors"] = deployment_flavors
Scott Bakeraf36c4d2014-09-09 09:58:49 -07001318 context["deployment_images"] = deployment_images
Tony Mackec23b992014-09-02 21:18:45 -04001319 context["site_login_bases"] = site_login_bases
Scott Baker510fdbb2014-08-05 17:19:24 -07001320 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
1321
Tony Mackc2835a92013-05-28 09:18:49 -04001322 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1323 if db_field.name == 'site':
Jeremy Moweryda57d402016-04-15 17:39:49 -07001324 kwargs['queryset'] = Site.select_by_user(
1325 request.user).filter(hosts_users=True)
1326 kwargs['widget'] = forms.Select(
1327 attrs={'onChange': "update_slice_prefix(this, $($(this).closest('fieldset')[0]).find('.field-name input')[0].id)"})
Scott Baker40c00762014-08-21 16:55:59 -07001328
Tony Mackc2835a92013-05-28 09:18:49 -04001329 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1330
Tony Mack04062832013-05-10 08:22:44 -04001331 def queryset(self, request):
1332 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -05001333 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -04001334
Tony Mack79748612013-05-01 14:52:03 -04001335 def get_formsets(self, request, obj=None):
1336 for inline in self.get_inline_instances(request, obj):
1337 # hide MyInline in the add view
1338 if obj is None:
1339 continue
Tony Mackd8515472015-08-19 11:58:18 -04001340 if isinstance(inline, InstanceInline):
Tony Mack2bd5b412013-06-11 21:05:06 -04001341 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -04001342 yield inline.get_formset(request, obj)
1343
Scott Baker533c2152015-09-15 17:48:57 -07001344 def add_extra_context(self, request, extra_context):
1345 super(SliceAdmin, self).add_extra_context(request, extra_context)
1346 # set context["slice_id"] to the PK passed in the URL to this view
Jeremy Moweryda57d402016-04-15 17:39:49 -07001347 if len(request.resolver_match.args) > 0:
Scott Baker533c2152015-09-15 17:48:57 -07001348 extra_context["slice_id"] = request.resolver_match.args[0]
1349
Scott Baker25881992015-06-12 10:40:15 -07001350 def UNUSED_get_inline_instances(self, request, obj=None):
1351 # HACK for CORD to do something special on vcpe slice page
1352 # this was a good idea, but failed miserably, as something still
1353 # expects there to be a deployment field.
1354 # XXX this approach is better than clobbering self.inlines, so
1355 # try to make this work post-demo.
1356 if (obj is not None) and (obj.name == "mysite_vcpe"):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001357 cord_vcpe_inlines = [SlicePrivilegeInline, CordInstanceInline,
1358 TagInline, ReservationInline, SliceNetworkInline]
Scott Baker25881992015-06-12 10:40:15 -07001359
Jeremy Moweryda57d402016-04-15 17:39:49 -07001360 inlines = []
Scott Baker25881992015-06-12 10:40:15 -07001361 for inline_class in cord_vcpe_inlines:
1362 inlines.append(inline_class(self.model, self.admin_site))
1363 else:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001364 inlines = super(SliceAdmin, self).get_inline_instances(
1365 request, obj)
Scott Baker25881992015-06-12 10:40:15 -07001366
1367 return inlines
1368
Jeremy Moweryda57d402016-04-15 17:39:49 -07001369
Scott Baker67db95f2015-02-18 15:50:11 -08001370class SlicePrivilegeAdmin(XOSBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -04001371 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001372 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -04001373 ]
Scott Baker40c00762014-08-21 16:55:59 -07001374 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -07001375 list_display = ('backend_status_icon', 'user', 'slice', 'role')
1376 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -04001377
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001378 user_readonly_fields = ['user', 'slice', 'role']
1379 user_readonly_inlines = []
1380
Tony Mackc2835a92013-05-28 09:18:49 -04001381 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1382 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -05001383 kwargs['queryset'] = Slice.select_by_user(request.user)
Jeremy Moweryc2e8f162016-01-10 20:36:51 -07001384
Tony Mackc2835a92013-05-28 09:18:49 -04001385 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -05001386 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001387
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001388 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -04001389
Tony Mack04062832013-05-10 08:22:44 -04001390 def queryset(self, request):
1391 # admins can see all memberships. Users can only see memberships of
1392 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -05001393 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001394
Tony Mack9bcbe4f2013-04-29 08:13:27 -04001395 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -04001396 # update openstack connection to use this site/tenant
1397 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -04001398 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -04001399 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -04001400 obj.save()
1401
1402 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -04001403 # update openstack connection to use this site/tenant
1404 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -04001405 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -04001406 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -04001407 obj.delete()
1408
Jeremy Moweryda57d402016-04-15 17:39:49 -07001409
Scott Baker67db95f2015-02-18 15:50:11 -08001410class ImageAdmin(XOSBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001411
Scott Baker36f50872014-08-21 13:01:25 -07001412 fieldsets = [('Image Details',
Jeremy Moweryda57d402016-04-15 17:39:49 -07001413 {'fields': ['backend_status_text', 'name', 'kind', 'disk_format', 'container_format', 'tag', 'path'],
1414 'classes': ['suit-tab suit-tab-general']})
1415 ]
Scott Baker40c00762014-08-21 16:55:59 -07001416 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001417
Jeremy Moweryda57d402016-04-15 17:39:49 -07001418 suit_form_tabs = (('general', 'Image Details'), ('instances', 'Instances'),
1419 ('imagedeployments', 'Deployments'), ('admin-only', 'Admin-Only'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001420
Tony Mackd8515472015-08-19 11:58:18 -04001421 inlines = [InstanceInline, ControllerImagesInline]
Scott Bakerb6f99242014-06-11 11:34:44 -07001422
Jeremy Moweryda57d402016-04-15 17:39:49 -07001423 user_readonly_fields = ['name', 'disk_format',
1424 'container_format', 'tag', 'path']
Scott Bakerb27b62c2014-08-15 16:29:16 -07001425
Scott Bakerdcf9e0d2015-11-09 16:17:11 -08001426 list_display = ['backend_status_icon', 'name', 'kind']
Scott Baker63d1a552014-08-21 15:19:07 -07001427 list_display_links = ('backend_status_icon', 'name', )
1428
Jeremy Moweryda57d402016-04-15 17:39:49 -07001429
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001430class NodeForm(forms.ModelForm):
Scott Bakerb0955d92016-04-06 14:34:49 -07001431 nodelabels = forms.ModelMultipleChoiceField(
Scott Baker7c886d42016-03-04 10:35:32 -08001432 queryset=NodeLabel.objects.all(),
1433 required=False,
1434 help_text="Select which labels apply to this node",
1435 widget=FilteredSelectMultiple(
1436 verbose_name=('Labels'), is_stacked=False
1437 )
1438 )
Jeremy Moweryda57d402016-04-15 17:39:49 -07001439
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001440 class Meta:
Scott Bakerdc5db282015-09-21 15:06:38 -07001441 model = Node
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001442 widgets = {
1443 'site': LinkedSelect,
1444 'deployment': LinkedSelect
1445 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001446
Scott Baker7c886d42016-03-04 10:35:32 -08001447 def __init__(self, *args, **kwargs):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001448 request = kwargs.pop('request', None)
1449 super(NodeForm, self).__init__(*args, **kwargs)
Scott Baker7c886d42016-03-04 10:35:32 -08001450
Jeremy Moweryda57d402016-04-15 17:39:49 -07001451 if self.instance and self.instance.pk:
1452 self.fields['nodelabels'].initial = self.instance.nodelabels.all()
Scott Baker7c886d42016-03-04 10:35:32 -08001453
1454 def save(self, commit=True):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001455 node = super(NodeForm, self).save(commit=False)
Scott Baker7c886d42016-03-04 10:35:32 -08001456
Jeremy Moweryda57d402016-04-15 17:39:49 -07001457 node.nodelabels = self.cleaned_data['nodelabels']
Scott Baker7c886d42016-03-04 10:35:32 -08001458
Jeremy Moweryda57d402016-04-15 17:39:49 -07001459 if commit:
1460 node.save()
Scott Baker7c886d42016-03-04 10:35:32 -08001461
Jeremy Moweryda57d402016-04-15 17:39:49 -07001462 return node
Scott Baker7c886d42016-03-04 10:35:32 -08001463
1464
1465class NodeLabelAdmin(XOSBaseAdmin):
1466 list_display = ('name',)
1467 list_display_links = ('name', )
1468
1469 fields = ('name', )
1470
1471
Scott Baker67db95f2015-02-18 15:50:11 -08001472class NodeAdmin(XOSBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001473 form = NodeForm
Tony Mack68a1e422014-12-08 16:43:02 -05001474 list_display = ('backend_status_icon', 'name', 'site_deployment')
Scott Baker63d1a552014-08-21 15:19:07 -07001475 list_display_links = ('backend_status_icon', 'name', )
Tony Mack68a1e422014-12-08 16:43:02 -05001476 list_filter = ('site_deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001477
Jeremy Moweryda57d402016-04-15 17:39:49 -07001478 inlines = [TagInline, InstanceInline]
Scott Baker7c886d42016-03-04 10:35:32 -08001479 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name', 'site_deployment'], 'classes':['suit-tab suit-tab-details']}),
Scott Bakerb0955d92016-04-06 14:34:49 -07001480 ('Labels', {'fields': ['nodelabels'], 'classes':['suit-tab suit-tab-labels']})]
Scott Baker40c00762014-08-21 16:55:59 -07001481 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001482
Jeremy Moweryda57d402016-04-15 17:39:49 -07001483 user_readonly_fields = ['name', 'site_deployment']
1484 user_readonly_inlines = [TagInline, InstanceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001485
Jeremy Moweryda57d402016-04-15 17:39:49 -07001486 suit_form_tabs = (('details', 'Node Details'), ('instances',
1487 'Instances'), ('labels', 'Labels'), ('tags', 'Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001488
Tony Mack02b8f142015-08-04 17:32:32 -04001489 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1490 if db_field.name == 'site':
Jeremy Moweryda57d402016-04-15 17:39:49 -07001491 kwargs['queryset'] = Site.select_by_user(
1492 request.user).filter(hosts_nodes=True)
Siobhan Tully567e3e62013-06-21 18:03:16 -04001493
Jeremy Moweryda57d402016-04-15 17:39:49 -07001494 field = super(NodeAdmin, self).formfield_for_foreignkey(
1495 db_field, request, **kwargs)
Scott Bakerdc5db282015-09-21 15:06:38 -07001496
1497 return field
1498
Jeremy Moweryda57d402016-04-15 17:39:49 -07001499
Tony Mackd8515472015-08-19 11:58:18 -04001500class InstanceForm(forms.ModelForm):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001501
Tony Mackd90cdbf2013-04-16 22:48:40 -04001502 class Meta:
Tony Mackd8515472015-08-19 11:58:18 -04001503 model = Instance
Tony Mackd90cdbf2013-04-16 22:48:40 -04001504 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -04001505 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -04001506 widgets = {
1507 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -04001508 'instance_name': PlainTextWidget(),
Scott Baker9d856052015-01-19 11:32:20 -08001509 'instance_id': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001510 'slice': LinkedSelect,
Tony Mackb2dba4b2014-12-26 13:38:02 -05001511 'deployment': LinkedSelect,
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001512 'node': LinkedSelect,
1513 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -04001514 }
Tony Mackd90cdbf2013-04-16 22:48:40 -04001515
Jeremy Moweryda57d402016-04-15 17:39:49 -07001516
Scott Baker67db95f2015-02-18 15:50:11 -08001517class TagAdmin(XOSBaseAdmin):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001518 list_display = ['backend_status_icon', 'service',
1519 'name', 'value', 'content_type', 'content_object', ]
Scott Baker63d1a552014-08-21 15:19:07 -07001520 list_display_links = list_display
Jeremy Moweryda57d402016-04-15 17:39:49 -07001521 user_readonly_fields = ['service', 'name',
1522 'value', 'content_type', 'content_object', ]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001523 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -04001524
Jeremy Moweryda57d402016-04-15 17:39:49 -07001525
Tony Mack26ea0eb2015-09-01 16:06:52 +00001526class InstancePortInline(XOSTabularInline):
Tony Mackb956a5d2015-09-10 21:58:15 +00001527 fields = ['backend_status_icon', 'network', 'instance', 'ip', 'mac']
Scott Bakere553b472015-09-08 18:22:15 -07001528 readonly_fields = ("backend_status_icon", "ip", "mac")
Scott Baker5a7d9312015-08-26 09:43:33 -07001529 model = Port
Scott Bakerba12a252015-11-16 16:21:47 -08001530 #selflink_fieldname = "network"
Scott Bakerfbade882015-08-25 18:00:15 -07001531 extra = 0
1532 verbose_name_plural = "Ports"
1533 verbose_name = "Port"
1534 suit_classes = 'suit-tab suit-tab-ports'
1535
Jeremy Moweryda57d402016-04-15 17:39:49 -07001536
Tony Mackd8515472015-08-19 11:58:18 -04001537class InstanceAdmin(XOSBaseAdmin):
1538 form = InstanceForm
Tony Mackcdec0902013-04-15 00:38:49 -04001539 fieldsets = [
Jeremy Moweryda57d402016-04-15 17:39:49 -07001540 ('Instance Details', {'fields': ['backend_status_text', 'slice', 'deployment', 'isolation', 'flavor', 'image', 'node',
1541 'parent', 'all_ips_string', 'instance_id', 'instance_name', 'ssh_command', ], 'classes': ['suit-tab suit-tab-general'], }),
1542 ('Container Settings', {'fields': ['volumes'], 'classes': [
1543 'suit-tab suit-tab-container'], }),
Tony Mackcdec0902013-04-15 00:38:49 -04001544 ]
Tony Mackdb8580b2015-01-30 17:20:46 -05001545 readonly_fields = ('backend_status_text', 'ssh_command', 'all_ips_string')
Jeremy Moweryda57d402016-04-15 17:39:49 -07001546 list_display = ['backend_status_icon', 'all_ips_string', 'instance_id',
1547 'instance_name', 'isolation', 'slice', 'flavor', 'image', 'node', 'deployment']
1548 list_display_links = ('backend_status_icon',
1549 'all_ips_string', 'instance_id', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001550
Jeremy Moweryda57d402016-04-15 17:39:49 -07001551 suit_form_tabs = (('general', 'Instance Details'), ('ports', 'Ports'),
1552 ('container', 'Container Settings'), ('tags', 'Tags'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001553
Tony Mack32010062015-09-13 22:50:39 +00001554 inlines = [TagInline, InstancePortInline]
Tony Mack53106f32013-04-27 16:43:01 -04001555
Jeremy Moweryda57d402016-04-15 17:39:49 -07001556 user_readonly_fields = ['slice', 'deployment',
1557 'node', 'ip', 'instance_name', 'flavor', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001558
Scott Baker7ccc6ad2015-01-25 22:16:13 -08001559 def ssh_command(self, obj):
1560 ssh_command = obj.get_ssh_command()
1561 if ssh_command:
1562 return ssh_command
1563 else:
1564 return "(not available)"
1565
Tony Mackc2835a92013-05-28 09:18:49 -04001566 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1567 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -05001568 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001569
Tony Mackd8515472015-08-19 11:58:18 -04001570 return super(InstanceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -04001571
Tony Mack04062832013-05-10 08:22:44 -04001572 def queryset(self, request):
Tony Mackd8515472015-08-19 11:58:18 -04001573 # admins can see all instances. Users can only see instances of
Tony Mack04062832013-05-10 08:22:44 -04001574 # the slices they belong to.
Tony Mackd8515472015-08-19 11:58:18 -04001575 return Instance.select_by_user(request.user)
Tony Mack5b061472014-02-04 07:57:10 -05001576
Jeremy Moweryda57d402016-04-15 17:39:49 -07001577 def add_view(self, request, form_url='', extra_context=None):
1578 self.readonly_fields = ('backend_status_text',
1579 'ssh_command', 'all_ips_string')
1580 return super(InstanceAdmin, self).add_view(request, form_url, extra_context)
Tony Mack04062832013-05-10 08:22:44 -04001581
Scott Baker17ee7f82015-09-21 21:42:41 -07001582 def change_view(self, request, object_id, extra_context=None):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001583 self.readonly_fields = ('backend_status_text', 'ssh_command',
1584 'all_ips_string', 'deployment', 'slice', 'flavor', 'image', 'node')
1585 # for XOSAdminMixin.change_view's user_readonly_fields switching code
1586 self.readonly_save = self.readonly_fields
1587 return super(InstanceAdmin, self).change_view(request, object_id, extra_context)
Tony Mack53106f32013-04-27 16:43:01 -04001588
Scott Baker878576f2015-09-21 16:02:54 -07001589 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
1590 deployment_nodes = []
Scott Baker2a5fe502016-03-22 09:37:57 -07001591# for node in Node.objects.all():
1592 for node in Node.objects.order_by("name"):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001593 deployment_nodes.append(
1594 (node.site_deployment.deployment.id, node.id, node.name))
Scott Baker878576f2015-09-21 16:02:54 -07001595
1596 deployment_flavors = []
1597 for flavor in Flavor.objects.all():
1598 for deployment in flavor.deployments.all():
Jeremy Moweryda57d402016-04-15 17:39:49 -07001599 deployment_flavors.append(
1600 (deployment.id, flavor.id, flavor.name))
Scott Baker878576f2015-09-21 16:02:54 -07001601
1602 deployment_images = []
1603 for image in Image.objects.all():
1604 for deployment_image in image.imagedeployments.all():
Jeremy Moweryda57d402016-04-15 17:39:49 -07001605 deployment_images.append(
1606 (deployment_image.deployment.id, image.id, image.name))
Scott Baker878576f2015-09-21 16:02:54 -07001607
1608 site_login_bases = []
1609 for site in Site.objects.all():
1610 site_login_bases.append((site.id, site.login_base))
1611
1612 context["deployment_nodes"] = deployment_nodes
1613 context["deployment_flavors"] = deployment_flavors
1614 context["deployment_images"] = deployment_images
1615 context["site_login_bases"] = site_login_bases
1616 return super(InstanceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
1617
1618 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1619 if db_field.name == 'deployment':
Jeremy Moweryda57d402016-04-15 17:39:49 -07001620 kwargs['queryset'] = Deployment.select_by_acl(request.user).filter(
1621 sitedeployments__nodes__isnull=False).distinct()
1622 kwargs['widget'] = forms.Select(
1623 attrs={'onChange': "instance_deployment_changed(this);"})
Scott Baker878576f2015-09-21 16:02:54 -07001624 if db_field.name == 'flavor':
Jeremy Moweryda57d402016-04-15 17:39:49 -07001625 kwargs['widget'] = forms.Select(
1626 attrs={'onChange': "instance_flavor_changed(this);"})
Scott Baker878576f2015-09-21 16:02:54 -07001627
Jeremy Moweryda57d402016-04-15 17:39:49 -07001628 field = super(InstanceAdmin, self).formfield_for_foreignkey(
1629 db_field, request, **kwargs)
Scott Baker878576f2015-09-21 16:02:54 -07001630
1631 return field
1632
Jeremy Moweryda57d402016-04-15 17:39:49 -07001633 # def save_model(self, request, obj, form, change):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001634 # # update openstack connection to use this site/tenant
1635 # auth = request.session.get('auth', {})
1636 # auth['tenant'] = obj.slice.name
1637 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
1638 # obj.creator = request.user
1639 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -04001640
Jeremy Moweryda57d402016-04-15 17:39:49 -07001641 # def delete_model(self, request, obj):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001642 # # update openstack connection to use this site/tenant
1643 # auth = request.session.get('auth', {})
1644 # auth['tenant'] = obj.slice.name
1645 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
1646 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -04001647
Jeremy Moweryda57d402016-04-15 17:39:49 -07001648# class ContainerPortInline(XOSTabularInline):
Scott Bakerdcf9e0d2015-11-09 16:17:11 -08001649# fields = ['backend_status_icon', 'network', 'container', 'ip', 'mac', 'segmentation_id']
1650# readonly_fields = ("backend_status_icon", "ip", "mac", "segmentation_id")
1651# model = Port
1652# selflink_fieldname = "network"
1653# extra = 0
1654# verbose_name_plural = "Ports"
1655# verbose_name = "Port"
1656# suit_classes = 'suit-tab suit-tab-ports'
Scott Baker9f457d92015-10-26 19:52:10 -07001657
Jeremy Moweryda57d402016-04-15 17:39:49 -07001658# class ContainerAdmin(XOSBaseAdmin):
Scott Bakerdcf9e0d2015-11-09 16:17:11 -08001659# fieldsets = [
1660# ('Container Details', {'fields': ['backend_status_text', 'slice', 'node', 'docker_image', 'volumes', 'no_sync'], 'classes': ['suit-tab suit-tab-general'], })
1661# ]
1662# readonly_fields = ('backend_status_text', )
1663# list_display = ['backend_status_icon', 'id']
1664# list_display_links = ('backend_status_icon', 'id', )
1665#
1666# suit_form_tabs =(('general', 'Container Details'), ('ports', 'Ports'))
1667#
1668# inlines = [TagInline, ContainerPortInline]
1669#
1670# def formfield_for_foreignkey(self, db_field, request, **kwargs):
1671# if db_field.name == 'slice':
1672# kwargs['queryset'] = Slice.select_by_user(request.user)
1673#
1674# return super(ContainerAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1675#
1676# def queryset(self, request):
1677# # admins can see all instances. Users can only see instances of
1678# # the slices they belong to.
1679# return Container.select_by_user(request.user)
Scott Bakere4ea8952015-10-26 15:12:13 -07001680
Jeremy Moweryda57d402016-04-15 17:39:49 -07001681
Siobhan Tully53437282013-04-26 19:30:27 -04001682class UserCreationForm(forms.ModelForm):
1683 """A form for creating new users. Includes all the required
1684 fields, plus a repeated password."""
1685 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
Jeremy Moweryda57d402016-04-15 17:39:49 -07001686 password2 = forms.CharField(
1687 label='Password confirmation', widget=forms.PasswordInput)
Siobhan Tully53437282013-04-26 19:30:27 -04001688
1689 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -04001690 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001691 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -04001692
1693 def clean_password2(self):
1694 # Check that the two password entries match
1695 password1 = self.cleaned_data.get("password1")
1696 password2 = self.cleaned_data.get("password2")
1697 if password1 and password2 and password1 != password2:
1698 raise forms.ValidationError("Passwords don't match")
1699 return password2
1700
1701 def save(self, commit=True):
1702 # Save the provided password in hashed format
1703 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -04001704 user.password = self.cleaned_data["password1"]
Jeremy Moweryda57d402016-04-15 17:39:49 -07001705 # user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -04001706 if commit:
1707 user.save()
1708 return user
1709
Siobhan Tully567e3e62013-06-21 18:03:16 -04001710
Siobhan Tully53437282013-04-26 19:30:27 -04001711class UserChangeForm(forms.ModelForm):
1712 """A form for updating users. Includes all the fields on
1713 the user, but replaces the password field with admin's
1714 password hash display field.
1715 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -05001716 password = ReadOnlyPasswordHashField(label='Password',
Jeremy Moweryda57d402016-04-15 17:39:49 -07001717 help_text='<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -04001718
Jeremy Moweryda57d402016-04-15 17:39:49 -07001719 PROFILE_CHOICES = ((None, '------'), ('regular',
1720 'Regular user'), ('cp', 'Content Provider'))
1721 profile = forms.ChoiceField(
1722 choices=PROFILE_CHOICES, required=False, label="Quick Profile")
Scott Bakerb6043c22015-05-19 16:39:48 -07001723
Siobhan Tully53437282013-04-26 19:30:27 -04001724 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -04001725 model = User
Jeremy Moweryda57d402016-04-15 17:39:49 -07001726 widgets = {'public_key': UploadTextareaWidget, }
Siobhan Tully53437282013-04-26 19:30:27 -04001727
1728 def clean_password(self):
1729 # Regardless of what the user provides, return the initial value.
1730 # This is done here, rather than on the field, because the
1731 # field does not have access to the initial value
1732 return self.initial["password"]
1733
Scott Bakerb6043c22015-05-19 16:39:48 -07001734 def save(self, *args, **kwargs):
1735 if self.cleaned_data['profile']:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001736 self.instance.apply_profile(self.cleaned_data['profile'])
Scott Bakerb6043c22015-05-19 16:39:48 -07001737
1738 return super(UserChangeForm, self).save(*args, **kwargs)
1739
Jeremy Moweryda57d402016-04-15 17:39:49 -07001740
Scott Baker67db95f2015-02-18 15:50:11 -08001741class UserDashboardViewInline(XOSTabularInline):
Scott Baker2c3cb642014-05-19 17:55:56 -07001742 model = UserDashboardView
1743 extra = 0
1744 suit_classes = 'suit-tab suit-tab-dashboards'
1745 fields = ['user', 'dashboardView', 'order']
1746
Jeremy Moweryda57d402016-04-15 17:39:49 -07001747
Scott Baker67db95f2015-02-18 15:50:11 -08001748class ControllerUserInline(XOSTabularInline):
Tony Mack30dfcd72015-01-10 23:08:10 -05001749 model = ControllerUser
1750 extra = 0
1751 suit_classes = 'suit-tab suit-tab-admin-only'
1752 fields = ['controller', 'user', 'kuser_id']
Tony Mack30dfcd72015-01-10 23:08:10 -05001753
1754
Scott Baker3a8aed62015-02-27 12:21:22 -08001755class UserAdmin(XOSAdminMixin, UserAdmin):
1756 # Note: Make sure XOSAdminMixin is listed before
Scott Bakerf4aeedc2014-10-03 13:10:47 -07001757 # admin.ModelAdmin in the class declaration.
1758
Siobhan Tully53437282013-04-26 19:30:27 -04001759 class Meta:
1760 app_label = "core"
1761
1762 # The forms to add and change user instances
1763 form = UserChangeForm
1764 add_form = UserCreationForm
1765
1766 # The fields to be used in displaying the User model.
1767 # These override the definitions on the base UserAdmin
1768 # that reference specific fields on auth.User.
Jeremy Moweryda57d402016-04-15 17:39:49 -07001769 list_display = ('backend_status_icon', 'email',
1770 'firstname', 'lastname', 'site', 'last_login')
Scott Bakera111f442015-01-24 13:33:26 -08001771 list_display_links = ("email",)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001772 list_filter = ('site',)
Jeremy Moweryda57d402016-04-15 17:39:49 -07001773 inlines = [SlicePrivilegeInline, SitePrivilegeInline]
Tony Mack30dfcd72015-01-10 23:08:10 -05001774 admin_inlines = [ControllerUserInline]
Jeremy Moweryda57d402016-04-15 17:39:49 -07001775 fieldListLoginDetails = ['backend_status_text', 'email', 'site', 'password', 'is_active',
1776 'is_readonly', 'is_admin', 'is_appuser', 'public_key', 'login_page', 'profile']
1777 fieldListContactInfo = ['firstname', 'lastname', 'phone', 'timezone']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001778
Siobhan Tully53437282013-04-26 19:30:27 -04001779 fieldsets = (
Jeremy Moweryda57d402016-04-15 17:39:49 -07001780 ('Login Details', {'fields': ['backend_status_text', 'email', 'site', 'password', 'is_active',
1781 'is_readonly', 'is_admin', 'is_appuser', 'public_key'], 'classes': ['suit-tab suit-tab-general']}),
1782 ('Contact Information', {'fields': (
1783 'firstname', 'lastname', 'phone', 'timezone'), 'classes': ['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001784 #('Important dates', {'fields': ('last_login',)}),
1785 )
1786 add_fieldsets = (
1787 (None, {
1788 'classes': ('wide',),
Jeremy Moweryda57d402016-04-15 17:39:49 -07001789 'fields': ('site', 'email', 'firstname', 'lastname', 'is_admin', 'is_readonly', 'is_appuser', 'phone', 'public_key', 'password1', 'password2')},
1790 ),
Siobhan Tully53437282013-04-26 19:30:27 -04001791 )
Scott Baker40c00762014-08-21 16:55:59 -07001792 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001793 search_fields = ('email',)
1794 ordering = ('email',)
1795 filter_horizontal = ()
1796
Scott Baker3ca51f62014-05-23 12:05:11 -07001797 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001798
Scott Baker6a995352014-10-06 17:51:20 -07001799 @property
1800 def suit_form_tabs(self):
1801 if getattr(_thread_locals, "obj", None) is None:
1802 return []
1803 else:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001804 tabs = [('general', 'Login Details'),
1805 ('contact', 'Contact Information'),
1806 ('sliceprivileges', 'Slice Privileges'),
1807 ('siteprivileges', 'Site Privileges')]
Tony Mack30dfcd72015-01-10 23:08:10 -05001808
Jeremy Moweryda57d402016-04-15 17:39:49 -07001809 request = getattr(_thread_locals, "request", None)
Tony Mack30dfcd72015-01-10 23:08:10 -05001810 if request and request.user.is_admin:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001811 tabs.append(('admin-only', 'Admin-Only'))
Tony Mack30dfcd72015-01-10 23:08:10 -05001812
1813 return tabs
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001814
Tony Mackc2835a92013-05-28 09:18:49 -04001815 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1816 if db_field.name == 'site':
Jeremy Moweryda57d402016-04-15 17:39:49 -07001817 kwargs['queryset'] = Site.select_by_user(
1818 request.user).filter(hosts_users=True)
Tony Mackc2835a92013-05-28 09:18:49 -04001819
1820 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1821
Tony Mack5b061472014-02-04 07:57:10 -05001822 def queryset(self, request):
1823 return User.select_by_user(request.user)
1824
Tony Mackc8f443d2015-01-25 21:58:30 -05001825 def get_form(self, request, obj=None, **kwargs):
Tony Mack03b92292015-01-28 12:37:12 -05001826 # copy login details list
1827 login_details_fields = list(self.fieldListLoginDetails)
Tony Mack933b2912015-01-28 12:49:58 -05001828 if not request.user.is_admin:
Scott Baker90472612015-01-29 10:55:53 -08001829 # only admins can see 'is_admin' and 'is_readonly' fields
Tony Mack03b92292015-01-28 12:37:12 -05001830 if 'is_admin' in login_details_fields:
1831 login_details_fields.remove('is_admin')
1832 if 'is_readonly' in login_details_fields:
Scott Bakerb6043c22015-05-19 16:39:48 -07001833 login_details_fields.remove('is_readonly')
1834 if 'is_appuser' in login_details_fields:
1835 login_details_fields.remove('is_admin')
1836 if 'profile' in login_details_fields:
1837 login_details_fields.remove('profile')
Jeremy Moweryda57d402016-04-15 17:39:49 -07001838 # if len(request.user.siteprivileges.filter(role__role = 'pi')) > 0:
Scott Bakerb6043c22015-05-19 16:39:48 -07001839 # only admins and pis can change a user's site
Jeremy Moweryc2e8f162016-01-10 20:36:51 -07001840 # self.readonly_fields = ('backend_status_text', 'site')
Tony Mack03b92292015-01-28 12:37:12 -05001841 self.fieldsets = (
Jeremy Moweryda57d402016-04-15 17:39:49 -07001842 ('Login Details', {'fields': login_details_fields,
1843 'classes': ['suit-tab suit-tab-general']}),
1844 ('Contact Information', {
1845 'fields': self.fieldListContactInfo, 'classes': ['suit-tab suit-tab-contact']}),
Tony Mack03b92292015-01-28 12:37:12 -05001846 )
Jeremy Moweryc2e8f162016-01-10 20:36:51 -07001847 return super(UserAdmin, self).get_form(request, obj, **kwargs)
Tony Mackc8f443d2015-01-25 21:58:30 -05001848
Jeremy Moweryda57d402016-04-15 17:39:49 -07001849
Scott Baker67db95f2015-02-18 15:50:11 -08001850class ControllerDashboardViewInline(XOSTabularInline):
Scott Bakerf2c0c512014-12-22 17:35:34 -08001851 model = ControllerDashboardView
Scott Baker786a9c12014-12-19 16:41:12 -08001852 extra = 0
1853 fields = ["controller", "url"]
1854 suit_classes = 'suit-tab suit-tab-controllers'
1855
Jeremy Moweryda57d402016-04-15 17:39:49 -07001856
Scott Baker67db95f2015-02-18 15:50:11 -08001857class DashboardViewAdmin(XOSBaseAdmin):
Scott Baker2c3cb642014-05-19 17:55:56 -07001858 fieldsets = [('Dashboard View Details',
Jeremy Moweryda57d402016-04-15 17:39:49 -07001859 {'fields': ['backend_status_text', 'name', 'url', 'enabled', 'deployments'],
1860 'classes': ['suit-tab suit-tab-general']})
1861 ]
Scott Baker2c44e6e2015-01-18 16:46:26 -08001862 list_display = ["name", "enabled", "url"]
Scott Baker40c00762014-08-21 16:55:59 -07001863 readonly_fields = ('backend_status_text', )
Scott Bakerf2c0c512014-12-22 17:35:34 -08001864 inlines = [ControllerDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001865
Jeremy Moweryda57d402016-04-15 17:39:49 -07001866 suit_form_tabs = (('general', 'Dashboard View Details'),
1867 ('controllers', 'Per-controller Dashboard Details'))
1868
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001869
Scott Baker67db95f2015-02-18 15:50:11 -08001870class ServiceResourceInline(XOSTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001871 model = ServiceResource
1872 extra = 0
1873
Jeremy Moweryda57d402016-04-15 17:39:49 -07001874
Scott Baker67db95f2015-02-18 15:50:11 -08001875class ServiceClassAdmin(XOSBaseAdmin):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001876 list_display = ('backend_status_icon', 'name',
1877 'commitment', 'membershipFee')
Scott Baker63d1a552014-08-21 15:19:07 -07001878 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001879 inlines = [ServiceResourceInline]
1880
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001881 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1882 user_readonly_inlines = []
1883
Jeremy Moweryda57d402016-04-15 17:39:49 -07001884
Scott Baker67db95f2015-02-18 15:50:11 -08001885class ReservedResourceInline(XOSTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001886 model = ReservedResource
1887 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001888 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001889
1890 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001891 field = super(ReservedResourceInline, self).formfield_for_foreignkey(
1892 db_field, request, **kwargs)
Scott Baker133c9212013-05-17 09:09:11 -07001893
1894 if db_field.name == 'resource':
1895 # restrict resources to those that the slice's service class allows
1896 if request._slice is not None:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001897 field.queryset = field.queryset.filter(
1898 serviceClass=request._slice.serviceClass, calendarReservable=True)
Scott Baker133c9212013-05-17 09:09:11 -07001899 if len(field.queryset) > 0:
1900 field.initial = field.queryset.all()[0]
S.Çağlar Onurb6e63f02015-02-24 17:28:09 -05001901 else:
1902 field.queryset = field.queryset.none()
Tony Mackd8515472015-08-19 11:58:18 -04001903 elif db_field.name == 'instance':
1904 # restrict instances to those that belong to the slice
S.Çağlar Onurb6e63f02015-02-24 17:28:09 -05001905 if request._slice is not None:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001906 field.queryset = field.queryset.filter(slice=request._slice)
Scott Baker133c9212013-05-17 09:09:11 -07001907 else:
S.Çağlar Onurb6e63f02015-02-24 17:28:09 -05001908 field.queryset = field.queryset.none()
1909
Scott Baker133c9212013-05-17 09:09:11 -07001910 return field
1911
Tony Mack5b061472014-02-04 07:57:10 -05001912 def queryset(self, request):
1913 return ReservedResource.select_by_user(request.user)
1914
Jeremy Moweryda57d402016-04-15 17:39:49 -07001915
Scott Baker133c9212013-05-17 09:09:11 -07001916class ReservationChangeForm(forms.ModelForm):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001917
Scott Baker133c9212013-05-17 09:09:11 -07001918 class Meta:
1919 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001920 widgets = {
Jeremy Moweryda57d402016-04-15 17:39:49 -07001921 'slice': LinkedSelect
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001922 }
Scott Baker133c9212013-05-17 09:09:11 -07001923
Jeremy Moweryda57d402016-04-15 17:39:49 -07001924
Scott Baker133c9212013-05-17 09:09:11 -07001925class ReservationAddForm(forms.ModelForm):
Jeremy Moweryda57d402016-04-15 17:39:49 -07001926 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(
1927 attrs={"onChange": "document.getElementById('id_refresh').value=1; submit()"}))
Scott Baker133c9212013-05-17 09:09:11 -07001928 refresh = forms.CharField(widget=forms.HiddenInput())
1929
1930 class Media:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001931 css = {'all': ('xos.css',)} # .field-refresh { display: none; }
Scott Baker133c9212013-05-17 09:09:11 -07001932
1933 def clean_slice(self):
1934 slice = self.cleaned_data.get("slice")
Jeremy Moweryda57d402016-04-15 17:39:49 -07001935 x = ServiceResource.objects.filter(
1936 serviceClass=slice.serviceClass, calendarReservable=True)
Scott Baker133c9212013-05-17 09:09:11 -07001937 if len(x) == 0:
Jeremy Moweryda57d402016-04-15 17:39:49 -07001938 raise forms.ValidationError(
1939 "The slice you selected does not have a service class that allows reservations")
Scott Baker133c9212013-05-17 09:09:11 -07001940 return slice
1941
1942 class Meta:
1943 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001944 widgets = {
Jeremy Moweryda57d402016-04-15 17:39:49 -07001945 'slice': LinkedSelect
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001946 }
1947
Scott Baker133c9212013-05-17 09:09:11 -07001948
1949class ReservationAddRefreshForm(ReservationAddForm):
1950 """ This form is displayed when the Reservation Form receives an update
1951 from the Slice dropdown onChange handler. It doesn't validate the
1952 data and doesn't save the data. This will cause the form to be
1953 redrawn.
1954 """
1955
Scott Baker8737e5f2013-05-17 09:35:32 -07001956 """ don't validate anything other than slice """
1957 dont_validate_fields = ("startTime", "duration")
1958
Scott Baker133c9212013-05-17 09:09:11 -07001959 def full_clean(self):
1960 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001961
1962 for fieldname in self.dont_validate_fields:
1963 if fieldname in self._errors:
1964 del self._errors[fieldname]
1965
Scott Baker133c9212013-05-17 09:09:11 -07001966 return result
1967
1968 """ don't save anything """
Jeremy Moweryda57d402016-04-15 17:39:49 -07001969
Scott Baker133c9212013-05-17 09:09:11 -07001970 def is_valid(self):
1971 return False
1972
Jeremy Moweryda57d402016-04-15 17:39:49 -07001973
Scott Baker67db95f2015-02-18 15:50:11 -08001974class ReservationAdmin(XOSBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001975 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Jeremy Moweryda57d402016-04-15 17:39:49 -07001976 fieldsets = [('Reservation Details', {
1977 'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001978 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001979 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001980 form = ReservationAddForm
1981
Jeremy Moweryda57d402016-04-15 17:39:49 -07001982 suit_form_tabs = (('general', 'Reservation Details'),
1983 ('reservedresources', 'Reserved Resources'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001984
1985 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001986 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001987
Scott Baker133c9212013-05-17 09:09:11 -07001988 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001989 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001990 request._refresh = False
1991 request._slice = None
1992 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001993 # "refresh" will be set to "1" if the form was submitted due to
1994 # a change in the Slice dropdown.
Jeremy Moweryda57d402016-04-15 17:39:49 -07001995 if request.POST.get("refresh", "1") == "1":
Scott Baker133c9212013-05-17 09:09:11 -07001996 request._refresh = True
1997 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001998
1999 # Keep track of the slice that was selected, so the
2000 # reservedResource inline can filter items for the slice.
Jeremy Moweryda57d402016-04-15 17:39:49 -07002001 request._slice = request.POST.get("slice", None)
Scott Baker133c9212013-05-17 09:09:11 -07002002 if (request._slice is not None):
2003 request._slice = Slice.objects.get(id=request._slice)
2004
Jeremy Moweryda57d402016-04-15 17:39:49 -07002005 result = super(ReservationAdmin, self).add_view(
2006 request, form_url, extra_context)
Scott Baker133c9212013-05-17 09:09:11 -07002007 return result
2008
Jeremy Moweryda57d402016-04-15 17:39:49 -07002009 def changelist_view(self, request, extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07002010 timezone.activate(request.user.timezone)
2011 return super(ReservationAdmin, self).changelist_view(request, extra_context)
2012
Scott Baker133c9212013-05-17 09:09:11 -07002013 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04002014 request._obj_ = obj
2015 if obj is not None:
2016 # For changes, set request._slice to the slice already set in the
2017 # object.
2018 request._slice = obj.slice
2019 self.form = ReservationChangeForm
2020 else:
2021 if getattr(request, "_refresh", False):
2022 self.form = ReservationAddRefreshForm
2023 else:
2024 self.form = ReservationAddForm
2025 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
2026
Scott Baker133c9212013-05-17 09:09:11 -07002027 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04002028 if (obj is not None):
2029 # Prevent slice from being changed after the reservation has been
2030 # created.
2031 return ['slice']
2032 else:
Scott Baker133c9212013-05-17 09:09:11 -07002033 return []
Scott Baker3de3e372013-05-10 16:50:44 -07002034
Tony Mack5b061472014-02-04 07:57:10 -05002035 def queryset(self, request):
2036 return Reservation.select_by_user(request.user)
2037
Jeremy Moweryda57d402016-04-15 17:39:49 -07002038
Scott Baker67db95f2015-02-18 15:50:11 -08002039class NetworkParameterTypeAdmin(XOSBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07002040 list_display = ("backend_status_icon", "name", )
2041 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002042 user_readonly_fields = ['name']
2043 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07002044
Jeremy Moweryda57d402016-04-15 17:39:49 -07002045
Scott Baker67db95f2015-02-18 15:50:11 -08002046class RouterAdmin(XOSBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07002047 list_display = ("backend_status_icon", "name", )
2048 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002049 user_readonly_fields = ['name']
2050 user_readonly_inlines = []
2051
Jeremy Moweryda57d402016-04-15 17:39:49 -07002052
Scott Baker67db95f2015-02-18 15:50:11 -08002053class RouterInline(XOSTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07002054 model = Router.networks.through
2055 extra = 0
2056 verbose_name_plural = "Routers"
2057 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04002058 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07002059
Jeremy Moweryda57d402016-04-15 17:39:49 -07002060
Scott Bakerb27b62c2014-08-15 16:29:16 -07002061class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002062 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07002063 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002064 verbose_name_plural = "Parameters"
2065 verbose_name = "Parameter"
2066 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07002067 fields = ['backend_status_icon', 'parameter', 'value']
2068 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002069
Jeremy Moweryda57d402016-04-15 17:39:49 -07002070
Scott Bakerfbade882015-08-25 18:00:15 -07002071class NetworkPortInline(XOSTabularInline):
Scott Bakerdcf9e0d2015-11-09 16:17:11 -08002072 fields = ['backend_status_icon', 'network', 'instance', 'ip', 'mac']
Scott Bakere553b472015-09-08 18:22:15 -07002073 readonly_fields = ("backend_status_icon", "ip", "mac")
Scott Baker5a7d9312015-08-26 09:43:33 -07002074 model = Port
Scott Baker17ff0172015-11-16 13:43:38 -08002075 #selflink_fieldname = "instance"
Scott Baker74d8e622013-07-29 16:04:22 -07002076 extra = 0
Scott Baker5f1068a2015-08-25 17:11:30 -07002077 verbose_name_plural = "Ports"
2078 verbose_name = "Port"
2079 suit_classes = 'suit-tab suit-tab-ports'
Scott Baker74d8e622013-07-29 16:04:22 -07002080
Jeremy Moweryda57d402016-04-15 17:39:49 -07002081
Scott Baker67db95f2015-02-18 15:50:11 -08002082class NetworkSlicesInline(XOSTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07002083 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08002084 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07002085 extra = 0
2086 verbose_name_plural = "Slices"
2087 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04002088 suit_classes = 'suit-tab suit-tab-networkslices'
Jeremy Moweryda57d402016-04-15 17:39:49 -07002089 fields = ['backend_status_icon', 'network', 'slice']
Scott Baker40c00762014-08-21 16:55:59 -07002090 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07002091
Jeremy Moweryda57d402016-04-15 17:39:49 -07002092
Scott Baker67db95f2015-02-18 15:50:11 -08002093class ControllerNetworkInline(XOSTabularInline):
Tony Mack3066a952015-01-05 22:48:11 -05002094 model = ControllerNetwork
Scott Baker8806cdf2014-10-17 16:27:23 -07002095 extra = 0
Tony Mack06c8e472014-11-30 15:53:08 -05002096 verbose_name_plural = "Controller Networks"
2097 verbose_name = "Controller Network"
Scott Baker8806cdf2014-10-17 16:27:23 -07002098 suit_classes = 'suit-tab suit-tab-admin-only'
Jeremy Moweryda57d402016-04-15 17:39:49 -07002099 fields = ['backend_status_icon', 'controller',
2100 'net_id', 'subnet_id', 'subnet']
Scott Baker8806cdf2014-10-17 16:27:23 -07002101 readonly_fields = ('backend_status_icon', )
2102
Jeremy Moweryda57d402016-04-15 17:39:49 -07002103
Scott Baker69e045d2014-11-17 23:44:03 -08002104class NetworkForm(forms.ModelForm):
Jeremy Moweryda57d402016-04-15 17:39:49 -07002105
Scott Baker69e045d2014-11-17 23:44:03 -08002106 class Meta:
2107 model = Network
2108 widgets = {
2109 'topologyParameters': UploadTextareaWidget,
2110 'controllerParameters': UploadTextareaWidget,
2111 }
2112
Jeremy Moweryda57d402016-04-15 17:39:49 -07002113
Scott Baker67db95f2015-02-18 15:50:11 -08002114class NetworkAdmin(XOSBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07002115 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
2116 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07002117 readonly_fields = ("subnet", )
Jeremy Moweryda57d402016-04-15 17:39:49 -07002118 inlines = [NetworkParameterInline, NetworkPortInline,
2119 NetworkSlicesInline, RouterInline]
Tony Mack3066a952015-01-05 22:48:11 -05002120 admin_inlines = [ControllerNetworkInline]
Scott Baker74d8e622013-07-29 16:04:22 -07002121
Jeremy Moweryda57d402016-04-15 17:39:49 -07002122 form = NetworkForm
Scott Baker69e045d2014-11-17 23:44:03 -08002123
Siobhan Tully2d95e482013-09-06 10:56:06 -04002124 fieldsets = [
Jeremy Moweryda57d402016-04-15 17:39:49 -07002125 (None, {'fields': ['backend_status_text', 'name', 'template', 'ports', 'labels',
2126 'owner', 'guaranteed_bandwidth', 'permit_all_slices',
2127 'permitted_slices', 'network_id', 'router_id', 'subnet_id',
Scott Baker3789cb22015-08-21 16:40:53 -07002128 'subnet', 'autoconnect'],
Scott Baker3e28dd72014-11-17 16:04:45 -08002129 'classes':['suit-tab suit-tab-general']}),
Scott Baker549aa252015-01-03 12:29:29 -08002130 (None, {'fields': ['topology_parameters', 'controller_url', 'controller_parameters'],
Scott Baker3e28dd72014-11-17 16:04:45 -08002131 'classes':['suit-tab suit-tab-sdn']}),
Jeremy Moweryda57d402016-04-15 17:39:49 -07002132 ]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002133
Scott Baker40c00762014-08-21 16:55:59 -07002134 readonly_fields = ('backend_status_text', )
Jeremy Moweryda57d402016-04-15 17:39:49 -07002135 user_readonly_fields = ['name', 'template', 'ports', 'labels', 'owner', 'guaranteed_bandwidth',
2136 'permit_all_slices', 'permitted_slices', 'network_id', 'router_id',
2137 'subnet_id', 'subnet', 'autoconnect']
Siobhan Tully2d95e482013-09-06 10:56:06 -04002138
Scott Baker8806cdf2014-10-17 16:27:23 -07002139 @property
2140 def suit_form_tabs(self):
Jeremy Moweryda57d402016-04-15 17:39:49 -07002141 tabs = [('general', 'Network Details'),
2142 ('sdn', 'SDN Configuration'),
2143 ('netparams', 'Parameters'),
2144 ('ports', 'Ports'),
2145 ('networkslices', 'Slices'),
2146 ('routers', 'Routers'),
2147 ]
Scott Baker8806cdf2014-10-17 16:27:23 -07002148
Jeremy Moweryda57d402016-04-15 17:39:49 -07002149 request = getattr(_thread_locals, "request", None)
Scott Baker8806cdf2014-10-17 16:27:23 -07002150 if request and request.user.is_admin:
Jeremy Moweryda57d402016-04-15 17:39:49 -07002151 tabs.append(('admin-only', 'Admin-Only'))
Scott Baker8806cdf2014-10-17 16:27:23 -07002152
2153 return tabs
2154
2155
Scott Baker67db95f2015-02-18 15:50:11 -08002156class NetworkTemplateAdmin(XOSBaseAdmin):
Jeremy Moweryda57d402016-04-15 17:39:49 -07002157 list_display = ("backend_status_icon", "name",
2158 "guaranteed_bandwidth", "visibility")
Scott Baker63d1a552014-08-21 15:19:07 -07002159 list_display_links = ('backend_status_icon', 'name', )
Scott Baker369f9b92015-01-03 12:03:38 -08002160 user_readonly_fields = ["name", "guaranteed_bandwidth", "visibility"]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002161 user_readonly_inlines = []
Jeremy Moweryda57d402016-04-15 17:39:49 -07002162 inlines = [NetworkParameterInline, ]
Scott Baker3e28dd72014-11-17 16:04:45 -08002163 fieldsets = [
Scott Bakera36a9902015-12-09 15:44:55 -08002164 (None, {'fields': ['name', 'description', 'guaranteed_bandwidth', 'visibility', 'translation', 'access', 'shared_network_name', 'shared_network_id', 'topology_kind', 'controller_kind'],
Jeremy Moweryda57d402016-04-15 17:39:49 -07002165 'classes':['suit-tab suit-tab-general']}), ]
2166 suit_form_tabs = (('general', 'Network Template Details'),
2167 ('netparams', 'Parameters'))
2168
Scott Baker74d8e622013-07-29 16:04:22 -07002169
Scott Baker17ff0172015-11-16 13:43:38 -08002170class PortAdmin(XOSBaseAdmin):
Scott Baker8a351272016-02-15 17:03:20 -08002171 list_display = ("backend_status_icon", "id", "ip")
Scott Baker17ff0172015-11-16 13:43:38 -08002172 list_display_links = ('backend_status_icon', 'id')
2173 readonly_fields = ("subnet", )
2174 inlines = [NetworkParameterInline]
2175
2176 fieldsets = [
2177 (None, {'fields': ['backend_status_text', 'network', 'instance', 'ip', 'port_id', 'mac'],
2178 'classes':['suit-tab suit-tab-general']}),
Jeremy Moweryda57d402016-04-15 17:39:49 -07002179 ]
Scott Baker17ff0172015-11-16 13:43:38 -08002180
2181 readonly_fields = ('backend_status_text', )
2182 suit_form_tabs = (('general', 'Port Details'), ('netparams', 'Parameters'))
2183
Jeremy Moweryda57d402016-04-15 17:39:49 -07002184
Scott Baker67db95f2015-02-18 15:50:11 -08002185class FlavorAdmin(XOSBaseAdmin):
Jeremy Moweryda57d402016-04-15 17:39:49 -07002186 list_display = ("backend_status_icon", "name",
2187 "flavor", "order", "default")
Scott Baker37b47902014-09-02 14:37:41 -07002188 list_display_links = ("backend_status_icon", "name")
2189 user_readonly_fields = ("name", "flavor")
2190 fields = ("name", "description", "flavor", "order", "default")
2191
Tony Mack31c2b8f2013-04-26 20:01:42 -04002192# register a signal that caches the user's credentials when they log in
Jeremy Moweryda57d402016-04-15 17:39:49 -07002193
2194
Tony Mack31c2b8f2013-04-26 20:01:42 -04002195def cache_credentials(sender, user, request, **kwds):
2196 auth = {'username': request.POST['username'],
2197 'password': request.POST['password']}
2198 request.session['auth'] = auth
2199user_logged_in.connect(cache_credentials)
2200
Jeremy Moweryda57d402016-04-15 17:39:49 -07002201
Scott Baker15cddfa2013-12-09 13:45:19 -08002202def dollar_field(fieldName, short_description):
2203 def newFunc(self, obj):
2204 try:
Jeremy Moweryda57d402016-04-15 17:39:49 -07002205 x = "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
Scott Baker15cddfa2013-12-09 13:45:19 -08002206 except:
Jeremy Moweryda57d402016-04-15 17:39:49 -07002207 x = getattr(obj, fieldName, 0.0)
Scott Baker15cddfa2013-12-09 13:45:19 -08002208 return x
2209 newFunc.short_description = short_description
2210 return newFunc
2211
Jeremy Moweryda57d402016-04-15 17:39:49 -07002212
Scott Baker15cddfa2013-12-09 13:45:19 -08002213def right_dollar_field(fieldName, short_description):
2214 def newFunc(self, obj):
2215 try:
2216 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
Jeremy Moweryda57d402016-04-15 17:39:49 -07002217 x = '<div align=right>$ %0.2f</div>' % float(
2218 getattr(obj, fieldName, 0.0))
Scott Baker15cddfa2013-12-09 13:45:19 -08002219 except:
Jeremy Moweryda57d402016-04-15 17:39:49 -07002220 x = getattr(obj, fieldName, 0.0)
Scott Baker15cddfa2013-12-09 13:45:19 -08002221 return x
2222 newFunc.short_description = short_description
2223 newFunc.allow_tags = True
2224 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08002225
Jeremy Moweryda57d402016-04-15 17:39:49 -07002226
Scott Baker67db95f2015-02-18 15:50:11 -08002227class InvoiceChargeInline(XOSTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08002228 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08002229 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08002230 verbose_name_plural = "Charges"
2231 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002232 exclude = ['account']
Jeremy Moweryda57d402016-04-15 17:39:49 -07002233 fields = ["date", "kind", "state", "object",
2234 "coreHours", "dollar_amount", "slice"]
2235 readonly_fields = ["date", "kind", "state",
2236 "object", "coreHours", "dollar_amount", "slice"]
Scott Baker9cb88a22013-12-09 18:56:00 -08002237 can_delete = False
2238 max_num = 0
2239
2240 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08002241
Jeremy Moweryda57d402016-04-15 17:39:49 -07002242
Scott Baker43105042013-12-06 23:23:36 -08002243class InvoiceAdmin(admin.ModelAdmin):
2244 list_display = ("date", "account")
2245
2246 inlines = [InvoiceChargeInline]
2247
Scott Baker9cb88a22013-12-09 18:56:00 -08002248 fields = ["date", "account", "dollar_amount"]
2249 readonly_fields = ["date", "account", "dollar_amount"]
2250
2251 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08002252
Jeremy Moweryda57d402016-04-15 17:39:49 -07002253
Scott Baker67db95f2015-02-18 15:50:11 -08002254class InvoiceInline(XOSTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08002255 model = Invoice
2256 extra = 0
2257 verbose_name_plural = "Invoices"
2258 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08002259 fields = ["date", "dollar_amount"]
2260 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08002261 suit_classes = 'suit-tab suit-tab-accountinvoice'
Jeremy Moweryda57d402016-04-15 17:39:49 -07002262 can_delete = False
2263 max_num = 0
Scott Baker15cddfa2013-12-09 13:45:19 -08002264
2265 dollar_amount = right_dollar_field("amount", "Amount")
2266
Jeremy Moweryda57d402016-04-15 17:39:49 -07002267
Scott Baker67db95f2015-02-18 15:50:11 -08002268class PendingChargeInline(XOSTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08002269 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08002270 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08002271 verbose_name_plural = "Charges"
2272 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002273 exclude = ["invoice"]
Jeremy Moweryda57d402016-04-15 17:39:49 -07002274 fields = ["date", "kind", "state", "object",
2275 "coreHours", "dollar_amount", "slice"]
2276 readonly_fields = ["date", "kind", "state",
2277 "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08002278 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Jeremy Moweryda57d402016-04-15 17:39:49 -07002279 can_delete = False
2280 max_num = 0
Scott Baker43105042013-12-06 23:23:36 -08002281
2282 def queryset(self, request):
2283 qs = super(PendingChargeInline, self).queryset(request)
2284 qs = qs.filter(state="pending")
2285 return qs
2286
Scott Baker15cddfa2013-12-09 13:45:19 -08002287 dollar_amount = right_dollar_field("amount", "Amount")
2288
Jeremy Moweryda57d402016-04-15 17:39:49 -07002289
Scott Baker67db95f2015-02-18 15:50:11 -08002290class PaymentInline(XOSTabularInline):
Jeremy Moweryda57d402016-04-15 17:39:49 -07002291 model = Payment
Scott Baker43105042013-12-06 23:23:36 -08002292 extra = 1
2293 verbose_name_plural = "Payments"
2294 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08002295 fields = ["date", "dollar_amount"]
2296 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08002297 suit_classes = 'suit-tab suit-tab-accountpayments'
Jeremy Moweryda57d402016-04-15 17:39:49 -07002298 can_delete = False
2299 max_num = 0
Scott Baker15cddfa2013-12-09 13:45:19 -08002300
2301 dollar_amount = right_dollar_field("amount", "Amount")
2302
Jeremy Moweryda57d402016-04-15 17:39:49 -07002303
Scott Baker43105042013-12-06 23:23:36 -08002304class AccountAdmin(admin.ModelAdmin):
2305 list_display = ("site", "balance_due")
2306
2307 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
2308
2309 fieldsets = [
Jeremy Moweryda57d402016-04-15 17:39:49 -07002310 (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 -08002311
Jeremy Moweryda57d402016-04-15 17:39:49 -07002312 readonly_fields = ['site', 'dollar_balance_due',
2313 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08002314
Jeremy Moweryda57d402016-04-15 17:39:49 -07002315 suit_form_tabs = (
2316 ('general', 'Account Details'),
Scott Baker43105042013-12-06 23:23:36 -08002317 ('accountinvoice', 'Invoices'),
2318 ('accountpayments', 'Payments'),
Jeremy Moweryda57d402016-04-15 17:39:49 -07002319 ('accountpendingcharges', 'Pending Charges'),
Scott Baker43105042013-12-06 23:23:36 -08002320 )
2321
Scott Baker15cddfa2013-12-09 13:45:19 -08002322 dollar_balance_due = dollar_field("balance_due", "Balance Due")
2323 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
2324 dollar_total_payments = dollar_field("total_payments", "Total Payments")
2325
Jeremy Moweryda57d402016-04-15 17:39:49 -07002326
Scott Bakerc24f86d2015-08-14 09:10:11 -07002327class ProgramForm(forms.ModelForm):
Jeremy Moweryda57d402016-04-15 17:39:49 -07002328
Scott Bakerc24f86d2015-08-14 09:10:11 -07002329 class Meta:
2330 model = Program
2331 widgets = {
2332 'contents': UploadTextareaWidget(attrs={'rows': 20, 'cols': 80, 'class': "input-xxlarge"}),
2333 'description': forms.Textarea(attrs={'rows': 3, 'cols': 80, 'class': 'input-xxlarge'}),
2334 'messages': forms.Textarea(attrs={'rows': 20, 'cols': 80, 'class': 'input-xxlarge'}),
2335 'output': forms.Textarea(attrs={'rows': 3, 'cols': 80, 'class': 'input-xxlarge'})
2336 }
2337
Jeremy Moweryda57d402016-04-15 17:39:49 -07002338
Scott Bakerc24f86d2015-08-14 09:10:11 -07002339class ProgramAdmin(XOSBaseAdmin):
2340 list_display = ("name", "status")
2341 list_display_links = ('name', "status")
2342
Jeremy Moweryda57d402016-04-15 17:39:49 -07002343 form = ProgramForm
Scott Bakerc24f86d2015-08-14 09:10:11 -07002344
2345 fieldsets = [
2346 (None, {'fields': ['name', 'command', 'kind', 'description', 'output', 'status'],
2347 'classes':['suit-tab suit-tab-general']}),
2348 (None, {'fields': ['contents'],
2349 'classes':['suit-tab suit-tab-contents']}),
2350 (None, {'fields': ['messages'],
2351 'classes':['suit-tab suit-tab-messages']}),
Jeremy Moweryda57d402016-04-15 17:39:49 -07002352 ]
Scott Bakerc24f86d2015-08-14 09:10:11 -07002353
2354 readonly_fields = ("status",)
2355
2356 @property
2357 def suit_form_tabs(self):
Jeremy Moweryda57d402016-04-15 17:39:49 -07002358 tabs = [('general', 'Program Details'),
2359 ('contents', 'Program Source'),
2360 ('messages', 'Messages'),
2361 ]
Scott Bakerc24f86d2015-08-14 09:10:11 -07002362
Jeremy Moweryda57d402016-04-15 17:39:49 -07002363 request = getattr(_thread_locals, "request", None)
Scott Bakerc24f86d2015-08-14 09:10:11 -07002364 if request and request.user.is_admin:
Jeremy Moweryda57d402016-04-15 17:39:49 -07002365 tabs.append(('admin-only', 'Admin-Only'))
Scott Bakerc24f86d2015-08-14 09:10:11 -07002366
2367 return tabs
2368
Jeremy Moweryda57d402016-04-15 17:39:49 -07002369
Scott Bakerb4d77972016-04-13 15:55:16 -07002370class AddressPoolForm(forms.ModelForm):
Jeremy Moweryda57d402016-04-15 17:39:49 -07002371
Scott Bakerb4d77972016-04-13 15:55:16 -07002372 class Meta:
2373 model = Program
2374 widgets = {
2375 'addresses': UploadTextareaWidget(attrs={'rows': 20, 'cols': 80, 'class': "input-xxlarge"}),
2376 }
2377
Jeremy Moweryda57d402016-04-15 17:39:49 -07002378
Scott Bakerb4d77972016-04-13 15:55:16 -07002379class AddressPoolAdmin(XOSBaseAdmin):
Scott Bakerfca52df2016-04-13 16:40:50 -07002380 list_display = ("name", "cidr")
Scott Bakerb4d77972016-04-13 15:55:16 -07002381 list_display_links = ('name',)
2382
Jeremy Moweryda57d402016-04-15 17:39:49 -07002383 form = AddressPoolForm
Scott Bakerb4d77972016-04-13 15:55:16 -07002384
2385 fieldsets = [
Scott Bakerfca52df2016-04-13 16:40:50 -07002386 (None, {'fields': ['name', 'cidr', 'gateway_ip', 'gateway_mac', 'addresses', 'inuse', 'service'],
Scott Bakerb4d77972016-04-13 15:55:16 -07002387 'classes':['suit-tab suit-tab-general']}),
Jeremy Moweryda57d402016-04-15 17:39:49 -07002388 ]
Scott Bakerb4d77972016-04-13 15:55:16 -07002389
2390 readonly_fields = ("status",)
2391
2392 @property
2393 def suit_form_tabs(self):
Jeremy Moweryda57d402016-04-15 17:39:49 -07002394 tabs = [('general', 'Program Details'),
2395 ('contents', 'Program Source'),
2396 ('messages', 'Messages'),
2397 ]
Scott Bakerb4d77972016-04-13 15:55:16 -07002398
2399# request=getattr(_thread_locals, "request", None)
2400# if request and request.user.is_admin:
2401# tabs.append( ('admin-only', 'Admin-Only') )
2402
2403 return tabs
2404
Scott Baker8cef72b2016-04-29 09:29:42 -07002405class AddressPoolInline(XOSTabularInline):
2406 model = AddressPool
2407 extra = 0
2408 suit_classes = 'suit-tab suit-tab-addresspools'
2409 fields = ['cidr', 'gateway_ip', 'gateway_mac']
2410 readonly_fields = ['cidr',]
2411
2412 # disable the add link
2413 def has_add_permission(self, request):
2414 return False
2415
Scott Bakerb18b81b2016-05-27 14:55:44 -07002416class DiagAdmin(XOSBaseAdmin):
2417 list_display = ("name", "backend_status", "backend_register")
2418 list_display_links = ('name',)
2419
2420 fieldsets = [
2421 (None, {'fields': ['name', 'backend_status', 'backend_register'],
2422 'classes':['suit-tab suit-tab-general']}),
2423 ]
2424
Siobhan Tully53437282013-04-26 19:30:27 -04002425# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04002426admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04002427# ... and, since we're not using Django's builtin permissions,
2428# unregister the Group model from admin.
Jeremy Moweryda57d402016-04-15 17:39:49 -07002429# admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04002430
Jeremy Moweryc2e8f162016-01-10 20:36:51 -07002431# When debugging it is often easier to see all the classes, but for regular use
Siobhan Tullybf1153a2013-05-27 20:53:48 -04002432# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002433showAll = False
Scott Baker43105042013-12-06 23:23:36 -08002434
Siobhan Tullybf1153a2013-05-27 20:53:48 -04002435admin.site.register(Deployment, DeploymentAdmin)
Tony Mack06c8e472014-11-30 15:53:08 -05002436admin.site.register(Controller, ControllerAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04002437admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04002438admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04002439admin.site.register(Service, ServiceAdmin)
Scott Bakerc9117f82016-05-26 20:57:22 -07002440admin.site.register(ServiceController, ServiceControllerAdmin)
Tony Mack450b6e02015-01-25 12:35:29 -05002441#admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07002442admin.site.register(Network, NetworkAdmin)
Scott Baker17ff0172015-11-16 13:43:38 -08002443admin.site.register(Port, PortAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07002444admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07002445admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Scott Bakerc24f86d2015-08-14 09:10:11 -07002446admin.site.register(Program, ProgramAdmin)
Tony Mack450b6e02015-01-25 12:35:29 -05002447#admin.site.register(Account, AccountAdmin)
2448#admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04002449
Siobhan Tullycf04fb62014-01-11 11:25:57 -05002450if True:
2451 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
2452 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullyd3515752013-06-21 16:34:53 -04002453 admin.site.register(Tag, TagAdmin)
Tony Mack06c8e472014-11-30 15:53:08 -05002454 admin.site.register(ControllerRole)
Siobhan Tullyce652d02013-10-08 21:52:35 -04002455 admin.site.register(SiteRole)
2456 admin.site.register(SliceRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04002457 admin.site.register(Node, NodeAdmin)
Scott Baker7c886d42016-03-04 10:35:32 -08002458 admin.site.register(NodeLabel, NodeLabelAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04002459 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
2460 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Tony Mackd8515472015-08-19 11:58:18 -04002461 admin.site.register(Instance, InstanceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04002462 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07002463 admin.site.register(DashboardView, DashboardViewAdmin)
Scott Baker37b47902014-09-02 14:37:41 -07002464 admin.site.register(Flavor, FlavorAdmin)
Scott Bakerb3cf9212015-07-06 14:40:20 -07002465 admin.site.register(TenantRoot, TenantRootAdmin)
2466 admin.site.register(TenantRootRole, TenantRootRoleAdmin)
Jeremy Moweryb52c49a2016-04-05 23:32:10 -07002467 admin.site.register(TenantRole, TenantRoleAdmin)
Scott Baker1e7e3482015-10-15 15:59:19 -07002468 admin.site.register(TenantAttribute, TenantAttributeAdmin)
Scott Bakerb4d77972016-04-13 15:55:16 -07002469 admin.site.register(AddressPool, AddressPoolAdmin)
Scott Bakerb18b81b2016-05-27 14:55:44 -07002470 admin.site.register(Diag, DiagAdmin)