blob: 94e84532f5e84823effd939f00265404899690df [file] [log] [blame]
Siobhan Tully30fd4292013-05-10 08:59:56 -04001from core.models import Site
2from core.models import *
3from openstack.manager import OpenStackManager
Tony Macke59a7c82013-04-27 11:08:10 -04004
Tony Mack7130ac32013-03-22 21:58:00 -04005from django.contrib import admin
Siobhan Tully53437282013-04-26 19:30:27 -04006from django.contrib.auth.models import Group
Siobhan Tully4bc09f22013-04-10 21:15:21 -04007from django import forms
Tony Mackd90cdbf2013-04-16 22:48:40 -04008from django.utils.safestring import mark_safe
Tony Mack7130ac32013-03-22 21:58:00 -04009from django.contrib.auth.admin import UserAdmin
Siobhan Tully4bc09f22013-04-10 21:15:21 -040010from django.contrib.admin.widgets import FilteredSelectMultiple
Siobhan Tully53437282013-04-26 19:30:27 -040011from django.contrib.auth.forms import ReadOnlyPasswordHashField
Scott Bakeracd45142013-05-19 16:19:16 -070012from django.contrib.auth.signals import user_logged_in
13from django.utils import timezone
Siobhan Tullyde5450d2013-06-21 11:35:33 -040014from django.contrib.contenttypes import generic
Siobhan Tullybfd11dc2013-09-03 12:59:24 -040015from suit.widgets import LinkedSelect
Siobhan Tullycf04fb62014-01-11 11:25:57 -050016from django.core.exceptions import PermissionDenied
Scott Bakere2bbf7e2014-01-13 12:09:31 -080017from django.core.urlresolvers import reverse, NoReverseMatch
Tony Mack7130ac32013-03-22 21:58:00 -040018
Scott Baker36f50872014-08-21 13:01:25 -070019import django_evolution
20
Scott Baker40c00762014-08-21 16:55:59 -070021def backend_icon(obj): # backend_status, enacted, updated):
22 #return "%s %s %s" % (str(obj.updated), str(obj.enacted), str(obj.backend_status))
23 if (obj.enacted is not None) and obj.enacted >= obj.updated:
Scott Bakerfbf06642014-09-09 10:38:15 -070024 return '<span style="min-width:16px;"><img src="/static/admin/img/icon_success.gif"></span>'
Scott Baker40c00762014-08-21 16:55:59 -070025 else:
26 if obj.backend_status == "Provisioning in progress" or obj.backend_status=="":
Scott Bakerfbf06642014-09-09 10:38:15 -070027 return '<span style="min-width:16px;" title="%s"><img src="/static/admin/img/icon_clock.gif"></span>' % obj.backend_status
Scott Baker63d1a552014-08-21 15:19:07 -070028 else:
Scott Bakerfbf06642014-09-09 10:38:15 -070029 return '<span style="min-width:16px;" title="%s"><img src="/static/admin/img/icon_error.gif"></span>' % obj.backend_status
Scott Baker40c00762014-08-21 16:55:59 -070030
31def backend_text(obj):
32 icon = backend_icon(obj)
33 if (obj.enacted is not None) and obj.enacted >= obj.updated:
34 return "%s %s" % (icon, "successfully enacted") # enacted on %s" % str(obj.enacted))
35 else:
36 return "%s %s" % (icon, obj.backend_status)
Scott Baker63d1a552014-08-21 15:19:07 -070037
Scott Baker36f50872014-08-21 13:01:25 -070038class PlainTextWidget(forms.HiddenInput):
39 input_type = 'hidden'
40
41 def render(self, name, value, attrs=None):
42 if value is None:
43 value = ''
44 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
45
Siobhan Tullycf04fb62014-01-11 11:25:57 -050046class ReadOnlyAwareAdmin(admin.ModelAdmin):
47
48 def has_add_permission(self, request, obj=None):
49 return (not self.__user_is_readonly(request))
Scott Baker36f50872014-08-21 13:01:25 -070050
Siobhan Tullycf04fb62014-01-11 11:25:57 -050051 def has_delete_permission(self, request, obj=None):
52 return (not self.__user_is_readonly(request))
53
54 def save_model(self, request, obj, form, change):
55 if self.__user_is_readonly(request):
56 raise PermissionDenied
57 #pass
58 else:
59 return super(ReadOnlyAwareAdmin, self).save_model(request, obj, form, change)
60
61 def get_actions(self,request):
62 actions = super(ReadOnlyAwareAdmin,self).get_actions(request)
63
64 if self.__user_is_readonly(request):
65 if 'delete_selected' in actions:
66 del actions['delete_selected']
67
68 return actions
69
70 def change_view(self,request,object_id, extra_context=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -050071 if self.__user_is_readonly(request):
Scott Bakeraf73e102014-04-22 22:40:07 -070072 if not hasattr(self, "readonly_save"):
73 # save the original readonly fields
74 self.readonly_save = self.readonly_fields
75 self.inlines_save = self.inlines
Scott Bakere8859f92014-05-23 12:42:40 -070076 if hasattr(self, "user_readonly_fields"):
77 self.readonly_fields=self.user_readonly_fields
78 if hasattr(self, "user_readonly_inlines"):
79 self.inlines = self.user_readonly_inlines
Scott Bakeraf73e102014-04-22 22:40:07 -070080 else:
81 if hasattr(self, "readonly_save"):
82 # restore the original readonly fields
83 self.readonly_fields = self.readonly_save
Scott Bakere8859f92014-05-23 12:42:40 -070084 if hasattr(self, "inlines_save"):
Scott Bakeraf73e102014-04-22 22:40:07 -070085 self.inlines = self.inlines_save
Siobhan Tullycf04fb62014-01-11 11:25:57 -050086
87 try:
88 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
89 except PermissionDenied:
90 pass
91 if request.method == 'POST':
92 raise PermissionDenied
93 request.readonly = True
94 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
95
Siobhan Tullycf04fb62014-01-11 11:25:57 -050096 def __user_is_readonly(self, request):
97 return request.user.isReadOnlyUser()
98
Scott Baker40c00762014-08-21 16:55:59 -070099 def backend_status_text(self, obj):
100 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -0700101
Scott Baker63d1a552014-08-21 15:19:07 -0700102 def backend_status_icon(self, obj):
Scott Baker40c00762014-08-21 16:55:59 -0700103 return mark_safe(backend_icon(obj))
Scott Baker63d1a552014-08-21 15:19:07 -0700104 backend_status_icon.short_description = ""
105
Scott Baker36f50872014-08-21 13:01:25 -0700106
Scott Bakere8859f92014-05-23 12:42:40 -0700107class SingletonAdmin (ReadOnlyAwareAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400108 def has_add_permission(self, request):
Scott Bakere8859f92014-05-23 12:42:40 -0700109 if not super(SingletonAdmin, self).has_add_permission(request):
110 return False
111
Siobhan Tullyce652d02013-10-08 21:52:35 -0400112 num_objects = self.model.objects.count()
113 if num_objects >= 1:
114 return False
115 else:
116 return True
117
118
Siobhan Tullyd3515752013-06-21 16:34:53 -0400119class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -0800120 def __init__(self, *args, **kwargs):
121 super(PlStackTabularInline, self).__init__(*args, **kwargs)
122
123 # InlineModelAdmin as no get_fields() method, so in order to add
124 # the selflink field, we override __init__ to modify self.fields and
125 # self.readonly_fields.
126
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800127 self.setup_selflink()
128
Scott Baker874936e2014-01-13 18:15:34 -0800129 def get_change_url(self, model, id):
130 """ Get the URL to a change form in the admin for this model """
131 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800132 try:
Scott Baker874936e2014-01-13 18:15:34 -0800133 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800134 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -0800135 return None
136
137 return url
138
139 def setup_selflink(self):
140 if hasattr(self, "selflink_fieldname"):
141 """ self.selflink_model can be defined to punch through a relation
142 to its target object. For example, in SliceNetworkInline, set
143 selflink_model = "network", and the URL will lead to the Network
144 object instead of trying to bring up a change view of the
145 SliceNetwork object.
146 """
147 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
148 else:
149 self.selflink_model = self.model
150
151 url = self.get_change_url(self.selflink_model, 0)
152
153 # We don't have an admin for this object, so don't create the
154 # selflink.
155 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800156 return
157
Scott Baker874936e2014-01-13 18:15:34 -0800158 # Since we need to add "selflink" to the field list, we need to create
159 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800160 if (self.fields is None):
161 self.fields = []
162 for f in self.model._meta.fields:
163 if f.editable and f.name != "id":
164 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800165
Scott Baker874936e2014-01-13 18:15:34 -0800166 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800167
Scott Baker874936e2014-01-13 18:15:34 -0800168 if self.readonly_fields is None:
169 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800170
Scott Baker874936e2014-01-13 18:15:34 -0800171 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800172
173 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800174 if hasattr(self, "selflink_fieldname"):
175 obj = getattr(obj, self.selflink_fieldname)
176
Scott Baker86568322014-01-12 16:53:31 -0800177 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800178 url = self.get_change_url(self.selflink_model, obj.id)
179 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800180 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800181 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800182
183 selflink.allow_tags = True
184 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400185
Scott Bakerb27b62c2014-08-15 16:29:16 -0700186 def has_add_permission(self, request):
187 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500188
189 def get_readonly_fields(self, request, obj=None):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700190 readonly_fields = list(self.readonly_fields)[:]
191 if request.user.isReadOnlyUser():
192 for field in self.fields:
193 if not field in readonly_fields:
194 readonly_fields.append(field)
195 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500196
Scott Baker40c00762014-08-21 16:55:59 -0700197 def backend_status_icon(self, obj):
198 return mark_safe(backend_icon(obj))
199 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -0700200
Scott Bakerb27b62c2014-08-15 16:29:16 -0700201class PlStackGenericTabularInline(generic.GenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500202 def has_add_permission(self, request):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700203 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500204
Scott Bakerb27b62c2014-08-15 16:29:16 -0700205 def get_readonly_fields(self, request, obj=None):
206 readonly_fields = list(self.readonly_fields)[:]
207 if request.user.isReadOnlyUser():
208 for field in self.fields:
209 if not field in readonly_fields:
210 readonly_fields.append(field)
211 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500212
Scott Baker40c00762014-08-21 16:55:59 -0700213 def backend_status_icon(self, obj):
214 return mark_safe(backend_icon(obj))
215 backend_status_icon.short_description = ""
216
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400217class ReservationInline(PlStackTabularInline):
218 model = Reservation
219 extra = 0
220 suit_classes = 'suit-tab suit-tab-reservations'
Scott Baker36f50872014-08-21 13:01:25 -0700221
Tony Mack5b061472014-02-04 07:57:10 -0500222 def queryset(self, request):
223 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400224
Scott Bakerb27b62c2014-08-15 16:29:16 -0700225class TagInline(PlStackGenericTabularInline):
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400226 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400227 extra = 0
228 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500229 fields = ['service', 'name', 'value']
230
231 def queryset(self, request):
232 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400233
Scott Baker74d8e622013-07-29 16:04:22 -0700234class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400235 """ This is a callable that looks up a network name in a sliver and returns
236 the ip address for that network.
237 """
238
Scott Baker434ca7e2014-08-15 12:29:20 -0700239 byNetworkName = {} # class variable
240
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400241 def __init__(self, name):
242 self.short_description = name
243 self.__name__ = name
244 self.network_name = name
245
246 def __call__(self, obj):
247 if obj is not None:
248 for nbs in obj.networksliver_set.all():
249 if (nbs.network.name == self.network_name):
250 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700251 return ""
252
253 def __str__(self):
254 return self.network_name
255
Scott Baker434ca7e2014-08-15 12:29:20 -0700256 @staticmethod
257 def get(network_name):
258 """ We want to make sure we alwars return the same NetworkLookerUpper
259 because sometimes django will cause them to be instantiated multiple
260 times (and we don't want different ones in form.fields vs
261 SliverInline.readonly_fields).
262 """
263 if network_name not in NetworkLookerUpper.byNetworkName:
264 NetworkLookerUpper.byNetworkName[network_name] = NetworkLookerUpper(network_name)
265 return NetworkLookerUpper.byNetworkName[network_name]
266
Siobhan Tullyd3515752013-06-21 16:34:53 -0400267class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400268 model = Sliver
Scott Baker7a61dc42014-09-02 17:08:20 -0700269 fields = ['backend_status_icon', 'all_ips_string', 'instance_name', 'slice', 'deploymentNetwork', 'flavor', 'image', 'node']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400270 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700271 readonly_fields = ['backend_status_icon', 'all_ips_string', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400272 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700273
Tony Mack5b061472014-02-04 07:57:10 -0500274 def queryset(self, request):
275 return Sliver.select_by_user(request.user)
276
Scott Bakerb24cc932014-06-09 10:51:16 -0700277 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
Scott Bakerb24cc932014-06-09 10:51:16 -0700278 if db_field.name == 'deploymentNetwork':
Scott Baker3b678742014-06-09 13:11:54 -0700279 kwargs['queryset'] = Deployment.select_by_acl(request.user)
Scott Baker7a61dc42014-09-02 17:08:20 -0700280 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_deployment_changed(this);"})
Scott Baker32481312014-09-08 12:14:14 -0700281 elif db_field.name == 'flavor':
282 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_flavor_changed(this);"})
Scott Baker3b678742014-06-09 13:11:54 -0700283
284 field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700285
286 return field
287
Siobhan Tullyd3515752013-06-21 16:34:53 -0400288class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400289 model = Site
290 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400291 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400292
Tony Mack5b061472014-02-04 07:57:10 -0500293 def queryset(self, request):
294 return Site.select_by_user(request.user)
295
Siobhan Tullyd3515752013-06-21 16:34:53 -0400296class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400297 model = User
Scott Baker40c00762014-08-21 16:55:59 -0700298 fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
299 readonly_fields = ('backend_status_icon', )
Siobhan Tully30fd4292013-05-10 08:59:56 -0400300 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400301 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400302
Tony Mack5b061472014-02-04 07:57:10 -0500303 def queryset(self, request):
304 return User.select_by_user(request.user)
305
Siobhan Tullyd3515752013-06-21 16:34:53 -0400306class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400307 model = Slice
Scott Baker40c00762014-08-21 16:55:59 -0700308 fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
309 readonly_fields = ('backend_status_icon', )
Tony Mack00d361f2013-04-28 10:28:42 -0400310 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400311 suit_classes = 'suit-tab suit-tab-slices'
312
Tony Mack5b061472014-02-04 07:57:10 -0500313 def queryset(self, request):
314 return Slice.select_by_user(request.user)
315
Siobhan Tullyd3515752013-06-21 16:34:53 -0400316class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400317 model = Node
318 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400319 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker40c00762014-08-21 16:55:59 -0700320 fields = ['backend_status_icon', 'name','deployment','site']
321 readonly_fields = ('backend_status_icon', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400322
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400323class DeploymentPrivilegeInline(PlStackTabularInline):
324 model = DeploymentPrivilege
325 extra = 0
326 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700327 fields = ['backend_status_icon', 'user','role','deployment']
328 readonly_fields = ('backend_status_icon', )
Tony Mack5b061472014-02-04 07:57:10 -0500329
330 def queryset(self, request):
331 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400332
Siobhan Tullyd3515752013-06-21 16:34:53 -0400333class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400334 model = SitePrivilege
335 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400336 suit_classes = 'suit-tab suit-tab-siteprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700337 fields = ['backend_status_icon', 'user','site', 'role']
338 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400339
Tony Mackc2835a92013-05-28 09:18:49 -0400340 def formfield_for_foreignkey(self, db_field, request, **kwargs):
341 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500342 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400343
344 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500345 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400346 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
347
Tony Mack5b061472014-02-04 07:57:10 -0500348 def queryset(self, request):
349 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400350
Tony Macke4be32f2014-03-11 20:45:25 -0400351class SiteDeploymentInline(PlStackTabularInline):
352 model = SiteDeployments
Tony Macke4be32f2014-03-11 20:45:25 -0400353 extra = 0
354 suit_classes = 'suit-tab suit-tab-deployments'
Scott Baker40c00762014-08-21 16:55:59 -0700355 fields = ['backend_status_icon', 'deployment','site']
356 readonly_fields = ('backend_status_icon', )
Tony Macke4be32f2014-03-11 20:45:25 -0400357
358 def formfield_for_foreignkey(self, db_field, request, **kwargs):
359 if db_field.name == 'site':
360 kwargs['queryset'] = Site.select_by_user(request.user)
361
362 if db_field.name == 'deployment':
363 kwargs['queryset'] = Deployment.select_by_user(request.user)
364 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
365
366 def queryset(self, request):
367 return SiteDeployments.select_by_user(request.user)
368
369
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400370class SlicePrivilegeInline(PlStackTabularInline):
371 model = SlicePrivilege
372 suit_classes = 'suit-tab suit-tab-sliceprivileges'
373 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700374 fields = ('backend_status_icon', 'user', 'slice', 'role')
375 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400376
Tony Mackc2835a92013-05-28 09:18:49 -0400377 def formfield_for_foreignkey(self, db_field, request, **kwargs):
378 if db_field.name == 'slice':
Scott Baker36f50872014-08-21 13:01:25 -0700379 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400380 if db_field.name == 'user':
Scott Baker36f50872014-08-21 13:01:25 -0700381 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400382
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400383 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400384
Tony Mack5b061472014-02-04 07:57:10 -0500385 def queryset(self, request):
386 return SlicePrivilege.select_by_user(request.user)
387
Scott Bakera0015eb2013-08-14 17:28:14 -0700388class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700389 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800390 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700391 extra = 0
392 verbose_name = "Network Connection"
393 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400394 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker40c00762014-08-21 16:55:59 -0700395 fields = ['backend_status_icon', 'network']
396 readonly_fields = ('backend_status_icon', )
Scott Baker2170b972014-06-03 12:14:07 -0700397
398class ImageDeploymentsInline(PlStackTabularInline):
399 model = ImageDeployments
400 extra = 0
401 verbose_name = "Image Deployments"
402 verbose_name_plural = "Image Deployments"
403 suit_classes = 'suit-tab suit-tab-imagedeployments'
Scott Baker40c00762014-08-21 16:55:59 -0700404 fields = ['backend_status_icon', 'image', 'deployment', 'glance_image_id']
405 readonly_fields = ['backend_status_icon', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700406
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500407class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400408 save_on_top = False
Scott Baker36f50872014-08-21 13:01:25 -0700409
Tony Mack332ee1d2014-02-04 15:33:45 -0500410 def save_model(self, request, obj, form, change):
Tony Mack3d042792014-03-17 19:18:37 -0400411 obj.caller = request.user
Tony Mack332ee1d2014-02-04 15:33:45 -0500412 # update openstack connection to use this site/tenant
413 obj.save_by_user(request.user)
414
415 def delete_model(self, request, obj):
416 obj.delete_by_user(request.user)
417
418 def save_formset(self, request, form, formset, change):
419 instances = formset.save(commit=False)
420 for instance in instances:
421 instance.save_by_user(request.user)
Scott Baker7cbd4272014-09-30 11:35:30 -0700422
423 # BUG in django 1.7? Objects are not deleted by formset.save if
424 # commit is False. So let's delete them ourselves.
425 #
426 # code from forms/models.py save_existing_objects()
427 try:
428 forms_to_delete = formset.deleted_forms
429 except AttributeError:
430 forms_to_delete = []
431 if formset.initial_forms:
432 for form in formset.initial_forms:
433 obj = form.instance
434 if form in forms_to_delete:
435 if obj.pk is None:
436 continue
437 formset.deleted_objects.append(obj)
438 obj.delete()
439
Tony Mack332ee1d2014-02-04 15:33:45 -0500440 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400441
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400442class SliceRoleAdmin(PlanetStackBaseAdmin):
443 model = SliceRole
444 pass
445
446class SiteRoleAdmin(PlanetStackBaseAdmin):
447 model = SiteRole
448 pass
449
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400450class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400451 sites = forms.ModelMultipleChoiceField(
452 queryset=Site.objects.all(),
453 required=False,
Scott Baker70983182014-06-09 22:10:00 -0700454 help_text="Select which sites are allowed to host nodes in this deployment",
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400455 widget=FilteredSelectMultiple(
456 verbose_name=('Sites'), is_stacked=False
457 )
458 )
Scott Bakerde0f4412014-06-11 15:40:26 -0700459 images = forms.ModelMultipleChoiceField(
460 queryset=Image.objects.all(),
461 required=False,
462 help_text="Select which images should be deployed on this deployment",
463 widget=FilteredSelectMultiple(
464 verbose_name=('Images'), is_stacked=False
465 )
466 )
Scott Baker37b47902014-09-02 14:37:41 -0700467 flavors = forms.ModelMultipleChoiceField(
468 queryset=Flavor.objects.all(),
469 required=False,
470 help_text="Select which flavors should be usable on this deployment",
471 widget=FilteredSelectMultiple(
472 verbose_name=('Flavors'), is_stacked=False
473 )
474 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400475 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400476 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700477 many_to_many = ["flavors",]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400478
Siobhan Tully320b4622014-01-17 15:11:14 -0500479 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700480 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500481 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
482
Scott Baker5380c522014-06-06 14:49:43 -0700483 self.fields['accessControl'].initial = "allow site " + request.user.site.name
484
Siobhan Tully320b4622014-01-17 15:11:14 -0500485 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700486 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Scott Bakerde0f4412014-06-11 15:40:26 -0700487 self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
Scott Baker37b47902014-09-02 14:37:41 -0700488 self.fields['flavors'].initial = self.instance.flavors.all()
Scott Bakerde0f4412014-06-11 15:40:26 -0700489
490 def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
491 """ helper function for handling m2m relations from the MultipleChoiceField
492
493 this_obj: the source object we want to link from
494
495 selected_objs: a list of destination objects we want to link to
496
497 all_relations: the full set of relations involving this_obj, including ones we don't want
498
499 relation_class: the class that implements the relation from source to dest
500
501 local_attrname: field name representing this_obj in relation_class
502
503 foreign_attrname: field name representing selected_objs in relation_class
504
505 This function will remove all newobjclass relations from this_obj
506 that are not contained in selected_objs, and add any relations that
507 are in selected_objs but don't exist in the data model yet.
508 """
509
510 existing_dest_objs = []
511 for relation in list(all_relations):
512 if getattr(relation, foreign_attrname) not in selected_objs:
513 #print "deleting site", sdp.site
514 relation.delete()
515 else:
516 existing_dest_objs.append(getattr(relation, foreign_attrname))
517
518 for dest_obj in selected_objs:
519 if dest_obj not in existing_dest_objs:
520 #print "adding site", site
521 kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
522 relation = relation_class(**kwargs)
523 relation.save()
Siobhan Tully320b4622014-01-17 15:11:14 -0500524
525 def save(self, commit=True):
526 deployment = super(DeploymentAdminForm, self).save(commit=False)
527
Scott Baker37b47902014-09-02 14:37:41 -0700528 deployment.flavors = self.cleaned_data['flavors']
529
Siobhan Tully320b4622014-01-17 15:11:14 -0500530 if commit:
531 deployment.save()
532
533 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700534 # save_m2m() doesn't seem to work with 'through' relations. So we
535 # create/destroy the through models ourselves. There has to be
536 # a better way...
537
Scott Bakerde0f4412014-06-11 15:40:26 -0700538 self.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
539 self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
Scott Bakerc9b14f72014-05-22 13:44:20 -0700540
Scott Baker37b47902014-09-02 14:37:41 -0700541 self.save_m2m()
Siobhan Tully320b4622014-01-17 15:11:14 -0500542
543 return deployment
544
Scott Bakerff5e0f32014-05-22 14:40:27 -0700545class DeploymentAdminROForm(DeploymentAdminForm):
546 def save(self, commit=True):
547 raise PermissionDenied
548
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500549class SiteAssocInline(PlStackTabularInline):
550 model = Site.deployments.through
551 extra = 0
552 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400553
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400554class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500555 model = Deployment
Tony Mack2cbd3802014-09-29 16:10:52 -0400556 fieldList = ['backend_status_text', 'name', 'availability_zone', 'sites', 'images', 'flavors', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500557 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Scott Bakerde0f4412014-06-11 15:40:26 -0700558 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
Scott Baker63d1a552014-08-21 15:19:07 -0700559 list_display = ['backend_status_icon', 'name']
560 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700561 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500562
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500563 user_readonly_fields = ['name']
564
Scott Bakerde0f4412014-06-11 15:40:26 -0700565 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags')) # ,('imagedeployments','Images'))
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500566
Scott Bakerff5e0f32014-05-22 14:40:27 -0700567 def get_form(self, request, obj=None, **kwargs):
568 if request.user.isReadOnlyUser():
569 kwargs["form"] = DeploymentAdminROForm
570 else:
571 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700572 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
573
574 # from stackexchange: pass the request object into the form
575
576 class AdminFormMetaClass(adminForm):
577 def __new__(cls, *args, **kwargs):
578 kwargs['request'] = request
579 return adminForm(*args, **kwargs)
580
581 return AdminFormMetaClass
582
Siobhan Tullyce652d02013-10-08 21:52:35 -0400583class ServiceAttrAsTabInline(PlStackTabularInline):
584 model = ServiceAttribute
585 fields = ['name','value']
586 extra = 0
587 suit_classes = 'suit-tab suit-tab-serviceattrs'
588
Siobhan Tullyce652d02013-10-08 21:52:35 -0400589class ServiceAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700590 list_display = ("backend_status_icon","name","description","versionNumber","enabled","published")
591 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700592 fieldList = ["backend_status_text","name","description","versionNumber","enabled","published"]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500593 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
594 inlines = [ServiceAttrAsTabInline,SliceInline]
Scott Baker40c00762014-08-21 16:55:59 -0700595 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500596
597 user_readonly_fields = fieldList
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500598
599 suit_form_tabs =(('general', 'Service Details'),
600 ('slices','Slices'),
601 ('serviceattrs','Additional Attributes'),
602 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400603
Tony Mack0553f282013-06-10 22:54:50 -0400604class SiteAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700605 fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400606 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500607 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400608 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400609 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400610 suit_form_tabs =(('general', 'Site Details'),
611 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400612 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400613 ('deployments','Deployments'),
614 ('slices','Slices'),
Scott Baker36f50872014-08-21 13:01:25 -0700615 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400616 ('tags','Tags'),
617 )
Scott Baker40c00762014-08-21 16:55:59 -0700618 readonly_fields = ['backend_status_text', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500619
620 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500621
Scott Baker63d1a552014-08-21 15:19:07 -0700622 list_display = ('backend_status_icon', 'name', 'login_base','site_url', 'enabled')
623 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400624 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400625 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400626 search_fields = ['name']
627
Tony Mack04062832013-05-10 08:22:44 -0400628 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500629 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400630
Tony Mack5cd13202013-05-01 21:48:38 -0400631 def get_formsets(self, request, obj=None):
632 for inline in self.get_inline_instances(request, obj):
633 # hide MyInline in the add view
634 if obj is None:
635 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400636 if isinstance(inline, SliceInline):
637 inline.model.caller = request.user
638 yield inline.get_formset(request, obj)
639
640 def get_formsets(self, request, obj=None):
641 for inline in self.get_inline_instances(request, obj):
642 # hide MyInline in the add view
643 if obj is None:
644 continue
645 if isinstance(inline, SliverInline):
646 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400647 yield inline.get_formset(request, obj)
648
Scott Baker545db2a2013-12-09 18:44:43 -0800649 def accountLink(self, obj):
650 link_obj = obj.accounts.all()
651 if link_obj:
652 reverse_path = "admin:core_account_change"
653 url = reverse(reverse_path, args =(link_obj[0].id,))
654 return "<a href='%s'>%s</a>" % (url, "view billing details")
655 else:
656 return "no billing data for this site"
657 accountLink.allow_tags = True
658 accountLink.short_description = "Billing"
659
Tony Mack332ee1d2014-02-04 15:33:45 -0500660 def save_model(self, request, obj, form, change):
661 # update openstack connection to use this site/tenant
662 obj.save_by_user(request.user)
663
664 def delete_model(self, request, obj):
665 obj.delete_by_user(request.user)
666
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500667
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400668class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700669 fieldList = ['backend_status_text', 'user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400670 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500671 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400672 ]
Scott Baker40c00762014-08-21 16:55:59 -0700673 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700674 list_display = ('backend_status_icon', 'user', 'site', 'role')
675 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500676 user_readonly_fields = fieldList
677 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400678
Tony Mackc2835a92013-05-28 09:18:49 -0400679 def formfield_for_foreignkey(self, db_field, request, **kwargs):
680 if db_field.name == 'site':
681 if not request.user.is_admin:
682 # only show sites where user is an admin or pi
683 sites = set()
684 for site_privilege in SitePrivilege.objects.filer(user=request.user):
685 if site_privilege.role.role_type in ['admin', 'pi']:
686 sites.add(site_privilege.site)
687 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
688
689 if db_field.name == 'user':
690 if not request.user.is_admin:
691 # only show users from sites where caller has admin or pi role
692 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
693 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
694 sites = [site_privilege.site for site_privilege in site_privileges]
695 site_privileges = SitePrivilege.objects.filter(site__in=sites)
696 emails = [site_privilege.user.email for site_privilege in site_privileges]
697 users = User.objects.filter(email__in=emails)
698 kwargs['queryset'] = users
699
700 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
701
Tony Mack04062832013-05-10 08:22:44 -0400702 def queryset(self, request):
703 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400704 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400705 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500706 #if not request.user.is_admin:
707 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
708 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
709 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
710 # sites = Site.objects.filter(login_base__in=login_bases)
711 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400712 return qs
713
Siobhan Tullyce652d02013-10-08 21:52:35 -0400714class SliceForm(forms.ModelForm):
715 class Meta:
716 model = Slice
717 widgets = {
Scott Baker36f50872014-08-21 13:01:25 -0700718 'service': LinkedSelect
Siobhan Tullyce652d02013-10-08 21:52:35 -0400719 }
720
Tony Mack2cbd3802014-09-29 16:10:52 -0400721 def clean(self):
722 cleaned_data = super(SliceForm, self).clean()
723 name = cleaned_data.get('name')
724 site_id = cleaned_data.get('site')
725 site = Slice.objects.get(id=site_id)
726 if not name.startswith(site.login_base):
727 raise forms.ValidationError('slice name must begin with %s' % site.login_base)
728 return cleaned_data
729
Tony Mack2bd5b412013-06-11 21:05:06 -0400730class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400731 form = SliceForm
Tony Mackfbb26fc2014-09-02 07:03:27 -0400732 fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500733 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Scott Baker40c00762014-08-21 16:55:59 -0700734 readonly_fields = ('backend_status_text', )
Tony Mack7d459902014-09-03 13:18:57 -0400735 list_display = ('backend_status_icon', 'name', 'site','serviceClass', 'slice_url', 'max_slivers')
736 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully2d95e482013-09-06 10:56:06 -0400737 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400738
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500739 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400740
741 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400742 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400743 ('sliceprivileges','Privileges'),
744 ('slivers','Slivers'),
745 ('tags','Tags'),
746 ('reservations','Reservations'),
747 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400748
Scott Baker510fdbb2014-08-05 17:19:24 -0700749 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
Scott Baker510fdbb2014-08-05 17:19:24 -0700750 deployment_nodes = []
751 for node in Node.objects.all():
752 deployment_nodes.append( (node.deployment.id, node.id, node.name) )
753
Scott Baker7a61dc42014-09-02 17:08:20 -0700754 deployment_flavors = []
755 for flavor in Flavor.objects.all():
756 for deployment in flavor.deployments.all():
757 deployment_flavors.append( (deployment.id, flavor.id, flavor.name) )
758
Scott Baker93e80cd2014-09-09 09:58:49 -0700759 deployment_images = []
760 for image in Image.objects.all():
761 for imageDeployment in image.imagedeployments_set.all():
762 deployment_images.append( (imageDeployment.deployment.id, image.id, image.name) )
763
Tony Mackec23b992014-09-02 21:18:45 -0400764 site_login_bases = []
765 for site in Site.objects.all():
Scott Baker93e80cd2014-09-09 09:58:49 -0700766 site_login_bases.append((site.id, site.login_base))
767
Scott Baker510fdbb2014-08-05 17:19:24 -0700768 context["deployment_nodes"] = deployment_nodes
Scott Baker7a61dc42014-09-02 17:08:20 -0700769 context["deployment_flavors"] = deployment_flavors
Scott Baker93e80cd2014-09-09 09:58:49 -0700770 context["deployment_images"] = deployment_images
Tony Mackec23b992014-09-02 21:18:45 -0400771 context["site_login_bases"] = site_login_bases
Scott Baker510fdbb2014-08-05 17:19:24 -0700772 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
773
Tony Mackc2835a92013-05-28 09:18:49 -0400774 def formfield_for_foreignkey(self, db_field, request, **kwargs):
775 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500776 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackec23b992014-09-02 21:18:45 -0400777 kwargs['widget'] = forms.Select(attrs={'onChange': "update_slice_prefix(this, $($(this).closest('fieldset')[0]).find('.field-name input')[0].id)"})
Scott Baker40c00762014-08-21 16:55:59 -0700778
Tony Mackc2835a92013-05-28 09:18:49 -0400779 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
780
Tony Mack04062832013-05-10 08:22:44 -0400781 def queryset(self, request):
782 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500783 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400784
Tony Mack79748612013-05-01 14:52:03 -0400785 def get_formsets(self, request, obj=None):
786 for inline in self.get_inline_instances(request, obj):
787 # hide MyInline in the add view
788 if obj is None:
789 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400790 if isinstance(inline, SliverInline):
791 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400792 yield inline.get_formset(request, obj)
793
Tony Mack2bd5b412013-06-11 21:05:06 -0400794
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400795class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400796 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700797 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -0400798 ]
Scott Baker40c00762014-08-21 16:55:59 -0700799 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700800 list_display = ('backend_status_icon', 'user', 'slice', 'role')
801 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -0400802
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500803 user_readonly_fields = ['user', 'slice', 'role']
804 user_readonly_inlines = []
805
Tony Mackc2835a92013-05-28 09:18:49 -0400806 def formfield_for_foreignkey(self, db_field, request, **kwargs):
807 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500808 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400809
810 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500811 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400812
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400813 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400814
Tony Mack04062832013-05-10 08:22:44 -0400815 def queryset(self, request):
816 # admins can see all memberships. Users can only see memberships of
817 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500818 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400819
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400820 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400821 # update openstack connection to use this site/tenant
822 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400823 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400824 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400825 obj.save()
826
827 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400828 # update openstack connection to use this site/tenant
829 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400830 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400831 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400832 obj.delete()
833
Siobhan Tully567e3e62013-06-21 18:03:16 -0400834
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400835class ImageAdmin(PlanetStackBaseAdmin):
836
Scott Baker36f50872014-08-21 13:01:25 -0700837 fieldsets = [('Image Details',
Scott Baker40c00762014-08-21 16:55:59 -0700838 {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400839 'classes': ['suit-tab suit-tab-general']})
840 ]
Scott Baker40c00762014-08-21 16:55:59 -0700841 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400842
Scott Baker2170b972014-06-03 12:14:07 -0700843 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400844
Scott Baker2170b972014-06-03 12:14:07 -0700845 inlines = [SliverInline, ImageDeploymentsInline]
Scott Bakerb6f99242014-06-11 11:34:44 -0700846
Tony Mack32e1ce32014-05-07 13:29:41 -0400847 user_readonly_fields = ['name', 'disk_format', 'container_format']
Scott Bakerb27b62c2014-08-15 16:29:16 -0700848
Scott Baker63d1a552014-08-21 15:19:07 -0700849 list_display = ['backend_status_icon', 'name']
850 list_display_links = ('backend_status_icon', 'name', )
851
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400852class NodeForm(forms.ModelForm):
853 class Meta:
854 widgets = {
855 'site': LinkedSelect,
856 'deployment': LinkedSelect
857 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400858
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500859class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400860 form = NodeForm
Scott Baker63d1a552014-08-21 15:19:07 -0700861 list_display = ('backend_status_icon', 'name', 'site', 'deployment')
862 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400863 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500864
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400865 inlines = [TagInline,SliverInline]
Scott Baker40c00762014-08-21 16:55:59 -0700866 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
867 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400868
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500869 user_readonly_fields = ['name','site','deployment']
870 user_readonly_inlines = [TagInline,SliverInline]
871
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400872 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400873
Siobhan Tully567e3e62013-06-21 18:03:16 -0400874
Tony Mackd90cdbf2013-04-16 22:48:40 -0400875class SliverForm(forms.ModelForm):
876 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400877 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400878 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400879 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400880 widgets = {
881 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400882 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400883 'slice': LinkedSelect,
884 'deploymentNetwork': LinkedSelect,
885 'node': LinkedSelect,
886 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400887 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400888
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500889class TagAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700890 list_display = ['backend_status_icon', 'service', 'name', 'value', 'content_type', 'content_object',]
891 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500892 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
893 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400894
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400895class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400896 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400897 fieldsets = [
Scott Baker7a61dc42014-09-02 17:08:20 -0700898 ('Sliver Details', {'fields': ['backend_status_text', 'slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400899 ]
Scott Baker40c00762014-08-21 16:55:59 -0700900 readonly_fields = ('backend_status_text', )
Scott Baker7a61dc42014-09-02 17:08:20 -0700901 list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deploymentNetwork']
Scott Baker63d1a552014-08-21 15:19:07 -0700902 list_display_links = ('backend_status_icon', 'ip',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400903
904 suit_form_tabs =(('general', 'Sliver Details'),
905 ('tags','Tags'),
906 )
907
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400908 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400909
Scott Baker7a61dc42014-09-02 17:08:20 -0700910 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500911
Tony Mackc2835a92013-05-28 09:18:49 -0400912 def formfield_for_foreignkey(self, db_field, request, **kwargs):
913 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500914 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400915
916 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
917
Tony Mack04062832013-05-10 08:22:44 -0400918 def queryset(self, request):
Scott Baker36f50872014-08-21 13:01:25 -0700919 # admins can see all slivers. Users can only see slivers of
Tony Mack04062832013-05-10 08:22:44 -0400920 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500921 return Sliver.select_by_user(request.user)
922
Tony Mack04062832013-05-10 08:22:44 -0400923
Tony Mack1d6b85f2013-05-07 18:49:14 -0400924 def get_formsets(self, request, obj=None):
925 # make some fields read only if we are updating an existing record
926 if obj == None:
Scott Baker36f50872014-08-21 13:01:25 -0700927 #self.readonly_fields = ('ip', 'instance_name')
Scott Baker40c00762014-08-21 16:55:59 -0700928 self.readonly_fields = ('backend_status_text')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400929 else:
Scott Baker40c00762014-08-21 16:55:59 -0700930 self.readonly_fields = ('backend_status_text')
Scott Baker36f50872014-08-21 13:01:25 -0700931 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400932
933 for inline in self.get_inline_instances(request, obj):
934 # hide MyInline in the add view
935 if obj is None:
936 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700937 if isinstance(inline, SliverInline):
938 inline.model.caller = request.user
939 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400940
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500941 #def save_model(self, request, obj, form, change):
942 # # update openstack connection to use this site/tenant
943 # auth = request.session.get('auth', {})
944 # auth['tenant'] = obj.slice.name
945 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
946 # obj.creator = request.user
947 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400948
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500949 #def delete_model(self, request, obj):
950 # # update openstack connection to use this site/tenant
951 # auth = request.session.get('auth', {})
952 # auth['tenant'] = obj.slice.name
953 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
954 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400955
Siobhan Tully53437282013-04-26 19:30:27 -0400956class UserCreationForm(forms.ModelForm):
957 """A form for creating new users. Includes all the required
958 fields, plus a repeated password."""
959 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
960 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
961
962 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400963 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400964 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400965
966 def clean_password2(self):
967 # Check that the two password entries match
968 password1 = self.cleaned_data.get("password1")
969 password2 = self.cleaned_data.get("password2")
970 if password1 and password2 and password1 != password2:
971 raise forms.ValidationError("Passwords don't match")
972 return password2
973
974 def save(self, commit=True):
975 # Save the provided password in hashed format
976 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400977 user.password = self.cleaned_data["password1"]
978 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400979 if commit:
980 user.save()
981 return user
982
Siobhan Tully567e3e62013-06-21 18:03:16 -0400983
Siobhan Tully53437282013-04-26 19:30:27 -0400984class UserChangeForm(forms.ModelForm):
985 """A form for updating users. Includes all the fields on
986 the user, but replaces the password field with admin's
987 password hash display field.
988 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500989 password = ReadOnlyPasswordHashField(label='Password',
990 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400991
992 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400993 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400994
995 def clean_password(self):
996 # Regardless of what the user provides, return the initial value.
997 # This is done here, rather than on the field, because the
998 # field does not have access to the initial value
999 return self.initial["password"]
1000
Scott Baker2c3cb642014-05-19 17:55:56 -07001001class UserDashboardViewInline(PlStackTabularInline):
1002 model = UserDashboardView
1003 extra = 0
1004 suit_classes = 'suit-tab suit-tab-dashboards'
1005 fields = ['user', 'dashboardView', 'order']
1006
Tony Mack2bd5b412013-06-11 21:05:06 -04001007class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -04001008 class Meta:
1009 app_label = "core"
1010
1011 # The forms to add and change user instances
1012 form = UserChangeForm
1013 add_form = UserCreationForm
1014
1015 # The fields to be used in displaying the User model.
1016 # These override the definitions on the base UserAdmin
1017 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001018 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001019 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -07001020 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001021
Scott Bakeradae55f2014-08-14 17:32:35 -07001022 fieldListLoginDetails = ['email','site','password','is_active','is_readonly','is_admin','public_key']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001023 fieldListContactInfo = ['firstname','lastname','phone','timezone']
1024
Siobhan Tully53437282013-04-26 19:30:27 -04001025 fieldsets = (
Scott Baker40c00762014-08-21 16:55:59 -07001026 ('Login Details', {'fields': ['backend_status_text', 'email', 'site','password', 'is_active', 'is_readonly', 'is_admin', 'public_key'], 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001027 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -07001028 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001029 #('Important dates', {'fields': ('last_login',)}),
1030 )
1031 add_fieldsets = (
1032 (None, {
1033 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001034 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -04001035 ),
1036 )
Scott Baker40c00762014-08-21 16:55:59 -07001037 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001038 search_fields = ('email',)
1039 ordering = ('email',)
1040 filter_horizontal = ()
1041
Scott Baker3ca51f62014-05-23 12:05:11 -07001042 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001043
Scott Baker2c3cb642014-05-19 17:55:56 -07001044 suit_form_tabs =(('general','Login Details'),
1045 ('contact','Contact Information'),
1046 ('sliceprivileges','Slice Privileges'),
1047 ('siteprivileges','Site Privileges'),
1048 ('deploymentprivileges','Deployment Privileges'),
1049 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001050
Tony Mackc2835a92013-05-28 09:18:49 -04001051 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1052 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001053 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001054
1055 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1056
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001057 def has_add_permission(self, request, obj=None):
1058 return (not self.__user_is_readonly(request))
1059
1060 def has_delete_permission(self, request, obj=None):
1061 return (not self.__user_is_readonly(request))
1062
1063 def get_actions(self,request):
1064 actions = super(UserAdmin,self).get_actions(request)
1065
1066 if self.__user_is_readonly(request):
1067 if 'delete_selected' in actions:
1068 del actions['delete_selected']
1069
1070 return actions
1071
1072 def change_view(self,request,object_id, extra_context=None):
1073
1074 if self.__user_is_readonly(request):
Scott Bakerf875eba2014-05-23 12:09:15 -07001075 if not hasattr(self, "readonly_save"):
1076 # save the original readonly fields
1077 self.readonly_save = self.readonly_fields
1078 self.inlines_save = self.inlines
Scott Bakerb27b62c2014-08-15 16:29:16 -07001079 if hasattr(self, "user_readonly_fields"):
1080 self.readonly_fields=self.user_readonly_fields
1081 if hasattr(self, "user_readonly_inlines"):
1082 self.inlines = self.user_readonly_inlines
Scott Bakerf875eba2014-05-23 12:09:15 -07001083 else:
1084 if hasattr(self, "readonly_save"):
1085 # restore the original readonly fields
1086 self.readonly_fields = self.readonly_save
1087 self.inlines = self.inlines_save
1088
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001089 try:
1090 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1091 except PermissionDenied:
1092 pass
1093 if request.method == 'POST':
1094 raise PermissionDenied
1095 request.readonly = True
1096 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1097
1098 def __user_is_readonly(self, request):
1099 #groups = [x.name for x in request.user.groups.all() ]
1100 #return "readonly" in groups
1101 return request.user.isReadOnlyUser()
1102
Tony Mack5b061472014-02-04 07:57:10 -05001103 def queryset(self, request):
1104 return User.select_by_user(request.user)
1105
Scott Baker40c00762014-08-21 16:55:59 -07001106 def backend_status_text(self, obj):
1107 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -07001108
Scott Baker40c00762014-08-21 16:55:59 -07001109 def backend_status_icon(self, obj):
1110 return mark_safe(backend_icon(obj))
1111 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -07001112
Scott Baker2c3cb642014-05-19 17:55:56 -07001113class DashboardViewAdmin(PlanetStackBaseAdmin):
1114 fieldsets = [('Dashboard View Details',
Scott Baker40c00762014-08-21 16:55:59 -07001115 {'fields': ['backend_status_text', 'name', 'url'],
Scott Baker2c3cb642014-05-19 17:55:56 -07001116 'classes': ['suit-tab suit-tab-general']})
1117 ]
Scott Baker40c00762014-08-21 16:55:59 -07001118 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001119
Scott Baker2c3cb642014-05-19 17:55:56 -07001120 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001121
Scott Baker0165fac2014-01-13 11:49:26 -08001122class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001123 model = ServiceResource
1124 extra = 0
1125
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001126class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001127 list_display = ('backend_status_icon', 'name', 'commitment', 'membershipFee')
1128 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001129 inlines = [ServiceResourceInline]
1130
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001131 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1132 user_readonly_inlines = []
1133
Scott Baker0165fac2014-01-13 11:49:26 -08001134class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001135 model = ReservedResource
1136 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001137 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001138
1139 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1140 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1141
1142 if db_field.name == 'resource':
1143 # restrict resources to those that the slice's service class allows
1144 if request._slice is not None:
1145 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1146 if len(field.queryset) > 0:
1147 field.initial = field.queryset.all()[0]
1148 else:
1149 field.queryset = field.queryset.none()
1150 elif db_field.name == 'sliver':
1151 # restrict slivers to those that belong to the slice
1152 if request._slice is not None:
1153 field.queryset = field.queryset.filter(slice = request._slice)
1154 else:
1155 field.queryset = field.queryset.none()
1156
1157 return field
1158
Tony Mack5b061472014-02-04 07:57:10 -05001159 def queryset(self, request):
1160 return ReservedResource.select_by_user(request.user)
1161
Scott Baker133c9212013-05-17 09:09:11 -07001162class ReservationChangeForm(forms.ModelForm):
1163 class Meta:
1164 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001165 widgets = {
1166 'slice' : LinkedSelect
1167 }
Scott Baker133c9212013-05-17 09:09:11 -07001168
1169class ReservationAddForm(forms.ModelForm):
1170 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1171 refresh = forms.CharField(widget=forms.HiddenInput())
1172
1173 class Media:
1174 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1175
1176 def clean_slice(self):
1177 slice = self.cleaned_data.get("slice")
1178 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1179 if len(x) == 0:
1180 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1181 return slice
1182
1183 class Meta:
1184 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001185 widgets = {
1186 'slice' : LinkedSelect
1187 }
1188
Scott Baker133c9212013-05-17 09:09:11 -07001189
1190class ReservationAddRefreshForm(ReservationAddForm):
1191 """ This form is displayed when the Reservation Form receives an update
1192 from the Slice dropdown onChange handler. It doesn't validate the
1193 data and doesn't save the data. This will cause the form to be
1194 redrawn.
1195 """
1196
Scott Baker8737e5f2013-05-17 09:35:32 -07001197 """ don't validate anything other than slice """
1198 dont_validate_fields = ("startTime", "duration")
1199
Scott Baker133c9212013-05-17 09:09:11 -07001200 def full_clean(self):
1201 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001202
1203 for fieldname in self.dont_validate_fields:
1204 if fieldname in self._errors:
1205 del self._errors[fieldname]
1206
Scott Baker133c9212013-05-17 09:09:11 -07001207 return result
1208
1209 """ don't save anything """
1210 def is_valid(self):
1211 return False
1212
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001213class ReservationAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001214 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001215 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001216 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001217 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001218 form = ReservationAddForm
1219
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001220 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1221
1222 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001223 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001224
Scott Baker133c9212013-05-17 09:09:11 -07001225 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001226 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001227 request._refresh = False
1228 request._slice = None
1229 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001230 # "refresh" will be set to "1" if the form was submitted due to
1231 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001232 if request.POST.get("refresh","1") == "1":
1233 request._refresh = True
1234 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001235
1236 # Keep track of the slice that was selected, so the
1237 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001238 request._slice = request.POST.get("slice",None)
1239 if (request._slice is not None):
1240 request._slice = Slice.objects.get(id=request._slice)
1241
1242 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1243 return result
1244
Scott Bakeracd45142013-05-19 16:19:16 -07001245 def changelist_view(self, request, extra_context = None):
1246 timezone.activate(request.user.timezone)
1247 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1248
Scott Baker133c9212013-05-17 09:09:11 -07001249 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001250 request._obj_ = obj
1251 if obj is not None:
1252 # For changes, set request._slice to the slice already set in the
1253 # object.
1254 request._slice = obj.slice
1255 self.form = ReservationChangeForm
1256 else:
1257 if getattr(request, "_refresh", False):
1258 self.form = ReservationAddRefreshForm
1259 else:
1260 self.form = ReservationAddForm
1261 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1262
Scott Baker133c9212013-05-17 09:09:11 -07001263 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001264 if (obj is not None):
1265 # Prevent slice from being changed after the reservation has been
1266 # created.
1267 return ['slice']
1268 else:
Scott Baker133c9212013-05-17 09:09:11 -07001269 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001270
Tony Mack5b061472014-02-04 07:57:10 -05001271 def queryset(self, request):
1272 return Reservation.select_by_user(request.user)
1273
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001274class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001275 list_display = ("backend_status_icon", "name", )
1276 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001277 user_readonly_fields = ['name']
1278 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001279
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001280class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001281 list_display = ("backend_status_icon", "name", )
1282 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001283 user_readonly_fields = ['name']
1284 user_readonly_inlines = []
1285
Scott Baker0165fac2014-01-13 11:49:26 -08001286class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001287 model = Router.networks.through
1288 extra = 0
1289 verbose_name_plural = "Routers"
1290 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001291 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001292
Scott Bakerb27b62c2014-08-15 16:29:16 -07001293class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001294 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07001295 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001296 verbose_name_plural = "Parameters"
1297 verbose_name = "Parameter"
1298 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07001299 fields = ['backend_status_icon', 'parameter', 'value']
1300 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001301
Scott Baker0165fac2014-01-13 11:49:26 -08001302class NetworkSliversInline(PlStackTabularInline):
Scott Baker40c00762014-08-21 16:55:59 -07001303 fields = ['backend_status_icon', 'network','sliver','ip']
1304 readonly_fields = ("backend_status_icon", "ip", )
Scott Baker74d8e622013-07-29 16:04:22 -07001305 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001306 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001307 extra = 0
1308 verbose_name_plural = "Slivers"
1309 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001310 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001311
Scott Baker0165fac2014-01-13 11:49:26 -08001312class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001313 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001314 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001315 extra = 0
1316 verbose_name_plural = "Slices"
1317 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001318 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Baker40c00762014-08-21 16:55:59 -07001319 fields = ['backend_status_icon', 'network','slice']
1320 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07001321
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001322class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001323 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
1324 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07001325 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001326
Scott Bakerd7d2a392013-08-06 08:57:30 -07001327 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001328
Siobhan Tully2d95e482013-09-06 10:56:06 -04001329 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001330 (None, {'fields': ['backend_status_text', 'name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001331
Scott Baker40c00762014-08-21 16:55:59 -07001332 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001333 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
Siobhan Tully2d95e482013-09-06 10:56:06 -04001334
1335 suit_form_tabs =(
1336 ('general','Network Details'),
1337 ('netparams', 'Parameters'),
1338 ('networkslivers','Slivers'),
1339 ('networkslices','Slices'),
1340 ('routers','Routers'),
1341 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001342class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001343 list_display = ("backend_status_icon", "name", "guaranteedBandwidth", "visibility")
1344 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001345 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1346 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001347
Scott Baker37b47902014-09-02 14:37:41 -07001348class FlavorAdmin(PlanetStackBaseAdmin):
1349 list_display = ("backend_status_icon", "name", "flavor", "order", "default")
1350 list_display_links = ("backend_status_icon", "name")
1351 user_readonly_fields = ("name", "flavor")
1352 fields = ("name", "description", "flavor", "order", "default")
1353
Tony Mack31c2b8f2013-04-26 20:01:42 -04001354# register a signal that caches the user's credentials when they log in
1355def cache_credentials(sender, user, request, **kwds):
1356 auth = {'username': request.POST['username'],
1357 'password': request.POST['password']}
1358 request.session['auth'] = auth
1359user_logged_in.connect(cache_credentials)
1360
Scott Baker15cddfa2013-12-09 13:45:19 -08001361def dollar_field(fieldName, short_description):
1362 def newFunc(self, obj):
1363 try:
1364 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1365 except:
1366 x=getattr(obj, fieldName, 0.0)
1367 return x
1368 newFunc.short_description = short_description
1369 return newFunc
1370
1371def right_dollar_field(fieldName, short_description):
1372 def newFunc(self, obj):
1373 try:
1374 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1375 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1376 except:
1377 x=getattr(obj, fieldName, 0.0)
1378 return x
1379 newFunc.short_description = short_description
1380 newFunc.allow_tags = True
1381 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001382
Scott Baker0165fac2014-01-13 11:49:26 -08001383class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001384 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001385 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001386 verbose_name_plural = "Charges"
1387 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001388 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001389 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1390 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1391 can_delete = False
1392 max_num = 0
1393
1394 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001395
1396class InvoiceAdmin(admin.ModelAdmin):
1397 list_display = ("date", "account")
1398
1399 inlines = [InvoiceChargeInline]
1400
Scott Baker9cb88a22013-12-09 18:56:00 -08001401 fields = ["date", "account", "dollar_amount"]
1402 readonly_fields = ["date", "account", "dollar_amount"]
1403
1404 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001405
Scott Baker0165fac2014-01-13 11:49:26 -08001406class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001407 model = Invoice
1408 extra = 0
1409 verbose_name_plural = "Invoices"
1410 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001411 fields = ["date", "dollar_amount"]
1412 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001413 suit_classes = 'suit-tab suit-tab-accountinvoice'
1414 can_delete=False
1415 max_num=0
1416
1417 dollar_amount = right_dollar_field("amount", "Amount")
1418
Scott Baker0165fac2014-01-13 11:49:26 -08001419class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001420 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001421 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001422 verbose_name_plural = "Charges"
1423 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001424 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001425 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1426 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001427 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001428 can_delete=False
1429 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001430
1431 def queryset(self, request):
1432 qs = super(PendingChargeInline, self).queryset(request)
1433 qs = qs.filter(state="pending")
1434 return qs
1435
Scott Baker15cddfa2013-12-09 13:45:19 -08001436 dollar_amount = right_dollar_field("amount", "Amount")
1437
Scott Baker0165fac2014-01-13 11:49:26 -08001438class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001439 model=Payment
1440 extra = 1
1441 verbose_name_plural = "Payments"
1442 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001443 fields = ["date", "dollar_amount"]
1444 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001445 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001446 can_delete=False
1447 max_num=0
1448
1449 dollar_amount = right_dollar_field("amount", "Amount")
1450
Scott Baker43105042013-12-06 23:23:36 -08001451class AccountAdmin(admin.ModelAdmin):
1452 list_display = ("site", "balance_due")
1453
1454 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1455
1456 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001457 (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 -08001458
Scott Baker15cddfa2013-12-09 13:45:19 -08001459 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001460
1461 suit_form_tabs =(
1462 ('general','Account Details'),
1463 ('accountinvoice', 'Invoices'),
1464 ('accountpayments', 'Payments'),
1465 ('accountpendingcharges','Pending Charges'),
1466 )
1467
Scott Baker15cddfa2013-12-09 13:45:19 -08001468 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1469 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1470 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1471
Siobhan Tully53437282013-04-26 19:30:27 -04001472# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001473admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001474# ... and, since we're not using Django's builtin permissions,
1475# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001476#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001477
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001478#Do not show django evolution in the admin interface
1479from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001480#admin.site.unregister(Version)
1481#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001482
1483
1484# When debugging it is often easier to see all the classes, but for regular use
1485# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001486showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001487
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001488admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001489admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001490admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001491admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001492admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001493admin.site.register(Network, NetworkAdmin)
1494admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001495admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001496admin.site.register(Account, AccountAdmin)
1497admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001498
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001499if True:
1500 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1501 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001502 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001503 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001504 admin.site.register(DeploymentRole)
1505 admin.site.register(SiteRole)
1506 admin.site.register(SliceRole)
1507 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001508 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001509 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1510 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001511 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001512 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001513 admin.site.register(DashboardView, DashboardViewAdmin)
Scott Baker37b47902014-09-02 14:37:41 -07001514 admin.site.register(Flavor, FlavorAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001515