Django-suit, add in Roles for specific classes site, slice, deployment, planetstack, change admin to leverage suit options
diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py
index a1a21d6..730937a 100644
--- a/planetstack/core/admin.py
+++ b/planetstack/core/admin.py
@@ -12,12 +12,19 @@
from django.contrib.auth.signals import user_logged_in
from django.utils import timezone
from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
import django_evolution
class PlStackTabularInline(admin.TabularInline):
exclude = ['enacted']
+class ReservationInline(PlStackTabularInline):
+ model = Reservation
+ extra = 0
+ suit_classes = 'suit-tab suit-tab-reservations'
+
+
class ReadonlyTabularInline(PlStackTabularInline):
can_delete = False
extra = 0
@@ -34,10 +41,27 @@
def has_add_permission(self, request):
return False
+class UserMembershipInline(generic.GenericTabularInline):
+ model = Member
+ exclude = ['enacted']
+ extra = 1
+ suit_classes = 'suit-tab suit-tab-membership'
+
+ def queryset(self, request):
+ qs = super(UserMembershipInline, self).queryset(request)
+ return qs.filter(user=request.user)
+
+class MemberInline(generic.GenericTabularInline):
+ model = Member
+ exclude = ['enacted']
+ extra = 1
+ suit_classes = 'suit-tab suit-tab-members'
+
class TagInline(generic.GenericTabularInline):
model = Tag
exclude = ['enacted']
- extra = 1
+ extra = 0
+ suit_classes = 'suit-tab suit-tab-tags'
class SliverInline(PlStackTabularInline):
model = Sliver
@@ -45,32 +69,51 @@
extra = 0
#readonly_fields = ['ip', 'instance_name', 'image']
readonly_fields = ['ip', 'instance_name']
+ suit_classes = 'suit-tab suit-tab-slivers'
class SiteInline(PlStackTabularInline):
model = Site
extra = 0
+ suit_classes = 'suit-tab suit-tab-sites'
class UserInline(PlStackTabularInline):
model = User
fields = ['email', 'firstname', 'lastname']
extra = 0
+ suit_classes = 'suit-tab suit-tab-users'
class SliceInline(PlStackTabularInline):
model = Slice
+ fields = ['name','enabled','description','slice_url']
extra = 0
+ suit_classes = 'suit-tab suit-tab-slices'
+
class RoleInline(PlStackTabularInline):
model = Role
extra = 0
+ suit_classes = 'suit-tab suit-tab-roles'
class NodeInline(PlStackTabularInline):
model = Node
extra = 0
+ suit_classes = 'suit-tab suit-tab-nodes'
+
+class SlicePrivilegeInline(PlStackTabularInline):
+ model = SlicePrivilege
+ extra = 0
+ suit_classes = 'suit-tab suit-tab-sliceprivileges'
+
+class DeploymentPrivilegeInline(PlStackTabularInline):
+ model = DeploymentPrivilege
+ extra = 0
+ suit_classes = 'suit-tab suit-tab-deploymentprivileges'
class SitePrivilegeInline(PlStackTabularInline):
model = SitePrivilege
extra = 0
+ suit_classes = 'suit-tab suit-tab-siteprivileges'
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'site':
@@ -94,10 +137,17 @@
kwargs['queryset'] = users
return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
-class SliceMembershipInline(PlStackTabularInline):
- model = SliceMembership
+class SitePrivilegeInline(PlStackTabularInline):
+ model = SitePrivilege
+ suit_classes = 'suit-tab suit-tab-siteprivileges'
extra = 0
- fields = ('user', 'role')
+ fields = ('user', 'site','role')
+
+class SlicePrivilegeInline(PlStackTabularInline):
+ model = SlicePrivilege
+ suit_classes = 'suit-tab suit-tab-sliceprivileges'
+ extra = 0
+ fields = ('user', 'slice','role')
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'slice':
@@ -119,7 +169,7 @@
users = User.objects.filter(email__in=emails)
kwargs['queryset'] = list(users)
- return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+ return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
class SliceTagInline(PlStackTabularInline):
model = SliceTag
@@ -137,11 +187,38 @@
save_on_top = False
exclude = ['enacted']
+#class RoleMemberForm(forms.ModelForm):
+# request=None
+# member=forms.ModelChoiceField(queryset=Member.objects.all()) #first get all
+#
+# def __init__(self,fata=None,files=None,auto_id='id_%s',prefix=None,initial=None,error_class=ErrorList,label_suffix=':',empty_permitted=False,instance=None):
+# super(RoleMemberForm,self).__init__data,files,auto_id,prefix,initial,error_class,label_suffix,empty_permitted,instance)
+#
+# self.fields["member"].queryset = member.objects.filter(
+
+class RoleMemberInline (admin.StackedInline):
+ model = Member
+# form = RoleMemberForm
+
+ def get_formset(self,request,obj=None, **kwargs):
+ self.form.request=request
+ return super(RoleMemberInline, self).get_formset(request, obj, **kwargs)
+
+class SliceRoleAdmin(PlanetStackBaseAdmin):
+ model = SliceRole
+ pass
+
+class SiteRoleAdmin(PlanetStackBaseAdmin):
+ model = SiteRole
+ pass
+
class RoleAdmin(PlanetStackBaseAdmin):
fieldsets = [
- ('Role', {'fields': ['role_type']})
+ ('Role', {'fields': ['role_type', 'description','content_type'],
+ 'classes':['collapse']})
]
- list_display = ('role_type',)
+ inlines = [ MemberInline,]
+ list_display = ('role_type','description','content_type')
class DeploymentAdminForm(forms.ModelForm):
@@ -155,47 +232,30 @@
class Meta:
model = Deployment
- def __init__(self, *args, **kwargs):
- super(DeploymentAdminForm, self).__init__(*args, **kwargs)
-
- if self.instance and self.instance.pk:
- self.fields['sites'].initial = self.instance.sites.all()
-
- def save(self, commit=True):
- deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
- if commit:
- deploymentNetwork.save()
-
- if deploymentNetwork.pk:
- deploymentNetwork.sites = self.cleaned_data['sites']
- self.save_m2m()
-
- return deploymentNetwork
class DeploymentAdmin(PlanetStackBaseAdmin):
form = DeploymentAdminForm
- inlines = [NodeInline,SliverInline]
-
- def get_formsets(self, request, obj=None):
- for inline in self.get_inline_instances(request, obj):
- # hide MyInline in the add view
- if obj is None:
- continue
- # give inline object access to driver and caller
- auth = request.session.get('auth', {})
- if request.user.site:
- auth['tenant'] = request.user.site.login_base
- inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
- yield inline.get_formset(request, obj)
+ inlines = [MemberInline,NodeInline,SliverInline,TagInline]
+ fieldsets = [
+ (None, {'fields': ['sites'], 'classes':['suit-tab suit-tab-sites']}),]
+ suit_form_tabs =(('sites', 'Sites'),('nodes','Nodes'),('members','Members'),('tags','Tags'))
class SiteAdmin(PlanetStackBaseAdmin):
fieldsets = [
- (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'location']}),
- ('Deployment Networks', {'fields': ['deployments']})
+ (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'location'], 'classes':['suit-tab suit-tab-general']}),
+ ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
]
+ suit_form_tabs =(('general', 'Site Details'),
+ ('users','Users'),
+ ('members','Privileges'),
+ ('deployments','Deployments'),
+ ('slices','Slices'),
+ ('nodes','Nodes'),
+ ('tags','Tags'),
+ )
list_display = ('name', 'login_base','site_url', 'enabled')
filter_horizontal = ('deployments',)
- inlines = [TagInline, NodeInline, UserInline, SitePrivilegeInline]
+ inlines = [SliceInline,UserInline,TagInline, NodeInline, MemberInline]
search_fields = ['name']
def queryset(self, request):
@@ -229,7 +289,7 @@
class SitePrivilegeAdmin(PlanetStackBaseAdmin):
fieldsets = [
- (None, {'fields': ['user', 'site', 'role']})
+ (None, {'fields': ['user', 'site', 'role'], 'classes':['collapse']})
]
list_display = ('user', 'site', 'role')
@@ -269,9 +329,17 @@
return qs
class SliceAdmin(PlanetStackBaseAdmin):
- fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
+ fieldsets = [('Slice Details', {'fields': ['name', 'site', 'serviceClass', 'description', 'slice_url'], 'classes':['suit-tab suit-tab-general']}),]
list_display = ('name', 'site','serviceClass', 'slice_url')
- inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline]
+ inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline]
+
+
+ suit_form_tabs =(('general', 'Slice Details'),
+ ('sliceprivileges','Privileges'),
+ ('slivers','Slivers'),
+ ('tags','Tags'),
+ ('reservations','Reservations'),
+ )
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'site':
@@ -317,7 +385,7 @@
obj.caller = request.user
obj.save()
-class SliceMembershipAdmin(PlanetStackBaseAdmin):
+class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
fieldsets = [
(None, {'fields': ['user', 'slice', 'role']})
]
@@ -344,12 +412,12 @@
users = User.objects.filter(email__in=emails)
kwargs['queryset'] = users
- return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+ return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
def queryset(self, request):
# admins can see all memberships. Users can only see memberships of
# slices where they have the admin role.
- qs = super(SliceMembershipAdmin, self).queryset(request)
+ qs = super(SlicePrivilegeAdmin, self).queryset(request)
if not request.user.is_admin:
roles = Role.objects.filter(role_type__in=['admin', 'pi'])
site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
@@ -374,13 +442,33 @@
obj.delete()
-class ImageAdmin(admin.ModelAdmin):
- fields = ['image_id', 'name', 'disk_format', 'container_format']
+class ImageAdmin(PlanetStackBaseAdmin):
+
+ fieldsets = [('Image Details',
+ {'fields': ['image_id', 'name', 'disk_format', 'container_format'],
+ 'classes': ['suit-tab suit-tab-general']})
+ ]
+
+ suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
+
+ inlines = [SliverInline]
+
+class NodeForm(forms.ModelForm):
+ class Meta:
+ widgets = {
+ 'site': LinkedSelect,
+ 'deployment': LinkedSelect
+ }
class NodeAdmin(admin.ModelAdmin):
+ form = NodeForm
+ exclude = ['enacted']
list_display = ('name', 'site', 'deployment')
list_filter = ('deployment',)
- inlines = [TagInline]
+ inlines = [TagInline,SliverInline]
+ fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
+
+ suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
class SliverForm(forms.ModelForm):
@@ -391,26 +479,41 @@
widgets = {
'ip': PlainTextWidget(),
'instance_name': PlainTextWidget(),
+ 'slice': LinkedSelect,
+ 'deploymentNetwork': LinkedSelect,
+ 'node': LinkedSelect,
+ 'image': LinkedSelect
}
class ProjectAdmin(admin.ModelAdmin):
exclude = ['enacted']
+ inlines = [TagInline]
+
+class MemberAdmin(admin.ModelAdmin):
+ exclude = ['enacted']
+ list_display = ['role', 'rightContent_type', 'content_type', 'content_object',]
class TagAdmin(admin.ModelAdmin):
exclude = ['enacted']
+ list_display = ['project', 'name', 'value', 'content_type', 'content_object',]
class SliverAdmin(PlanetStackBaseAdmin):
form = SliverForm
fieldsets = [
- ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']})
+ ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
]
list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
+
+ suit_form_tabs =(('general', 'Sliver Details'),
+ ('tags','Tags'),
+ )
+
inlines = [TagInline]
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'slice':
if not request.user.is_admin:
- slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)])
+ slices = set([sm.slice.name for sm in SlicePrivilege.objects.filter(user=request.user)])
kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
@@ -470,7 +573,7 @@
class Meta:
model = User
- fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site')
+ fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
def clean_password2(self):
# Check that the two password entries match
@@ -518,24 +621,26 @@
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
- list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
- list_filter = ('site',)
- inlines = [SitePrivilegeInline, SliceMembershipInline]
+ list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
+ list_filter = ()
+ inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
fieldsets = (
- (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
- ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}),
+ ('Login Details', {'fields': ('email', 'username','site','password', 'is_admin', 'public_key'), 'classes':['suit-tab suit-tab-general']}),
+ ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
#('Important dates', {'fields': ('last_login',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
- 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')}
+ 'fields': ('email', 'username','firstname', 'lastname', 'phone', 'public_key','password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
+ suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
+
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'site':
if not request.user.is_admin:
@@ -562,6 +667,7 @@
exclude = ['enacted']
model = ReservedResource
extra = 0
+ suit_classes = 'suit-tab suit-tab-reservedresources'
def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
@@ -586,6 +692,9 @@
class ReservationChangeForm(forms.ModelForm):
class Meta:
model = Reservation
+ widgets = {
+ 'slice' : LinkedSelect
+ }
class ReservationAddForm(forms.ModelForm):
slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
@@ -603,6 +712,10 @@
class Meta:
model = Reservation
+ widgets = {
+ 'slice' : LinkedSelect
+ }
+
class ReservationAddRefreshForm(ReservationAddForm):
""" This form is displayed when the Reservation Form receives an update
@@ -629,10 +742,14 @@
class ReservationAdmin(admin.ModelAdmin):
exclude = ['enacted']
+ fieldsets = [('Reservation Details', {'fields': ['startTime', 'duration','slice'], 'classes': ['suit-tab suit-tab-general']})]
list_display = ('startTime', 'duration')
- inlines = [ReservedResourceInline]
form = ReservationAddForm
+ suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
+
+ inlines = [ReservedResourceInline]
+
def add_view(self, request, form_url='', extra_context=None):
timezone.activate(request.user.timezone)
request._refresh = False
@@ -700,7 +817,7 @@
# When debugging it is often easier to see all the classes, but for regular use
# only the top-levels should be displayed
-showAll = False
+showAll = True
admin.site.register(Deployment, DeploymentAdmin)
admin.site.register(Site, SiteAdmin)
@@ -708,13 +825,19 @@
admin.site.register(Project, ProjectAdmin)
admin.site.register(ServiceClass, ServiceClassAdmin)
admin.site.register(Reservation, ReservationAdmin)
+#admin.site.register(SliceRole, SliceRoleAdmin)
+#admin.site.register(SiteRole, SiteRoleAdmin)
+#admin.site.register(PlanetStackRole)
+#admin.site.register(DeploymentRole)
if showAll:
+ #admin.site.register(PlanetStack)
admin.site.register(Tag, TagAdmin)
admin.site.register(Node, NodeAdmin)
- admin.site.register(SliceMembership, SliceMembershipAdmin)
- admin.site.register(SitePrivilege, SitePrivilegeAdmin)
+ #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
+ #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
admin.site.register(Role, RoleAdmin)
+ admin.site.register(Member, MemberAdmin)
admin.site.register(Sliver, SliverAdmin)
admin.site.register(Image, ImageAdmin)
diff --git a/planetstack/core/fixtures/initial_data.json b/planetstack/core/fixtures/initial_data.json
index a86728a..f034820 100644
--- a/planetstack/core/fixtures/initial_data.json
+++ b/planetstack/core/fixtures/initial_data.json
@@ -314,5 +314,229 @@
"maxDuration": 8760,
"enacted": null
}
+},
+{
+ "pk": 1,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:35:50.572Z",
+ "description": "PlanetStack Application Administrator",
+ "created": "2013-07-30T10:30:28.633Z",
+ "content_type": 8,
+ "role_type": "Admin",
+ "enacted": null
+ }
+},
+{
+ "pk": 2,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:36:30.174Z",
+ "description": "User level role for PlanetStack Application",
+ "created": "2013-07-30T10:31:02.627Z",
+ "content_type": 8,
+ "role_type": "Default",
+ "enacted": null
+ }
+},
+{
+ "pk": 3,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:36:07.877Z",
+ "description": "Administrative role for a Slice",
+ "created": "2013-07-30T10:31:25.829Z",
+ "content_type": 21,
+ "role_type": "Admin",
+ "enacted": null
+ }
+},
+{
+ "pk": 4,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:36:20.679Z",
+ "description": "User level access for a particular Slice",
+ "created": "2013-07-30T10:31:48.791Z",
+ "content_type": 21,
+ "role_type": "Default",
+ "enacted": null
+ }
+},
+{
+ "pk": 5,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:35:59.388Z",
+ "description": "Administrator role for a particular Site",
+ "created": "2013-07-30T10:32:20.600Z",
+ "content_type": 15,
+ "role_type": "Admin",
+ "enacted": null
+ }
+},
+{
+ "pk": 6,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:34:39.494Z",
+ "description": "Principal Investigator for a particular Site",
+ "created": "2013-07-30T10:34:39.494Z",
+ "content_type": 15,
+ "role_type": "PI",
+ "enacted": null
+ }
+},
+{
+ "pk": 7,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:35:27.633Z",
+ "description": "Technical support for a particular Site. Allows for Read/Write access to a Site's Nodes.",
+ "created": "2013-07-30T10:35:27.633Z",
+ "content_type": 15,
+ "role_type": "Tech",
+ "enacted": null
+ }
+},
+{
+ "pk": 8,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:38:04.554Z",
+ "description": "Responsibility for a particular Site's accounting and invoices.",
+ "created": "2013-07-30T10:38:04.554Z",
+ "content_type": 15,
+ "role_type": "Billing",
+ "enacted": null
+ }
+},
+{
+ "pk": 9,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:39:07.062Z",
+ "description": "Default access for a particular Site which allows for Read-only access to the Site's objects.",
+ "created": "2013-07-30T10:39:07.062Z",
+ "content_type": 15,
+ "role_type": "Default",
+ "enacted": null
+ }
+},
+{
+ "pk": 10,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T10:39:55.479Z",
+ "description": "Represents the Site through which a particular user is managed through.",
+ "created": "2013-07-30T10:39:55.479Z",
+ "content_type": 15,
+ "role_type": "Homed",
+ "enacted": null
+ }
+},
+{
+ "pk": 11,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T17:35:59.815Z",
+ "description": "Administrative responsibility for a particular Deployment.",
+ "created": "2013-07-30T17:35:59.815Z",
+ "content_type": 9,
+ "role_type": "Admin",
+ "enacted": null
+ }
+},
+{
+ "pk": 12,
+ "model": "core.role",
+ "fields": {
+ "updated": "2013-07-30T17:36:54.728Z",
+ "description": "Default access for a particular Deployment.",
+ "created": "2013-07-30T17:36:54.728Z",
+ "content_type": 9,
+ "role_type": "Default",
+ "enacted": null
+ }
+},
+{
+ "pk": 1,
+ "model": "core.planetstackrole",
+ "fields": {
+ "updated": "2013-09-03T11:47:42.611Z",
+ "enacted": "2013-09-03T11:47:51Z",
+ "role": "admin",
+ "created": "2013-09-03T11:47:42.611Z"
+ }
+},
+{
+ "pk": 1,
+ "model": "core.siterole",
+ "fields": {
+ "updated": "2013-09-03T11:48:34.966Z",
+ "enacted": null,
+ "role": "admin",
+ "created": "2013-09-03T11:48:34.966Z"
+ }
+},
+{
+ "pk": 2,
+ "model": "core.siterole",
+ "fields": {
+ "updated": "2013-09-03T11:48:49.480Z",
+ "enacted": null,
+ "role": "pi",
+ "created": "2013-09-03T11:48:49.480Z"
+ }
+},
+{
+ "pk": 3,
+ "model": "core.siterole",
+ "fields": {
+ "updated": "2013-09-03T11:49:03.678Z",
+ "enacted": null,
+ "role": "tech",
+ "created": "2013-09-03T11:49:03.678Z"
+ }
+},
+{
+ "pk": 4,
+ "model": "core.siterole",
+ "fields": {
+ "updated": "2013-09-03T11:49:17.254Z",
+ "enacted": null,
+ "role": "billing",
+ "created": "2013-09-03T11:49:17.254Z"
+ }
+},
+{
+ "pk": 1,
+ "model": "core.slicerole",
+ "fields": {
+ "updated": "2013-09-03T11:48:02.080Z",
+ "enacted": null,
+ "role": "admin",
+ "created": "2013-09-03T11:48:02.080Z"
+ }
+},
+{
+ "pk": 2,
+ "model": "core.slicerole",
+ "fields": {
+ "updated": "2013-09-03T11:48:17.688Z",
+ "enacted": null,
+ "role": "default",
+ "created": "2013-09-03T11:48:17.688Z"
+ }
+},
+{
+ "pk": 1,
+ "model": "core.deploymentrole",
+ "fields": {
+ "updated": "2013-09-03T11:48:02.080Z",
+ "enacted": null,
+ "role": "admin",
+ "created": "2013-09-03T11:48:02.080Z"
+ }
}
]
diff --git a/planetstack/core/models/__init__.py b/planetstack/core/models/__init__.py
index 2280822..1cc4d07 100644
--- a/planetstack/core/models/__init__.py
+++ b/planetstack/core/models/__init__.py
@@ -1,17 +1,25 @@
from .plcorebase import PlCoreBase
-from .deployment import Deployment
+from .planetstack import PlanetStack
from .project import Project
from .tag import Tag
+from .role import Role
+from .deployment import Deployment
from .site import Site
+from .user import User
+from .serviceclass import ServiceClass
+from .slice import Slice
from .site import SitePrivilege
from .image import Image
-from .user import User
-from .role import Role
from .node import Node
-from .serviceclass import ServiceClass
from .serviceresource import ServiceResource
-from .slice import Slice
-from .slice import SliceMembership
+from .slice import SliceRole
+from .slice import SlicePrivilege
+from .site import SiteRole
+from .site import SitePrivilege
+from .deployment import DeploymentRole
+from .deployment import DeploymentPrivilege
+from .planetstack import PlanetStackRole
+from .planetstack import PlanetStackPrivilege
from .slicetag import SliceTag
from .sliver import Sliver
from .reservation import ReservedResource
diff --git a/planetstack/core/models/deployment.py b/planetstack/core/models/deployment.py
index d38115f..4e835d0 100644
--- a/planetstack/core/models/deployment.py
+++ b/planetstack/core/models/deployment.py
@@ -1,11 +1,30 @@
import os
from django.db import models
from core.models import PlCoreBase
+from core.models import Member
+from django.contrib.contenttypes import generic
# Create your models here.
class Deployment(PlCoreBase):
name = models.CharField(max_length=200, unique=True, help_text="Name of the Deployment")
+ members = generic.GenericRelation(Member)
def __unicode__(self): return u'%s' % (self.name)
+
+class DeploymentRole(PlCoreBase):
+
+ ROLE_CHOICES = (('admin','Admin'),)
+ role = models.CharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+ def __unicode__(self): return u'%s' % (self.role)
+
+class DeploymentPrivilege(PlCoreBase):
+
+ user = models.ForeignKey('User', related_name='deployment_privileges')
+ deployment = models.ForeignKey('Deployment', related_name='deployment_privileges')
+ role = models.ForeignKey('DeploymentRole')
+
+ def __unicode__(self): return u'%s %s %s' % (self.deployment, self.user, self.role)
+
diff --git a/planetstack/core/models/planetstack.py b/planetstack/core/models/planetstack.py
new file mode 100644
index 0000000..9007a51
--- /dev/null
+++ b/planetstack/core/models/planetstack.py
@@ -0,0 +1,30 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+
+# Create your models here.
+
+class PlanetStack(PlCoreBase):
+ description = models.CharField(max_length=200, unique=True, default="PlanetStack", help_text="Used for scoping of roles at the PlanetStack Application level")
+
+ class Meta:
+ verbose_name_plural = "PlanetStack"
+ app_label = "core"
+
+ def __unicode__(self): return u'%s' % (self.description)
+
+class PlanetStackRole(PlCoreBase):
+ ROLE_CHOICES = (('admin','Admin'),)
+ role = models.CharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+ def __unicode__(self): return u'%s' % (self.role)
+
+class PlanetStackPrivilege(PlCoreBase):
+ user = models.ForeignKey('User', related_name='planetstack_privileges')
+ planetstack = models.ForeignKey('PlanetStack', related_name='planetstack_privileges', default=1)
+ role = models.ForeignKey('PlanetStackRole')
+
+ def __unicode__(self): return u'%s %s %s' % (self.planetstack, self.user, self.role)
+
+
+
diff --git a/planetstack/core/models/role.py b/planetstack/core/models/role.py
index fd29848..234868e 100644
--- a/planetstack/core/models/role.py
+++ b/planetstack/core/models/role.py
@@ -2,14 +2,16 @@
import datetime
from django.db import models
from core.models import PlCoreBase
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
class Role(PlCoreBase):
- ROLE_CHOICES = (('admin', 'Admin'), ('pi', 'Principle Investigator'), ('tech', 'Technician'), ('user','User'))
- role = models.CharField(null=True, blank=True,max_length=256, unique=True, choices=ROLE_CHOICES)
- role_type = models.CharField(max_length=80, unique=True)
+ role_type = models.CharField(max_length=80, verbose_name="Name")
+ description = models.CharField(max_length=120, verbose_name="Description")
+ content_type = models.ForeignKey(ContentType, verbose_name="Role Scope")
- def __unicode__(self): return u'%s' % (self.role_type)
+ def __unicode__(self): return u'%s:%s' % (self.content_type,self.role_type)
def save(self, *args, **kwds):
diff --git a/planetstack/core/models/site.py b/planetstack/core/models/site.py
index 8a6d7c4..aee3843 100644
--- a/planetstack/core/models/site.py
+++ b/planetstack/core/models/site.py
@@ -24,11 +24,18 @@
def __unicode__(self): return u'%s' % (self.name)
+class SiteRole(PlCoreBase):
+
+ ROLE_CHOICES = (('admin','Admin'),('pi','PI'),('tech','Tech'),('billing','Billing'))
+ role = models.CharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+ def __unicode__(self): return u'%s' % (self.role)
+
class SitePrivilege(PlCoreBase):
user = models.ForeignKey('User', related_name='site_privileges')
site = models.ForeignKey('Site', related_name='site_privileges')
- role = models.ForeignKey('Role')
+ role = models.ForeignKey('SiteRole')
def __unicode__(self): return u'%s %s %s' % (self.site, self.user, self.role)
diff --git a/planetstack/core/models/slice.py b/planetstack/core/models/slice.py
index 74815b2..e584c07 100644
--- a/planetstack/core/models/slice.py
+++ b/planetstack/core/models/slice.py
@@ -40,15 +40,16 @@
self.creator = self.caller
super(Slice, self).save(*args, **kwds)
-class SliceMembership(PlCoreBase):
- user = models.ForeignKey('User', related_name='slice_memberships')
- slice = models.ForeignKey('Slice', related_name='slice_memberships')
- role = models.ForeignKey('Role')
+class SliceRole(PlCoreBase):
+ ROLE_CHOICES = (('admin','Admin'),('default','Default'))
+
+ role = models.CharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+ def __unicode__(self): return u'%s' % (self.role)
+
+class SlicePrivilege(PlCoreBase):
+ user = models.ForeignKey('User', related_name='slice_privileges')
+ slice = models.ForeignKey('Slice', related_name='slice_privileges')
+ role = models.ForeignKey('SliceRole')
def __unicode__(self): return u'%s %s %s' % (self.slice, self.user, self.role)
-
- def save(self, *args, **kwds):
- super(SliceMembership, self).save(*args, **kwds)
-
- def delete(self, *args, **kwds):
- super(SliceMembership, self).delete(*args, **kwds)
diff --git a/planetstack/core/models/user.py b/planetstack/core/models/user.py
index 758bcbf..2b63dda 100644
--- a/planetstack/core/models/user.py
+++ b/planetstack/core/models/user.py
@@ -2,11 +2,11 @@
import datetime
from collections import defaultdict
from django.db import models
-from core.models import PlCoreBase
-from core.models import Site
+from core.models import PlCoreBase,Site
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from timezones.fields import TimeZoneField
+
# Create your models here.
class UserManager(BaseUserManager):
def create_user(self, email, firstname, lastname, password=None):
@@ -54,6 +54,7 @@
unique=True,
db_index=True,
)
+ username = models.CharField(max_length=200, default="Something" )
kuser_id = models.CharField(null=True, blank=True, help_text="keystone user id", max_length=200)
firstname = models.CharField(help_text="person's given name", max_length=200)
@@ -61,7 +62,7 @@
phone = models.CharField(null=True, blank=True, help_text="phone number contact", max_length=100)
user_url = models.URLField(null=True, blank=True)
- site = models.ForeignKey(Site, related_name='users', verbose_name="Site this user will be homed too", null=True)
+ site = models.ForeignKey(Site, related_name='users', help_text="Site this user will be homed too", null=True)
public_key = models.TextField(null=True, blank=True, max_length=1024, help_text="Public key string")
is_active = models.BooleanField(default=True)
@@ -104,18 +105,21 @@
# Simplest possible answer: Yes, always
return True
- def get_roles(self):
- from core.models.site import SitePrivilege
- from core.models.slice import SliceMembership
+ def is_superuser(self):
+ return False
- site_privileges = SitePrivilege.objects.filter(user=self)
- slice_memberships = SliceMembership.objects.filter(user=self)
- roles = defaultdict(list)
- for site_privilege in site_privileges:
- roles[site_privilege.role.role_type].append(site_privilege.site.login_base)
- for slice_membership in slice_memberships:
- roles[slice_membership.role.role_type].append(slice_membership.slice.name)
- return roles
+# def get_roles(self):
+# from core.models.site import SitePrivilege
+# from core.models.slice import SliceMembership
+#
+# site_privileges = SitePrivilege.objects.filter(user=self)
+# slice_memberships = SliceMembership.objects.filter(user=self)
+# roles = defaultdict(list)
+# for site_privilege in site_privileges:
+# roles[site_privilege.role.role_type].append(site_privilege.site.login_base)
+# for slice_membership in slice_memberships:
+# roles[slice_membership.role.role_type].append(slice_membership.slice.name)
+# return roles
def save(self, *args, **kwds):
if not self.id:
diff --git a/planetstack/core/serializers.py b/planetstack/core/serializers.py
index 94f5c3c..b83157b 100644
--- a/planetstack/core/serializers.py
+++ b/planetstack/core/serializers.py
@@ -3,38 +3,108 @@
from core.models import *
+class DeploymentSerializer(serializers.HyperlinkedModelSerializer):
+
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ sites = serializers.HyperlinkedRelatedField(view_name='site-detail')
+ class Meta:
+ model = Deployment
+ fields = ('id',
+ 'url',
+ 'name',
+ 'sites'
+ )
+
+class ImageSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ class Meta:
+ model = Image
+ fields = ('id',
+ 'url',
+ 'image_id',
+ 'name',
+ 'disk_format',
+ 'container_format')
+
+class NodeSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ class Meta:
+ model = Node
+ fields = ('id',
+ 'url',
+ 'name')
+
+class ProjectSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ class Meta:
+ model = Project
+ fields = ('id',
+ 'url',
+ 'name')
+
+class ReservationSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ class Meta:
+ model = Reservation
+ fields = ('id',
+ 'url',
+ 'startTime',
+ 'slice',
+ 'duration',
+ 'endTime',
+ )
+
class RoleSerializer(serializers.HyperlinkedModelSerializer):
# HyperlinkedModelSerializer doesn't include the id by default
id = serializers.Field()
class Meta:
model = Role
fields = ('id',
- 'role',
- 'role_type')
+ 'url',
+ 'role',
+ 'role_type')
-class UserSerializer(serializers.HyperlinkedModelSerializer):
+class ServiceClassSerializer(serializers.HyperlinkedModelSerializer):
# HyperlinkedModelSerializer doesn't include the id by default
id = serializers.Field()
- site = serializers.HyperlinkedRelatedField(view_name='site-detail')
- slice_memberships = serializers.HyperlinkedRelatedField(view_name='slice-membership-detail')
- site_privileges = serializers.HyperlinkedRelatedField(view_name='siteprivilege-detail')
class Meta:
- model = User
+ model = ServiceClass
fields = ('id',
- 'kuser_id',
- 'firstname',
- 'lastname',
- 'email',
- 'password',
- 'phone',
- 'public_key',
- 'user_url',
- 'is_admin',
- 'site',
- 'slice_memberships',
- 'site_privileges')
-
+ 'url',
+ 'name',
+ 'description',
+ 'commitment',
+ 'membershipFee',
+ 'membershipFeeMonths',
+ 'upgradeRequiresApproval',
+ 'upgradeFrom',
+ )
+
+class ServiceResourceSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ serviceClass = serializers.HyperlinkedRelatedField(view_name='serviceclass-detail')
+ class Meta:
+ model = ServiceResource
+ fields = ('id',
+ 'url',
+ 'name',
+ 'serviceClass',
+ 'maxUnitsDeployment',
+ 'maxUnitsNode',
+ 'maxDuration',
+ 'bucketInRate',
+ 'bucketMaxSize',
+ 'cost',
+ 'calendarReservable',
+ )
+
class SliceSerializer(serializers.HyperlinkedModelSerializer):
# HyperlinkedModelSerializer doesn't include the id by default
id = serializers.Field()
@@ -43,6 +113,7 @@
class Meta:
model = Slice
fields = ('id',
+ 'url',
'tenant_id',
'enabled',
'name',
@@ -58,14 +129,15 @@
'updated',
'created')
-class SliceMembershipSerializer(serializers.HyperlinkedModelSerializer):
+class SlicePrivilegeSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.Field()
slice = serializers.HyperlinkedRelatedField(view_name='slice-detail')
user = serializers.HyperlinkedRelatedField(view_name='user-detail')
role = serializers.HyperlinkedRelatedField(view_name='role-detail')
class Meta:
- model = SliceMembership
+ model = SlicePrivilege
fields = ('id',
+ 'url',
'user',
'slice',
'role')
@@ -105,75 +177,90 @@
class Meta:
model = SitePrivilege
fields = ('id',
+ 'url',
'user',
'site',
'role')
-class DeploymentSerializer(serializers.HyperlinkedModelSerializer):
-
- # HyperlinkedModelSerializer doesn't include the id by default
- id = serializers.Field()
- sites = serializers.HyperlinkedRelatedField(view_name='site-detail')
- class Meta:
- model = Deployment
- fields = ('id',
- 'name',
- 'sites'
- )
-
class SliverSerializer(serializers.HyperlinkedModelSerializer):
# HyperlinkedModelSerializer doesn't include the id by default
id = serializers.Field()
image = serializers.HyperlinkedRelatedField(view_name='image-detail')
slice = serializers.HyperlinkedRelatedField(view_name='slice-detail')
- deployment = serializers.HyperlinkedRelatedField(view_name='deployment-detail')
+ deploymentNetwork = serializers.HyperlinkedRelatedField(view_name='deployment-detail')
node = serializers.HyperlinkedRelatedField(view_name='node-detail')
-
#slice = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Sliver
fields = ('id',
+ 'url',
'instance_id',
'name',
'instance_name',
'ip',
'image',
'slice',
- 'deployment',
+ 'deploymentNetwork',
'node')
-class NodeSerializer(serializers.HyperlinkedModelSerializer):
+class UserSerializer(serializers.HyperlinkedModelSerializer):
# HyperlinkedModelSerializer doesn't include the id by default
id = serializers.Field()
+ site = serializers.HyperlinkedRelatedField(view_name='site-detail')
+ slice_privileges = serializers.HyperlinkedRelatedField(view_name='sliceprivilege-detail')
+ site_privileges = serializers.HyperlinkedRelatedField(view_name='siteprivilege-detail')
class Meta:
- model = Node
+ model = User
fields = ('id',
- 'name')
-
-class ImageSerializer(serializers.HyperlinkedModelSerializer):
+ 'url',
+ 'kuser_id',
+ 'firstname',
+ 'lastname',
+ 'email',
+ 'password',
+ 'phone',
+ 'public_key',
+ 'user_url',
+ 'is_admin',
+ 'slice_privileges',
+ 'site_privileges')
+
+class TagSerializer(serializers.HyperlinkedModelSerializer):
# HyperlinkedModelSerializer doesn't include the id by default
id = serializers.Field()
+ project = serializers.HyperlinkedRelatedField(view_name='project-detail')
+ #content_type = serializers.PrimaryKeyRelatedField(read_only=True)
+ content_type = serializers.RelatedField(source = "content_type")
+ content_object = serializers.RelatedField(source='content_object')
class Meta:
- model = Image
- fields = ('id',
- 'image_id',
- 'name',
- 'disk_format',
- 'container_format')
+ model = Tag
+ fields = ('id',
+ 'url',
+ 'project',
+ 'value',
+ 'content_type',
+ 'object_id',
+ 'content_object',
+ 'name')
serializerLookUp = {
+ Deployment: DeploymentSerializer,
+ Image: ImageSerializer,
+ Node: NodeSerializer,
+ Project: ProjectSerializer,
+ Reservation: ReservationSerializer,
Role: RoleSerializer,
- User: UserSerializer,
+ ServiceClass: ServiceClassSerializer,
+ ServiceResource: ServiceResourceSerializer,
Site: SiteSerializer,
SitePrivilege: SitePrivilegeSerializer,
Slice: SliceSerializer,
- SliceMembership: SliceMembershipSerializer,
- Node: NodeSerializer,
+ SlicePrivilege: SlicePrivilegeSerializer,
Sliver: SliverSerializer,
- Deployment: DeploymentSerializer,
- Image: ImageSerializer,
+ Tag: TagSerializer,
+ User: UserSerializer,
None: None,
}
diff --git a/planetstack/core/static/planetstack.css b/planetstack/core/static/planetstack.css
index 2034708..b517eac 100644
--- a/planetstack/core/static/planetstack.css
+++ b/planetstack/core/static/planetstack.css
@@ -1 +1,2 @@
-.field-refresh { display: none; }
+.required:after {color: red ! important; font-size: 18px }
+#.btn-success {color:black}
diff --git a/planetstack/core/views/slice_memberships.py b/planetstack/core/views/slice_memberships.py
deleted file mode 100644
index 13f0707..0000000
--- a/planetstack/core/views/slice_memberships.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from core.serializers import SliceMembershipSerializer
-from rest_framework import generics
-from core.models import SliceMembership
-
-class SliceMembershipList(generics.ListCreateAPIView):
- queryset = SliceMembership.objects.all()
- serializer_class = SliceMembershipSerializer
-
-class SliceMembershipDetail(generics.RetrieveUpdateDestroyAPIView):
- queryset = SliceMembership.objects.all()
- serializer_class = SliceMembershipSerializer
-
-
diff --git a/planetstack/core/views/slice_privileges.py b/planetstack/core/views/slice_privileges.py
new file mode 100644
index 0000000..4dd1f93
--- /dev/null
+++ b/planetstack/core/views/slice_privileges.py
@@ -0,0 +1,13 @@
+from core.serializers import SlicePrivilegeSerializer
+from rest_framework import generics
+from core.models import SlicePrivilege
+
+class SlicePrivilegeList(generics.ListCreateAPIView):
+ queryset = SlicePrivilege.objects.all()
+ serializer_class = SlicePrivilegeSerializer
+
+class SlicePrivilegeDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = SlicePrivilege.objects.all()
+ serializer_class = SlicePrivilegeSerializer
+
+