Refactor to /opt/planetstack, final tweaks to make sure planetstack can run in non-openstack mode, adjustments to GUI for model focus changes
diff --git a/planetstack/core/__init__.py b/planetstack/core/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/core/__init__.py
diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py
new file mode 100644
index 0000000..6a8b71e
--- /dev/null
+++ b/planetstack/core/admin.py
@@ -0,0 +1,387 @@
+from core.models import Site
+from core.models import *
+from openstack.manager import OpenStackManager
+
+from django.contrib import admin
+from django.contrib.auth.models import Group
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+
+
+class ReadonlyTabularInline(admin.TabularInline):
+ can_delete = False
+ extra = 0
+ editable_fields = []
+
+ def get_readonly_fields(self, request, obj=None):
+ fields = []
+ for field in self.model._meta.get_all_field_names():
+ if (not field == 'id'):
+ if (field not in self.editable_fields):
+ fields.append(field)
+ return fields
+
+ def has_add_permission(self, request):
+ return False
+
+class SliverInline(admin.TabularInline):
+ model = Sliver
+ fields = ['ip', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
+ extra = 0
+
+class SiteInline(admin.TabularInline):
+ model = Site
+ extra = 0
+
+class UserInline(admin.TabularInline):
+ model = User
+ extra = 0
+
+class SliceInline(admin.TabularInline):
+ model = Slice
+ extra = 0
+
+class UserInline(admin.TabularInline):
+ model = User
+ extra = 0
+
+class RoleInline(admin.TabularInline):
+ model = Role
+ extra = 0
+
+class NodeInline(admin.TabularInline):
+ model = Node
+ extra = 0
+
+class PlainTextWidget(forms.Widget):
+ def render(self, _name, value, attrs):
+ return mark_safe(value) if value is not None else ''
+
+class PlanetStackBaseAdmin(admin.ModelAdmin):
+ save_on_top = False
+
+class OSModelAdmin(PlanetStackBaseAdmin):
+ """Attach client connection to openstack on delete() and save()"""
+
+ def save_model(self, request, obj, form, change):
+ auth = request.session.get('auth', {})
+ #auth['tenant'] = request.user.site.login_base
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.save()
+
+ def delete_model(self, request, obj):
+ auth = request.session.get('auth', {})
+ #auth['tenant'] = request.user.site.login_base
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.delete()
+
+class RoleAdmin(OSModelAdmin):
+ fieldsets = [
+ ('Role', {'fields': ['role_type']})
+ ]
+ list_display = ('role_type',)
+
+
+class DeploymentNetworkAdminForm(forms.ModelForm):
+ sites = forms.ModelMultipleChoiceField(
+ queryset=Site.objects.all(),
+ required=False,
+ widget=FilteredSelectMultiple(
+ verbose_name=('Sites'), is_stacked=False
+ )
+ )
+ class Meta:
+ model = DeploymentNetwork
+
+ def __init__(self, *args, **kwargs):
+ super(DeploymentNetworkAdminForm, 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(DeploymentNetworkAdminForm, self).save(commit=False)
+ if commit:
+ deploymentNetwork.save()
+
+ if deploymentNetwork.pk:
+ deploymentNetwork.sites = self.cleaned_data['sites']
+ self.save_m2m()
+
+ return deploymentNetwork
+
+class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
+ form = DeploymentNetworkAdminForm
+ inlines = [NodeInline,]
+
+ 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', {})
+ auth['tenant'] = request.user.site.login_base
+ inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ yield inline.get_formset(request, obj)
+
+class SiteAdmin(OSModelAdmin):
+ fieldsets = [
+ (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
+ ('Location', {'fields': ['latitude', 'longitude']}),
+ ('Deployment Networks', {'fields': ['deployments']})
+ ]
+ list_display = ('name', 'login_base','site_url', 'enabled')
+ filter_horizontal = ('deployments',)
+ inlines = [NodeInline, UserInline]
+ search_fields = ['name']
+
+ 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', {})
+ #auth['tenant'] = request.user.site.login_base
+ inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ yield inline.get_formset(request, obj)
+
+class SitePrivilegeAdmin(PlanetStackBaseAdmin):
+ fieldsets = [
+ (None, {'fields': ['user', 'site', 'role']})
+ ]
+ list_display = ('user', 'site', 'role')
+
+ def save_model(self, request, obj, form, change):
+ # update openstack connection to use this site/tenant
+ auth = request.session.get('auth', {})
+ #auth['tenant'] = obj.site.login_base
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.save()
+
+ def delete_model(self, request, obj):
+ # update openstack connection to use this site/tenant
+ auth = request.session.get('auth', {})
+ #auth['tenant'] = obj.site.login_base
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.delete()
+
+class KeyAdmin(OSModelAdmin):
+ fieldsets = [
+ ('Key', {'fields': ['name', 'key', 'type', 'blacklisted']})
+ ]
+ list_display = ['name', 'key', 'type', 'blacklisted']
+
+ def get_queryset(self, request):
+ # get keys user is allowed to see
+ qs = super(KeyAdmin, self).get_queryset(request)
+ if request.user.is_superuser:
+ return qs
+ # users can only see their own keys
+ return qs.filter(user=request.user)
+
+
+class SliceAdmin(OSModelAdmin):
+ fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
+ list_display = ('name', 'site','serviceClass', 'slice_url')
+ inlines = [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', {})
+ auth['tenant'] = obj.name # meed to connect using slice's tenant
+ inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ yield inline.get_formset(request, obj)
+
+ def get_queryset(self, request):
+ qs = super(SliceAdmin, self).get_queryset(request)
+ if request.user.is_superuser:
+ return qs
+ # users can only see slices at their site
+ return qs.filter(site=request.user.site)
+
+class SliceMembershipAdmin(PlanetStackBaseAdmin):
+ fieldsets = [
+ (None, {'fields': ['user', 'slice', 'role']})
+ ]
+ list_display = ('user', 'slice', 'role')
+
+ def save_model(self, request, obj, form, change):
+ # update openstack connection to use this site/tenant
+ auth = request.session.get('auth', {})
+ auth['tenant'] = obj.slice.name
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.save()
+
+ def delete_model(self, request, obj):
+ # update openstack connection to use this site/tenant
+ auth = request.session.get('auth', {})
+ auth['tenant'] = obj.slice.name
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.delete()
+
+
+class SubnetAdmin(PlanetStackBaseAdmin):
+ fields = ['cidr', 'ip_version', 'start', 'end', 'slice']
+ list_display = ('slice','cidr', 'start', 'end', 'ip_version')
+
+ def save_model(self, request, obj, form, change):
+ # update openstack connection to use this site/tenant
+ auth = request.session.get('auth', {})
+ auth['tenant'] = obj.slice.name
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.save()
+
+ def delete_model(self, request, obj):
+ # update openstack connection to use this site/tenant
+ auth = request.session.get('auth', {})
+ auth['tenant'] = obj.slice.name
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.delete()
+
+class ImageAdmin(admin.ModelAdmin):
+ fields = ['image_id', 'name', 'disk_format', 'container_format']
+
+class NodeAdmin(admin.ModelAdmin):
+ list_display = ('name', 'site', 'deploymentNetwork')
+ list_filter = ('deploymentNetwork',)
+
+
+class SliverForm(forms.ModelForm):
+ class Meta:
+ ip = forms.CharField(widget=PlainTextWidget)
+ instance_name = forms.CharField(widget=PlainTextWidget)
+ model = Sliver
+ widgets = {
+ 'ip': PlainTextWidget(),
+ 'instance_name': PlainTextWidget(),
+ }
+
+class SliverAdmin(PlanetStackBaseAdmin):
+ form = SliverForm
+ fieldsets = [
+ ('Sliver', {'fields': ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
+ ]
+ list_display = ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
+
+ def save_model(self, request, obj, form, change):
+ # update openstack connection to use this site/tenant
+ auth = request.session.get('auth', {})
+ auth['tenant'] = obj.slice.name
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.save()
+
+ def delete_model(self, request, obj):
+ # update openstack connection to use this site/tenant
+ auth = request.session.get('auth', {})
+ auth['tenant'] = obj.slice.name
+ obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+ obj.delete()
+
+class UserCreationForm(forms.ModelForm):
+ """A form for creating new users. Includes all the required
+ fields, plus a repeated password."""
+ password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
+ password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
+
+ class Meta:
+ model = User
+ fields = ('email', 'firstname', 'lastname', 'phone', 'key', 'site')
+
+ def clean_password2(self):
+ # Check that the two password entries match
+ password1 = self.cleaned_data.get("password1")
+ password2 = self.cleaned_data.get("password2")
+ if password1 and password2 and password1 != password2:
+ raise forms.ValidationError("Passwords don't match")
+ return password2
+
+ def save(self, commit=True):
+ # Save the provided password in hashed format
+ user = super(UserCreationForm, self).save(commit=False)
+ user.password = self.cleaned_data["password1"]
+ #user.set_password(self.cleaned_data["password1"])
+ if commit:
+ user.save()
+ return user
+
+
+class UserChangeForm(forms.ModelForm):
+ """A form for updating users. Includes all the fields on
+ the user, but replaces the password field with admin's
+ password hash display field.
+ """
+ password = ReadOnlyPasswordHashField()
+
+ class Meta:
+ model = User
+
+ def clean_password(self):
+ # Regardless of what the user provides, return the initial value.
+ # This is done here, rather than on the field, because the
+ # field does not have access to the initial value
+ return self.initial["password"]
+
+
+class UserAdmin(UserAdmin, OSModelAdmin):
+ class Meta:
+ app_label = "core"
+
+ # The forms to add and change user instances
+ form = UserChangeForm
+ add_form = UserCreationForm
+
+ # 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', 'last_login')
+ list_filter = ('site',)
+ fieldsets = (
+ (None, {'fields': ('email', 'password')}),
+ ('Personal info', {'fields': ('firstname','lastname','phone','site', 'key')}),
+ #('Important dates', {'fields': ('last_login',)}),
+ )
+ add_fieldsets = (
+ (None, {
+ 'classes': ('wide',),
+ 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'password1', 'password2', 'key')}
+ ),
+ )
+ search_fields = ('email',)
+ ordering = ('email',)
+ filter_horizontal = ()
+
+# register a signal that caches the user's credentials when they log in
+def cache_credentials(sender, user, request, **kwds):
+ auth = {'username': request.POST['username'],
+ 'password': request.POST['password']}
+ request.session['auth'] = auth
+user_logged_in.connect(cache_credentials)
+
+# Now register the new UserAdmin...
+admin.site.register(User, UserAdmin)
+# ... and, since we're not using Django's builtin permissions,
+# unregister the Group model from admin.
+admin.site.unregister(Group)
+
+admin.site.register(Site, SiteAdmin)
+#admin.site.register(SitePrivilege, SitePrivilegeAdmin)
+admin.site.register(Slice, SliceAdmin)
+#admin.site.register(SliceMembership, SliceMembershipAdmin)
+admin.site.register(Subnet, SubnetAdmin)
+#admin.site.register(Image, ImageAdmin)
+#admin.site.register(Node, NodeAdmin)
+admin.site.register(Sliver, SliverAdmin)
+admin.site.register(Key, KeyAdmin)
+#admin.site.register(Role, RoleAdmin)
+admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)
+
diff --git a/planetstack/core/api/__init__.py b/planetstack/core/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/core/api/__init__.py
diff --git a/planetstack/core/api/auth.py b/planetstack/core/api/auth.py
new file mode 100644
index 0000000..8796f14
--- /dev/null
+++ b/planetstack/core/api/auth.py
@@ -0,0 +1,8 @@
+from openstack.client import OpenStackClient
+
+def auth_check(username, password, tenant):
+ client = OpenStackClient(username=username,
+ password=password,
+ tenant=tenant)
+ client.authenticate()
+ return client
diff --git a/planetstack/core/api/deployment_networks.py b/planetstack/core/api/deployment_networks.py
new file mode 100644
index 0000000..51fa03e
--- /dev/null
+++ b/planetstack/core/api/deployment_networks.py
@@ -0,0 +1,39 @@
+from types import StringTypes
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import DeploymentNetwork
+
+def _get_deployment_networks(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ deployment_networks = DeploymentNetwork.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ deployment_networks = DeploymentNetwork.objects.filter(name=filter)
+ elif isinstance(filter, dict):
+ deployment_networks = DeploymentNetwork.objects.filter(**filter)
+ else:
+ deployment_networks = []
+ return deployment_networks
+
+def add_deployment_network(auth, name):
+ auth_check(auth)
+ deployment = DeploymentNetwork(name=name)
+ deployment.save()
+ return deployment
+
+def delete_deployment_network(auth, filter={}):
+ auth_check(auth)
+ deployments = _get_deployment_networks(filter)
+ for deployment in deployments:
+ deployment.delete()
+ return 1
+
+def get_deployment_networks(auth, filter={}):
+ auth_check(auth)
+ deployments = _get_deployment_networks(filter)
+ return deployments
+
+
+
diff --git a/planetstack/core/api/images.py b/planetstack/core/api/images.py
new file mode 100644
index 0000000..c080a55
--- /dev/null
+++ b/planetstack/core/api/images.py
@@ -0,0 +1,34 @@
+from types import StringTypes
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import Image
+
+def _get_images(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ images = Image.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ images = Image.objects.filter(name=filter)
+ elif isinstance(filter, dict):
+ images = Image.objects.filter(**filter)
+ else:
+ images = []
+ return images
+
+def add_image(auth, fields={}):
+ """not implemented"""
+ return
+
+def delete_image(auth, filter={}):
+ """not implemented"""
+ return 1
+
+def get_images(auth, filter={}):
+ auth_check(auth)
+ images = _get_images(filter)
+ return images
+
+
+
diff --git a/planetstack/core/api/keys.py b/planetstack/core/api/keys.py
new file mode 100644
index 0000000..e653690
--- /dev/null
+++ b/planetstack/core/api/keys.py
@@ -0,0 +1,51 @@
+from types import StringTypes
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.models import Key
+from core.api.auth import auth_check
+from core.api.users import _get_users
+
+
+def _get_keys(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ keys = Key.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ keys = Key.objects.filter(name=filter)
+ elif isinstance(filter, dict):
+ keys = Key.objects.filter(**filter)
+ else:
+ keys = []
+ return keys
+
+def add_key(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ users = _get_users(fields.get('user'))
+ if users: fields['user'] = users[0]
+ key = Key(**fields)
+ nova_fields = {'name': key.name,
+ 'key': key.key}
+ nova_key = driver.create_keypair(**nova_fields)
+ key.nkey_id = nova_key.id
+ key.save()
+ return key
+
+def update_key(auth, id, **fields):
+ return
+
+def delete_key(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ keys = _get_keys(filter)
+ for key in keys:
+ driver.delete_keypair(id=key.nkey_id)
+ key.delete()
+ return 1
+
+def get_keys(auth, filter={}):
+ client = auth_check(auth)
+ keys = _get_keys(filter)
+ return keys
+
+
+
diff --git a/planetstack/core/api/nodes.py b/planetstack/core/api/nodes.py
new file mode 100644
index 0000000..6514e54
--- /dev/null
+++ b/planetstack/core/api/nodes.py
@@ -0,0 +1,37 @@
+from types import StringTypes
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import Node
+
+def _get_nodes(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ nodes = Node.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ nodes = Node.objects.filter(name=filter)
+ elif isinstance(filter, dict):
+ nodes = Node.objects.filter(**filter)
+ else:
+ nodes = []
+ return nodes
+
+def add_node(auth, fields={}):
+ """not implemented"""
+ return
+
+def delete_node(auth, filter={}):
+ """not implemented"""
+ return 1
+
+def update_node(auth, id, fields={}):
+ return
+
+def get_nodes(auth, filter={}):
+ auth_check(auth)
+ nodes = _get_nodes(filter)
+ return nodes
+
+
+
diff --git a/planetstack/core/api/roles.py b/planetstack/core/api/roles.py
new file mode 100644
index 0000000..a799c01
--- /dev/null
+++ b/planetstack/core/api/roles.py
@@ -0,0 +1,39 @@
+from types import StringTypes
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import Role
+
+
+def _get_roles(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ roles = Role.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ roles = Role.objects.filter(role_type=filter)
+ elif isinstance(filter, dict):
+ roles = Role.objects.filter(**filter)
+ else:
+ roles = []
+ return roles
+
+def add_role(auth, name):
+ driver = OpenStackDriver(client = auth_check(auth))
+ keystone_role = driver.create_role(name=name)
+ role = Role(role_type=name, role_id=keystone_role.id)
+ role.save()
+ return role
+
+def delete_role(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ roles = _get_roles(filter)
+ for role in roles:
+ driver.delete_role({'id': role.role_id})
+ role.delete()
+ return 1
+
+def get_roles(auth, filter={}):
+ client = auth_check(auth)
+ return _get_roles(filter)
+
diff --git a/planetstack/core/api/site_privileges.py b/planetstack/core/api/site_privileges.py
new file mode 100644
index 0000000..85a8a83
--- /dev/null
+++ b/planetstack/core/api/site_privileges.py
@@ -0,0 +1,72 @@
+from types import StringTypes
+import re
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import SitePrivilege
+from core.api.users import _get_users
+from core.api.sites import _get_sites
+from core.api.roles import _get_roles
+
+
+def _get_site_privileges(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ site_privileges = SitePrivilege.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ site_privileges = SitePrivilege.objects.filter(name=filter)
+ elif isinstance(filter, dict):
+ site_privileges = SitePrivilege.objects.filter(**filter)
+ else:
+ site_privileges = []
+ return site_privileges
+
+def add_site_privilege(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ users = _get_user(fields.get('user'))
+ sites = _get_slice(fields.get('site'))
+ roles = _get_role(fields.get('role'))
+
+ if users: fields['user'] = users[0]
+ if slices: fields['site'] = sites[0]
+ if roles: fields['role'] = roles[0]
+
+ site_privilege = SitePrivilege(**fields)
+
+ # update nova role
+ driver.add_user_role(site_privilege.user.kuser_id,
+ site_privilege.site.tenant_id,
+ site_privilege.role.name)
+
+ site_privilege.save()
+ return site_privilege
+
+def update_site_privilege(auth, id, **fields):
+ return
+
+def delete_site_privilege(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ site_privileges = _get_site_privileges(filter)
+ for site_privilege in site_privileges:
+ driver.delete_user_role(kuser_id=site_privilege.user.id,
+ tenant_id = site_privilege.site.tenant_id,
+ role_name = site_privilege.role.name)
+ site_privilege.delete()
+ return 1
+
+def get_site_privileges(auth, filter={}):
+ client = auth_check(auth)
+ users = _get_users(filter.get('user'))
+ sites = _get_slices(filter.get('site'))
+ roles = _get_roles(filter.get('role'))
+
+ if users: filter['user'] = users[0]
+ if sites: filter['site'] = sites[0]
+ if roles: filter['role'] = roles[0]
+
+ site_privileges = _get_site_privileges(filter)
+ return site_privileges
+
+
+
diff --git a/planetstack/core/api/sites.py b/planetstack/core/api/sites.py
new file mode 100644
index 0000000..cfca6cf
--- /dev/null
+++ b/planetstack/core/api/sites.py
@@ -0,0 +1,62 @@
+from types import StringTypes
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import Site
+
+
+def _get_sites(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ sites = Site.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ sites = Site.objects.filter(login_base=filter)
+ elif isinstance(filter, dict):
+ sites = Site.objects.filter(**filter)
+ else:
+ sites = []
+ return sites
+
+def add_site(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ site = Site(**fields)
+ nova_fields = {'tenant_name': site.login_base,
+ 'description': site.name,
+ 'enabled': site.enabled}
+ tenant = driver.create_tenant(**nova_fields)
+ site.tenant_id=tenant.id
+ site.save()
+ return site
+
+def update_site(auth, id, **fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ sites = _get_sites(id)
+ if not sites:
+ return
+
+ site = Site[0]
+ nova_fields = {}
+ if 'description' in fields:
+ nova_fields['description'] = fields['name']
+ if 'enabled' in fields:
+ nova_fields['enabled'] = fields['enabled']
+ driver.update_tenant(site.tenant_id, **nova_fields)
+ site.update(**fields)
+ return site
+
+def delete_site(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ sites = _get_sites(id)
+ for site in sites:
+ driver.delete_tenant(id=site.tenant_id)
+ site.delete()
+ return 1
+
+def get_sites(auth, filter={}):
+ client = auth_check(auth)
+ sites = _get_sites(filter)
+ return sites
+
+
+
diff --git a/planetstack/core/api/slice_memberships.py b/planetstack/core/api/slice_memberships.py
new file mode 100644
index 0000000..77d79bf
--- /dev/null
+++ b/planetstack/core/api/slice_memberships.py
@@ -0,0 +1,71 @@
+from types import StringTypes
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import SliceMembership
+from core.api.users import _get_users
+from core.api.slices import _get_slices
+from core.api.roles import _get_roles
+
+def _get_slice_memberships(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ slice_memberships = SitePrivilege.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ slice_memberships = SitePrivilege.objects.filter(name=filter)
+ elif isinstance(filter, dict):
+ slice_memberships = SitePrivilege.objects.filter(**filter)
+ else:
+ slice_memberships = []
+ return slice_memberships
+
+
+def add_slice_membership(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ users = _get_users(fields.get('user'))
+ slices = _get_slices(fields.get('slice'))
+ roles = _get_roles(fields.get('role'))
+
+ if users: fields['user'] = users[0]
+ if slices: fields['slice'] = slices[0]
+ if roles: fields['role'] = roles[0]
+
+ slice_membership = SliceMembership(**fields)
+
+ # update nova role
+ driver.add_user_role(slice_membership.user.user_id,
+ slice_membership.slice.tenant_id,
+ slice_membership.role.name)
+
+ slice_membership.save()
+ return slice_membership
+
+def update_slice_membership(auth, id, **fields):
+ return
+
+def delete_slice_membership(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ slice_memberships = _get_slice_memberships(filter)
+ for slice_membership in slice_memberships:
+ driver.delete_user_role(kuser_id=slice_membership.user.id,
+ tenant_id = slice_membership.slice.tenant_id,
+ role_name = slice_membership.role.name)
+ slice_membership.delete()
+ return 1
+
+def get_slice_memberships(auth, filter={}):
+ client = auth_check(auth)
+ users = _get_users(fields.get('user'))
+ slices = _get_slices(fields.get('slice'))
+ roles = _get_roles(fields.get('role'))
+
+ if users: fields['user'] = users[0]
+ if slices: fields['slice'] = slices[0]
+ if roles: fields['role'] = roles[0]
+
+ slice_memberships = _get_slice_memberships(filter)
+ return slice_memberships
+
+
+
diff --git a/planetstack/core/api/slices.py b/planetstack/core/api/slices.py
new file mode 100644
index 0000000..f03dd6f
--- /dev/null
+++ b/planetstack/core/api/slices.py
@@ -0,0 +1,93 @@
+import re
+from types import StringTypes
+from django.contrib.auth import authenticate
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import Slice
+from core.api.sites import _get_sites
+
+def _get_slices(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ slices = Slice.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ slices = Slice.objects.filter(name=filter)
+ elif isinstance(filter, dict):
+ slices = Slice.objects.filter(**filter)
+ else:
+ slices = []
+ return slices
+
+
+def add_slice(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ login_base = fields['name'][:fields['name'].find('_')]
+ sites = _get_sites(login_base)
+ if sites: fields['site'] = sites[0]
+ slice = Slice(**fields)
+
+ # create tenant
+ nova_fields = {'tenant_name': slice.name,
+ 'description': slice.description,
+ 'enabled': slice.enabled}
+ tenant = driver.create_tenant(**nova_fields)
+ slice.tenant_id=tenant.id
+
+ # create network
+ network = driver.create_network(slice.name)
+ slice.network_id = network['id']
+
+ # create router
+ router = driver.create_router(slice.name)
+ slice.router_id = router['id']
+
+ slice.save()
+ return slice
+
+def update_slice(auth, id, **fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ slices = _get_slices(id)
+ if not slices:
+ return
+
+ # update tenant
+ slice = slices[0]
+ nova_fields = {}
+ if 'name' in fields:
+ nova_fields['tenant_name'] = fields['name']
+ if 'description' in fields:
+ nova_fields['description'] = fields['description']
+ if 'enabled' in fields:
+ nova_fields['enabled'] = fields['enabled']
+ driver.update_tenant(slice.tenant_id, **nova_fields)
+
+ # update db record
+ sites = _get_sites(fields.get('site'))
+ if sites: fields['site'] = sites[0]
+ slice.update(**fields)
+
+ return slice
+
+def delete_slice(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ slices = _get_slices(id)
+ for slice in slices:
+ driver.delete_network(slice.network_id)
+ driver.delete_router(slice.router_id)
+ driver.delete_slice(id=slice.tenant_id)
+ slice.delete()
+ return 1
+
+def get_slices(auth, filter={}):
+ user = authenticate(username=auth.get('username'),
+ password=auth.get('password'))
+ if 'site' in filter:
+ sites = _get_sites(filter.get('site'))
+ if sites: filter['site'] = sites[0]
+ slices = _get_slices(filter)
+ return slices
+
+
+
diff --git a/planetstack/core/api/slivers.py b/planetstack/core/api/slivers.py
new file mode 100644
index 0000000..e3244a4
--- /dev/null
+++ b/planetstack/core/api/slivers.py
@@ -0,0 +1,67 @@
+from types import StringTypes
+from django.contrib.auth import authenticate
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import Sliver, Slice
+from core.api.images import _get_images
+from core.api.keys import _get_keys
+from core.api.slices import _get_slices
+from core.api.deployment_networks import _get_deployment_networks
+from core.api.nodes import _get_nodes
+
+
+def _get_slivers(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ slivers = Sliver.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ slivers = Sliver.objects.filter(name=filter)
+ elif isinstance(filter, dict):
+ slivers = Sliver.objects.filter(**filter)
+ else:
+ slivers = []
+ return slivers
+
+def add_sliver(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+
+ images = _get_images(fields.get('image'))
+ if images: fields['image'] = images[0]
+ keys = _get_keys(fields.get('key'))
+ if keys: fields['key'] = keys[0]
+ slices = _get_slices(fields.get('slice'))
+ if slices:
+ fields['slice'] = slices[0]
+ deployment_networks = _get_deployment_networks(fields.get('deploymentNetwork'))
+ if deployment_networks: fields['deploymentNetwork'] = deployment_networks[0]
+ nodes = _get_nodes(fields.get('node'))
+ if nodes: fields['node'] = nodes[0]
+ sliver = Sliver(**fields)
+ sliver.driver = driver
+ sliver.save()
+ return sliver
+
+def update_sliver(auth, sliver, **fields):
+ return
+
+def delete_sliver(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ slivers = _get_slivers(filter)
+ for sliver in slivers:
+ sliver.driver = driver
+ sliver.delete()
+ return 1
+
+def get_slivers(auth, filter={}):
+ user = authenticate(username=auth.get('username'),
+ password=auth.get('password'))
+ if 'slice' in filter:
+ slices = _get_slices(filter.get('slice'))
+ if slices: filter['slice'] = slices[0]
+ slivers = _get_slivers(filter)
+ return slivers
+
+
+
diff --git a/planetstack/core/api/subnets.py b/planetstack/core/api/subnets.py
new file mode 100644
index 0000000..d618eda
--- /dev/null
+++ b/planetstack/core/api/subnets.py
@@ -0,0 +1,74 @@
+import commands
+from types import StringTypes
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import Subnet
+from core.api.slices import _get_slices
+
+
+def _get_subnets(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ subnets = Subnet.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ # the name is the subnet's slice's name
+ slices = _get_slices(filter)
+ slice = None
+ if slices: slice=slices[0]
+ subnets = Subnet.objects.filter(slice=slice)
+ elif isinstance(filter, dict):
+ subnets = Subnet.objects.filter(**filter)
+ else:
+ subnets = []
+ return subnets
+
+def add_subnet(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ slices = _get_slices(fields.get('slice'))
+ if slices: fields['slice'] = slices[0]
+ subnet = Subnet(**fields)
+ # create quantum subnet
+ quantum_subnet = driver.create_subnet(name= subnet.slice.name,
+ network_id=subnet.slice.network_id,
+ cidr_ip = subnet.cidr,
+ ip_version=subnet.ip_version,
+ start = subnet.start,
+ end = subnet.end)
+ subnet.subnet_id=quantum_subnet['id']
+ ## set dns servers
+ #driver.update_subnet(subnet.id, {'dns_nameservers': ['8.8.8.8', '8.8.4.4']})
+
+ # add subnet as interface to slice's router
+ try: driver.add_router_interface(subnet.slice.router_id, subnet.subnet_id)
+ except: pass
+ #add_route = 'route add -net %s dev br-ex gw 10.100.0.5' % self.cidr
+ commands.getstatusoutput(add_route)
+ subnet.save()
+ return subnet
+
+def update_subnet(auth, subnet, **fields):
+ return
+
+def delete_subnet(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ subnets = Subnet.objects.filter(**filter)
+ for subnet in subnets:
+ driver.delete_router_interface(subnet.slice.router_id, subnet.subnet_id)
+ driver.delete_subnet(subnet.subnet_id)
+ subnet.delete()
+ #del_route = 'route del -net %s' % subnet.cidr
+ commands.getstatusoutput(del_route)
+ return 1
+
+def get_subnets(auth, filter={}):
+ client = auth_check(auth)
+ if 'slice' in filter:
+ slice = _get_slice(filter.get('slice'))
+ if slice: filter['slice'] = slice
+ subnets = Subnet.objects.filter(**filter)
+ return subnets
+
+
+
diff --git a/planetstack/core/api/users.py b/planetstack/core/api/users.py
new file mode 100644
index 0000000..3b157ac
--- /dev/null
+++ b/planetstack/core/api/users.py
@@ -0,0 +1,71 @@
+from types import StringTypes
+from openstack.client import OpenStackClient
+from openstack.driver import OpenStackDriver
+from core.api.auth import auth_check
+from core.models import User, Site
+from core.api.sites import _get_sites
+
+def _get_users(filter):
+ if isinstance(filter, StringTypes) and filter.isdigit():
+ filter = int(filter)
+ if isinstance(filter, int):
+ users = User.objects.filter(id=filter)
+ elif isinstance(filter, StringTypes):
+ users = User.objects.filter(email=filter)
+ elif isinstance(filter, dict):
+ users = User.objects.filter(**filter)
+ else:
+ users = []
+ return users
+
+def add_user(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ sites = _get_sites(fields.get('site'))
+ if sites: fields['site'] = sites[0]
+ user = User(**fields)
+ nova_fields = {'name': user.email[:user.email.find('@')],
+ 'email': user.email,
+ 'password': fields.get('password'),
+ 'enabled': user.enabled}
+ nova_user = driver.create_user(**nova_fields)
+ #driver.add_user_user(user.id, user.site.tenant_id, 'user')
+ user.kuser_id=nova_user.id
+ user.save()
+ return user
+
+def update_user(auth, id, **fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ users = User.objects.filter(id=id)
+ if not users:
+ return
+
+ user = users[0]
+ nova_fields = {}
+ if 'email' in fields:
+ nova_fields['name'] = fields['email'][:self.email.find('@')]
+ nova_fields['email'] = fields['email']
+ if 'password' in fields:
+ nova_fields['password'] = fields['password']
+ if 'enabled' in fields:
+ nova_fields['enabled'] = fields['enabled']
+ driver.update_user(user.kuser_id, **nova_fields)
+ sites = _get_sites(fields.get('site'))
+ if sites: fields['site'] = sites[0]
+ user.update(**fields)
+ return user
+
+def delete_user(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ users = _get_users(filter)
+ for user in users:
+ driver.delete_user(id=user.kuser_id)
+ user.delete()
+ return 1
+
+def get_users(auth, filter={}):
+ client = auth_check(auth)
+ users = _get_users(filter)
+ return users
+
+
+
diff --git a/planetstack/core/api_root.py b/planetstack/core/api_root.py
new file mode 100644
index 0000000..61e76da
--- /dev/null
+++ b/planetstack/core/api_root.py
@@ -0,0 +1,18 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+
+@api_view(['GET'])
+def api_root(request, format=None):
+ return Response({
+ 'roles': reverse('role-list', request=request, format=format),
+ 'users': reverse('user-list', request=request, format=format),
+ 'keys': reverse('key-list', request=request, format=format),
+ #'nodes': reverse('node-list', request=request, format=format),
+ 'sites': reverse('site-list', request=request, format=format),
+ 'deploymentNetworks': reverse('deploymentnetwork-list', request=request, format=format),
+ 'slices': reverse('slice-list', request=request, format=format),
+ 'subnets': reverse('subnet-list', request=request, format=format),
+ 'slivers': reverse('sliver-list', request=request, format=format),
+ 'images': reverse('image-list', request=request, format=format),
+ })
diff --git a/planetstack/core/fixtures/__init__.py b/planetstack/core/fixtures/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/core/fixtures/__init__.py
diff --git a/planetstack/core/fixtures/initial_data.json b/planetstack/core/fixtures/initial_data.json
new file mode 100644
index 0000000..638b00d
--- /dev/null
+++ b/planetstack/core/fixtures/initial_data.json
@@ -0,0 +1,167 @@
+[
+{
+ "pk": 1,
+ "model": "core.deploymentnetwork",
+ "fields": {
+ "updated": "2013-04-03T22:57:09.331Z",
+ "name": "VICCI",
+ "created": "2013-04-03T22:57:09.331Z"
+ }
+},
+{
+ "pk": 2,
+ "model": "core.deploymentnetwork",
+ "fields": {
+ "updated": "2013-04-03T22:57:15.013Z",
+ "name": "VINI",
+ "created": "2013-04-03T22:57:15.013Z"
+ }
+},
+{
+ "pk": 3,
+ "model": "core.deploymentnetwork",
+ "fields": {
+ "updated": "2013-04-03T22:57:23.015Z",
+ "name": "PlanetLab Classic",
+ "created": "2013-04-03T22:57:23.015Z"
+ }
+},
+{
+ "pk": 4,
+ "model": "core.deploymentnetwork",
+ "fields": {
+ "updated": "2013-04-03T22:57:29.569Z",
+ "name": "GENI",
+ "created": "2013-04-03T22:57:29.569Z"
+ }
+},
+{
+ "pk": 1,
+ "model": "core.site",
+ "fields": {
+ "updated": "2013-04-05T15:21:04.135Z",
+ "name": "Princeton University",
+ "created": "2013-04-03T23:00:10.085Z",
+ "tenant_id": "",
+ "enabled": true,
+ "longitude": -74.6524,
+ "site_url": "http://princeton.edu/",
+ "login_base": "princeton",
+ "latitude": 40.3502,
+ "is_public": true,
+ "deployments": [
+ 3,
+ 4
+ ],
+ "abbreviated_name": ""
+ }
+},
+{
+ "pk": 2,
+ "model": "core.site",
+ "fields": {
+ "updated": "2013-04-05T15:42:36.517Z",
+ "name": "Stanford University",
+ "created": "2013-04-03T23:03:51.742Z",
+ "tenant_id": "",
+ "enabled": true,
+ "longitude": -122.172,
+ "site_url": "http://www.stanford.edu/",
+ "login_base": "stanford",
+ "latitude": 37.4294,
+ "is_public": true,
+ "deployments": [],
+ "abbreviated_name": ""
+ }
+},
+{
+ "pk": 3,
+ "model": "core.site",
+ "fields": {
+ "updated": "2013-04-05T15:42:17.263Z",
+ "name": "Georgia Institute of Technology",
+ "created": "2013-04-03T23:05:51.984Z",
+ "tenant_id": "",
+ "enabled": true,
+ "longitude": -84.3976,
+ "site_url": "http://www.gatech.edu/",
+ "login_base": "gt",
+ "latitude": 33.7772,
+ "is_public": true,
+ "deployments": [],
+ "abbreviated_name": ""
+ }
+},
+{
+ "pk": 4,
+ "model": "core.site",
+ "fields": {
+ "updated": "2013-04-05T15:39:27.501Z",
+ "name": "University of Washington",
+ "created": "2013-04-03T23:09:52.337Z",
+ "tenant_id": "",
+ "enabled": true,
+ "longitude": -122.313,
+ "site_url": "https://www.washington.edu/",
+ "login_base": "uw",
+ "latitude": 47.6531,
+ "is_public": true,
+ "deployments": [],
+ "abbreviated_name": ""
+ }
+},
+{
+ "pk": 5,
+ "model": "core.site",
+ "fields": {
+ "updated": "2013-04-05T15:38:56.889Z",
+ "name": "ETH Zuerich - Computer Science",
+ "created": "2013-04-03T23:14:11.072Z",
+ "tenant_id": "",
+ "enabled": true,
+ "longitude": 8.54513,
+ "site_url": "http://www.inf.ethz.ch/",
+ "login_base": "ethzcs",
+ "latitude": 47.3794,
+ "is_public": true,
+ "deployments": [],
+ "abbreviated_name": ""
+ }
+},
+{
+ "pk": 6,
+ "model": "core.site",
+ "fields": {
+ "updated": "2013-04-05T15:38:15.960Z",
+ "name": "Max Planck Institute for Software Systems",
+ "created": "2013-04-03T23:19:38.789Z",
+ "tenant_id": "",
+ "enabled": true,
+ "longitude": 6.589,
+ "site_url": "http://www.mpi-sws.mpg.de/",
+ "login_base": "mpisws",
+ "latitude": 49.14,
+ "is_public": true,
+ "deployments": [],
+ "abbreviated_name": ""
+ }
+},
+{
+ "pk": 7,
+ "model": "core.site",
+ "fields": {
+ "updated": "2013-04-05T15:37:32.185Z",
+ "name": "University of Tokyo",
+ "created": "2013-04-03T23:20:49.815Z",
+ "tenant_id": "",
+ "enabled": true,
+ "longitude": 139.5,
+ "site_url": "http://www.planet-lab-jp.org/",
+ "login_base": "utokyo",
+ "latitude": 35.75,
+ "is_public": true,
+ "deployments": [],
+ "abbreviated_name": ""
+ }
+}
+]
diff --git a/planetstack/core/models/__init__.py b/planetstack/core/models/__init__.py
new file mode 100644
index 0000000..4d9387b
--- /dev/null
+++ b/planetstack/core/models/__init__.py
@@ -0,0 +1,14 @@
+from .plcorebase import PlCoreBase
+from .deploymentnetwork import DeploymentNetwork
+from .site import Site
+from .site import SitePrivilege
+from .image import Image
+from .key import Key
+from .user import User
+from .role import Role
+from .node import Node
+from .slice import Slice
+from .slice import SliceMembership
+from .sliver import Sliver
+from .subnet import Subnet
+
diff --git a/planetstack/core/models/deploymentnetwork.py b/planetstack/core/models/deploymentnetwork.py
new file mode 100644
index 0000000..4068ee9
--- /dev/null
+++ b/planetstack/core/models/deploymentnetwork.py
@@ -0,0 +1,11 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+
+# Create your models here.
+
+class DeploymentNetwork(PlCoreBase):
+ name = models.CharField(max_length=200, unique=True, help_text="Name of the Deployment Network")
+
+ def __unicode__(self): return u'%s' % (self.name)
+
diff --git a/planetstack/core/models/image.py b/planetstack/core/models/image.py
new file mode 100644
index 0000000..b4803e2
--- /dev/null
+++ b/planetstack/core/models/image.py
@@ -0,0 +1,13 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+
+# Create your models here.
+
+class Image(PlCoreBase):
+ image_id = models.CharField(max_length=256, unique=True)
+ name = models.CharField(max_length=256, unique=True)
+ disk_format = models.CharField(max_length=256)
+ container_format = models.CharField(max_length=256)
+
+ def __unicode__(self): return u'%s' % (self.name)
diff --git a/planetstack/core/models/key.py b/planetstack/core/models/key.py
new file mode 100644
index 0000000..98cfb9b
--- /dev/null
+++ b/planetstack/core/models/key.py
@@ -0,0 +1,23 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+
+# Create your models here.
+
+class Key(PlCoreBase):
+ name = models.CharField(max_length=256, unique=True)
+ nkey_id = models.CharField(max_length=256, unique=True)
+ key = models.CharField(max_length=512)
+ type = models.CharField(max_length=256)
+ blacklisted = models.BooleanField(default=False)
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+ def save(self, *args, **kwds):
+ self.os_manager.save_key(self)
+ super(Key, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ self.os_manager.delete_key(self)
+ super(Key, self).delete(*args, **kwds)
+
diff --git a/planetstack/core/models/node.py b/planetstack/core/models/node.py
new file mode 100644
index 0000000..a249628
--- /dev/null
+++ b/planetstack/core/models/node.py
@@ -0,0 +1,14 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models import Site
+from core.models import DeploymentNetwork
+
+# Create your models here.
+
+class Node(PlCoreBase):
+ name = models.CharField(max_length=200, unique=True, help_text="Name of the Node")
+ site = models.ForeignKey(Site, related_name='nodes')
+ deploymentNetwork = models.ForeignKey(DeploymentNetwork, related_name='nodes')
+
+ def __unicode__(self): return u'%s' % (self.name)
diff --git a/planetstack/core/models/plcorebase.py b/planetstack/core/models/plcorebase.py
new file mode 100644
index 0000000..52aa0f7
--- /dev/null
+++ b/planetstack/core/models/plcorebase.py
@@ -0,0 +1,14 @@
+import os
+from django.db import models
+
+class PlCoreBase(models.Model):
+
+ created = models.DateTimeField(auto_now_add=True)
+ updated = models.DateTimeField(auto_now=True)
+
+ class Meta:
+ abstract = True
+ app_label = "core"
+
+
+
diff --git a/planetstack/core/models/role.py b/planetstack/core/models/role.py
new file mode 100644
index 0000000..b3611c1
--- /dev/null
+++ b/planetstack/core/models/role.py
@@ -0,0 +1,22 @@
+import os
+import datetime
+from django.db import models
+from core.models import PlCoreBase
+
+class Role(PlCoreBase):
+
+ #ROLE_CHOICES = (('admin', 'Admin'), ('pi', 'Principle Investigator'), ('user','User'))
+ role_id = models.CharField(max_length=256, unique=True)
+ role_type = models.CharField(max_length=80, unique=True)
+
+ def __unicode__(self): return u'%s' % (self.role_type)
+
+
+ def save(self, *args, **kwds):
+ self.os_manager.save_role(self)
+ super(Role, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ self.os_manager.delete_role(self)
+ super(Role, self).delete(*args, **kwds)
+
diff --git a/planetstack/core/models/site.py b/planetstack/core/models/site.py
new file mode 100644
index 0000000..ebf2ab9
--- /dev/null
+++ b/planetstack/core/models/site.py
@@ -0,0 +1,49 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models import DeploymentNetwork
+
+
+class Site(PlCoreBase):
+
+ tenant_id = models.CharField(max_length=200, help_text="Keystone tenant id")
+ name = models.CharField(max_length=200, help_text="Name for this Site")
+ site_url = models.URLField(null=True, blank=True, max_length=512, help_text="Site's Home URL Page")
+ enabled = models.BooleanField(default=True, help_text="Status for this Site")
+ longitude = models.FloatField(null=True, blank=True)
+ latitude = models.FloatField(null=True, blank=True)
+ login_base = models.CharField(max_length=50, unique=True, help_text="Prefix for Slices associated with this Site")
+ is_public = models.BooleanField(default=True, help_text="Indicates the visibility of this site to other members")
+ abbreviated_name = models.CharField(max_length=80)
+
+ deployments = models.ManyToManyField(DeploymentNetwork, blank=True, related_name='sites')
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+ def save(self, *args, **kwds):
+ self.os_manager.save_site(self)
+ super(Site, self).save(*args, **kwds)
+
+
+ def delete(self, *args, **kwds):
+ self.os_manager.delete_site(self)
+ super(Site, self).delete(*args, **kwds)
+
+
+class SitePrivilege(PlCoreBase):
+
+ user = models.ForeignKey('User', related_name='site_privileges')
+ site = models.ForeignKey('Site', related_name='site_privileges')
+ role = models.ForeignKey('Role')
+
+ def __unicode__(self): return u'%s %s %s' % (self.site, self.user, self.role)
+
+ def save(self, *args, **kwds):
+ self.os_manager.driver.add_user_role(self.user.kuser_id, self.site.tenant_id, self.role.role_type)
+ super(SitePrivilege, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ self.os_manager.driver.delete_user_role(self.user.kuser_id, self.site.tenant_id, self.role.role_type)
+ super(SitePrivilege, self).delete(*args, **kwds)
+
+
diff --git a/planetstack/core/models/slice.py b/planetstack/core/models/slice.py
new file mode 100644
index 0000000..539be24
--- /dev/null
+++ b/planetstack/core/models/slice.py
@@ -0,0 +1,51 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models import Site
+from core.models import User
+from core.models import Role
+from core.models import DeploymentNetwork
+
+# Create your models here.
+
+class Slice(PlCoreBase):
+ tenant_id = models.CharField(max_length=200, help_text="Keystone tenant id")
+ name = models.CharField(unique=True, help_text="The Name of the Slice", max_length=80)
+ enabled = models.BooleanField(default=True, help_text="Status for this Slice")
+ SLICE_CHOICES = (('plc', 'PLC'), ('delegated', 'Delegated'), ('controller','Controller'), ('none','None'))
+ instantiation = models.CharField(help_text="The instantiation type of the slice", max_length=80, choices=SLICE_CHOICES)
+ omf_friendly = models.BooleanField()
+ description=models.TextField(blank=True,help_text="High level description of the slice and expected activities", max_length=1024)
+ slice_url = models.URLField(blank=True, max_length=512)
+ site = models.ForeignKey(Site, related_name='slices', help_text="The Site this Node belongs too")
+ network_id = models.CharField(max_length=256, help_text="Quantum network")
+ router_id = models.CharField(max_length=256, help_text="Quantum router id")
+
+ SVC_CLASS_CHOICES = (('besteffort', 'Best Effort'), ('silver', 'Silver'), ('gold','Gold'))
+ serviceClass = models.CharField(verbose_name="Service Class",default="besteffort",help_text="The Service Class of this slice", max_length=30, choices=SVC_CLASS_CHOICES)
+
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+ def save(self, *args, **kwds):
+ self.os_manager.save_slice(self)
+ super(Slice, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ self.os_manager.delete_slice(self)
+ super(Slice, self).delete(*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')
+
+ def __unicode__(self): return u'%s %s %s' % (self.slice, self.user, self.role)
+
+ def save(self, *args, **kwds):
+ self.os_manager.driver.add_user_role(self.user.kuser_id, self.slice.tenant_id, self.role.role_type)
+ super(SliceMembership, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ self.os_manager.driver.delete_user_role(self.user.kuser_id, self.slice.tenant_id, self.role.role_type)
+ super(SliceMembership, self).delete(*args, **kwds)
diff --git a/planetstack/core/models/sliver.py b/planetstack/core/models/sliver.py
new file mode 100644
index 0000000..580c2af
--- /dev/null
+++ b/planetstack/core/models/sliver.py
@@ -0,0 +1,37 @@
+import os
+from django.db import models
+from django.core import exceptions
+from core.models import PlCoreBase
+from core.models import Image
+from core.models import Key
+from core.models import Slice
+from core.models import Node
+from core.models import Site
+from core.models import DeploymentNetwork
+
+# Create your models here.
+class Sliver(PlCoreBase):
+ instance_id = models.CharField(max_length=200, help_text="Nova instance id")
+ name = models.CharField(max_length=200, help_text="Sliver name")
+ instance_name = models.CharField(blank=True, null=True, max_length=200, help_text="OpenStack generated name")
+ ip = models.GenericIPAddressField(help_text="Sliver ip address", blank=True, null=True)
+ image = models.ForeignKey(Image, related_name='slivers')
+ key = models.ForeignKey(Key, related_name='slivers')
+ slice = models.ForeignKey(Slice, related_name='slivers')
+ node = models.ForeignKey(Node, related_name='slivers')
+ deploymentNetwork = models.ForeignKey(DeploymentNetwork, verbose_name='deployment', related_name='sliver_deploymentNetwork')
+ numberCores = models.IntegerField(verbose_name="Number of Cores", help_text="Number of cores for sliver", default=2)
+
+
+ def __unicode__(self): return u'%s' % (self.instance_name)
+
+ def save(self, *args, **kwds):
+ if not self.slice.subnet.exists():
+ raise exceptions.ValidationError, "Slice %s has no subnet" % self.slice.name
+
+ self.os_manager.save_sliver(self)
+ super(Sliver, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ self.os_manager.delete_sliver(self)
+ super(Sliver, self).delete(*args, **kwds)
diff --git a/planetstack/core/models/subnet.py b/planetstack/core/models/subnet.py
new file mode 100644
index 0000000..cad9fea
--- /dev/null
+++ b/planetstack/core/models/subnet.py
@@ -0,0 +1,25 @@
+import os
+import commands
+from django.db import models
+from core.models import PlCoreBase
+from core.models import Slice
+
+# Create your models here.
+
+class Subnet(PlCoreBase):
+ subnet_id = models.CharField(max_length=256, unique=True)
+ cidr = models.CharField(max_length=20)
+ ip_version = models.IntegerField()
+ start = models.IPAddressField()
+ end = models.IPAddressField()
+ slice = models.ForeignKey(Slice, related_name='subnet')
+
+ def __unicode__(self): return u'%s' % (self.slice.name)
+
+ def save(self, *args, **kwds):
+ self.os_manager.save_subnet(self)
+ super(Subnet, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ self.os_manager.delete_subnet(self)
+ super(Subnet, self).delete(*args, **kwds)
diff --git a/planetstack/core/models/user.py b/planetstack/core/models/user.py
new file mode 100644
index 0000000..6c776b1
--- /dev/null
+++ b/planetstack/core/models/user.py
@@ -0,0 +1,122 @@
+import os
+import datetime
+from django.db import models
+from core.models import PlCoreBase
+from core.models import Site
+from core.models import Key
+from openstack.manager import OpenStackManager
+from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
+
+# Create your models here.
+has_openstack = False
+
+class UserManager(BaseUserManager):
+ def create_user(self, email, firstname, lastname, password=None):
+ """
+ Creates and saves a User with the given email, date of
+ birth and password.
+ """
+ if not email:
+ raise ValueError('Users must have an email address')
+
+ user = self.model(
+ email=UserManager.normalize_email(email),
+ firstname=firstname,
+ lastname=lastname,
+ password=password
+ )
+ #user.set_password(password)
+ user.is_admin = True
+ user.save(using=self._db)
+ return user
+
+ def create_superuser(self, email, firstname, lastname, password):
+ """
+ Creates and saves a superuser with the given email, date of
+ birth and password.
+ """
+ user = self.create_user(email,
+ password=password,
+ firstname=firstname,
+ lastname=lastname
+ )
+ user.is_admin = True
+ user.save(using=self._db)
+ return user
+
+
+class User(AbstractBaseUser):
+
+ class Meta:
+ app_label = "core"
+
+ email = models.EmailField(
+ verbose_name='email address',
+ max_length=255,
+ unique=True,
+ db_index=True,
+ )
+
+ kuser_id = models.CharField(help_text="keystone user id", max_length=200)
+ firstname = models.CharField(help_text="person's given name", max_length=200)
+ lastname = models.CharField(help_text="person's surname", max_length=200)
+
+ 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)
+ key = models.ForeignKey(Key, related_name='user', null=True, blank=True)
+
+ is_active = models.BooleanField(default=True)
+ is_admin = models.BooleanField(default=True)
+ is_staff = models.BooleanField(default=True)
+
+ objects = UserManager()
+
+ USERNAME_FIELD = 'email'
+ REQUIRED_FIELDS = ['firstname', 'lastname']
+
+ def get_full_name(self):
+ # The user is identified by their email address
+ return self.email
+
+ def get_short_name(self):
+ # The user is identified by their email address
+ return self.email
+
+ def __unicode__(self):
+ return self.email
+
+ def has_perm(self, perm, obj=None):
+ "Does the user have a specific permission?"
+ # Simplest possible answer: Yes, always
+ return True
+
+ def has_module_perms(self, app_label):
+ "Does the user have permissions to view the app `app_label`?"
+ # Simplest possible answer: Yes, always
+ return True
+
+ @property
+ def is_staff(self):
+ "Is the user a member of staff?"
+ # Simplest possible answer: All admins are staff
+ return self.is_admin
+
+
+ def save(self, *args, **kwds):
+ if has_openstack:
+ if not hasattr(self, 'os_manager'):
+ setattr(self, 'os_manager', OpenStackManager())
+
+ self.os_manager.save_user(self)
+ if not self.id:
+ self.set_password(self.password)
+ super(User, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ if has_openstack:
+ if not hasattr(self, 'os_manager'):
+ setattr(self, 'os_manager', OpenStackManager())
+
+ self.os_manager.delete_user(self)
+ super(User, self).delete(*args, **kwds)
diff --git a/planetstack/core/serializers.py b/planetstack/core/serializers.py
new file mode 100644
index 0000000..55cf7c8
--- /dev/null
+++ b/planetstack/core/serializers.py
@@ -0,0 +1,210 @@
+from django.forms import widgets
+from rest_framework import serializers
+from core.models import *
+
+
+class RoleSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ class Meta:
+ model = Role
+ fields = ('id',
+ 'role_id',
+ 'role_type')
+
+
+class UserSerializer(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='site-privilege-detail')
+ class Meta:
+ model = User
+ fields = ('id',
+ 'user_id',
+ 'kuser_id',
+ 'firstname',
+ 'lastname',
+ 'email',
+ 'password',
+ 'phone',
+ 'user_url',
+ 'is_admin',
+ 'site',
+ 'slice_memberships',
+ 'site_privileges')
+
+class KeySerializer(serializers.HyperlinkedModelSerializer):
+ id = serializers.Field()
+ user = serializers.HyperlinkedRelatedField(view_name='user-detail')
+ class Meta:
+ model = Key
+ fields = ('id',
+ 'name',
+ 'key',
+ 'type',
+ 'blacklisted',
+ 'user')
+
+
+class SliceSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ site = serializers.HyperlinkedRelatedField(view_name='site-detail')
+ slivers = serializers.HyperlinkedRelatedField(view_name='sliver-detail')
+ subnet= serializers.HyperlinkedRelatedField(view_name='subnet-detail')
+ class Meta:
+ model = Slice
+ fields = ('id',
+ 'tenant_id',
+ 'enabled',
+ 'name',
+ 'url',
+ 'instantiation',
+ 'omf_friendly',
+ 'description',
+ 'slice_url',
+ 'network_id',
+ 'router_id',
+ 'site',
+ 'slivers',
+ 'updated',
+ 'created')
+
+class SliceMembershipSerializer(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 = SitePrivilege
+ fields = ('id',
+ 'user',
+ 'slice',
+ 'role')
+
+class SubnetSerializer(serializers.HyperlinkedModelSerializer):
+ id = serializers.Field()
+ slice = serializers.HyperlinkedRelatedField(view_name='slice-detail')
+ class Meta:
+ model = Subnet
+ fields = ('id',
+ 'subnet_id',
+ 'cidr',
+ 'ip_version',
+ 'start',
+ 'end',
+ 'slice')
+
+class SiteSerializer(serializers.HyperlinkedModelSerializer):
+
+ #Experimenting with whether to use ids, hyperlinks, or nested includes
+ #slices = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
+ #slices = serializers.RelatedField(many=True, read_only=True)
+ #slices = SliceSerializer(many=True)
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ slices = serializers.HyperlinkedRelatedField(many=True, read_only=True,view_name='slice-detail')
+
+ class Meta:
+ model = Site
+ fields = ('id',
+ 'url',
+ 'name',
+ 'slices',
+ 'site_url',
+ 'enabled',
+ 'longitude',
+ 'latitude',
+ 'login_base',
+ 'tenant_id',
+ 'is_public',
+ 'abbreviated_name',
+ 'updated',
+ 'created')
+
+class SitePrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+ id = serializers.Field()
+ site = serializers.HyperlinkedRelatedField(view_name='site-detail')
+ user = serializers.HyperlinkedRelatedField(view_name='user-detail')
+ role = serializers.HyperlinkedRelatedField(view_name='role-detail')
+ class Meta:
+ model = SitePrivilege
+ fields = ('id',
+ 'user',
+ 'site',
+ 'role')
+
+class DeploymentNetworkSerializer(serializers.HyperlinkedModelSerializer):
+
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ sites = serializers.HyperlinkedRelatedField(view_name='deploymentnetwork-detail')
+ class Meta:
+ model = DeploymentNetwork
+ 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')
+ key = serializers.HyperlinkedRelatedField(view_name='key-detail')
+ slice = serializers.HyperlinkedRelatedField(view_name='slice-detail')
+ deployment_network = serializers.HyperlinkedRelatedField(view_name='deployment_network-detail')
+ node = serializers.HyperlinkedRelatedField(view_name='node-detail')
+
+
+ #slice = serializers.PrimaryKeyRelatedField(read_only=True)
+
+ class Meta:
+ model = Sliver
+ fields = ('id',
+ 'instance_id',
+ 'name',
+ 'instance_name',
+ 'ip',
+ 'image',
+ 'key',
+ 'slice',
+ 'deploymentNetwork',
+ 'node')
+
+class NodeSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ class Meta:
+ model = Node
+ fields = ('id',
+ 'name')
+
+class ImageSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ class Meta:
+ model = Image
+ fields = ('id',
+ 'image_id',
+ 'name',
+ 'disk_format',
+ 'container_format')
+
+serializerLookUp = {
+ Role: RoleSerializer,
+ User: UserSerializer,
+ Key: KeySerializer,
+ Site: SiteSerializer,
+ SitePrivilege: SitePrivilegeSerializer,
+ Slice: SliceSerializer,
+ SliceMembership: SliceMembershipSerializer,
+ Subnet: SubnetSerializer,
+ Node: NodeSerializer,
+ Sliver: SliverSerializer,
+ DeploymentNetwork: DeploymentNetworkSerializer,
+ Image: ImageSerializer,
+ None: None,
+ }
+
diff --git a/planetstack/core/views/__init__.py b/planetstack/core/views/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/core/views/__init__.py
diff --git a/planetstack/core/views/deployment_networks.py b/planetstack/core/views/deployment_networks.py
new file mode 100644
index 0000000..63220a4
--- /dev/null
+++ b/planetstack/core/views/deployment_networks.py
@@ -0,0 +1,59 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.deployment_networks import add_deployment_network, delete_deployment_network, get_deployment_networks
+from core.serializers import DeploymentNetworkSerializer
+from util.request import parse_request
+
+
+class DeploymentNetworkListCreate(APIView):
+ """
+ List all deployment networks or create a new role.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'deploymentNetwork' in data:
+
+ deployment = add_deployment_network(data['auth'], data['deploymentNetwork'].get('name'))
+ serializer = DeploymentNetworkSerializer(deployment)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ deployment_networks = get_deployment_networks(data['auth'])
+ serializer = DeploymentNetworkSerializer(deployment_networks, many=True)
+ return Response(serializer.data)
+
+
+class DeploymentNetworkRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a deployment network
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a deployment network"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ deployment_networks = get_deployment_networks(data['auth'], pk)
+ if not deployment_networks:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = DeploymentNetworkSerializer(deployment_networks[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """deployment network update not implemnted"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_deployment_network(data['auth'], pk)
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/planetstack/core/views/images.py b/planetstack/core/views/images.py
new file mode 100644
index 0000000..7e0ab59
--- /dev/null
+++ b/planetstack/core/views/images.py
@@ -0,0 +1,55 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.images import add_image, delete_image, get_images
+from core.serializers import ImageSerializer
+from util.request import parse_request
+
+
+class ImageListCreate(APIView):
+ """
+ List all images or create a new image.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'image' in data:
+ """Not Implemented"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ else:
+ images = get_images(data['auth'])
+ serializer = ImageSerializer(images, many=True)
+ return Response(serializer.data)
+
+
+class ImageRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete an image
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve an image """
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ images = get_images(data['auth'], pk)
+ if not images:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = ImageSerializer(images[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update image not implemnted"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+
+ def delete(self, request, pk, format=None):
+ """delete image not implemnted"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+
+
+
+
diff --git a/planetstack/core/views/keys.py b/planetstack/core/views/keys.py
new file mode 100644
index 0000000..a5d0995
--- /dev/null
+++ b/planetstack/core/views/keys.py
@@ -0,0 +1,66 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.keys import add_key, delete_key, get_keys, update_key
+from core.serializers import KeySerializer
+from util.request import parse_request
+
+
+class KeyListCreate(APIView):
+ """
+ List all users or create a new key.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'key' in data:
+ key = add_key(data['auth'], data['key'])
+ serializer = KeySerializer(key)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ keys = get_keys(data['auth'])
+ serializer = KeySerializer(keys, many=True)
+ return Response(serializer.data)
+
+
+class KeyRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a key
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a key"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ keys = get_keys(data['auth'], pk)
+ if not keys:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = KeySerializer(keys[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update a key"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'key' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+
+ key = update_key(pk, data['key'])
+ serializer = KeySerializer(key)
+ return Response(serializer.data)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_key(data['auth'], pk)
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/planetstack/core/views/nodes.py b/planetstack/core/views/nodes.py
new file mode 100644
index 0000000..0f1977e
--- /dev/null
+++ b/planetstack/core/views/nodes.py
@@ -0,0 +1,55 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.nodes import add_node, delete_node, get_nodes, update_node
+from core.serializers import NodeSerializer
+from util.request import parse_request
+
+
+class NodeListCreate(APIView):
+ """
+ List all nodes or create a new node.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'node' in data:
+ """Not Implemented"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ else:
+ nodes = get_nodes(data['auth'])
+ serializer = NodeSerializer(nodes, many=True)
+ return Response(serializer.data)
+
+
+class NodeRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete an node
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve an node """
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ nodes = get_nodes(data['auth'], pk)
+ if not nodes:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = NodeSerializer(nodes[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update node not implemnted"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+
+ def delete(self, request, pk, format=None):
+ """delete node not implemnted"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+
+
+
+
diff --git a/planetstack/core/views/roles.py b/planetstack/core/views/roles.py
new file mode 100644
index 0000000..37bb149
--- /dev/null
+++ b/planetstack/core/views/roles.py
@@ -0,0 +1,58 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.roles import add_role, delete_role, get_roles
+from core.serializers import RoleSerializer
+from util.request import parse_request
+
+
+class RoleListCreate(APIView):
+ """
+ List all roles or create a new role.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'role' in data:
+ role = add_role(data['auth'], data['role']['role_type'])
+ serializer = RoleSerializer(data=role)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ roles = get_roles(data['auth'])
+ serializer = RoleSerializer(roles, many=True)
+ return Response(serializer.data)
+
+
+class RoleRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a role
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a role"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ roles = get_roles(data['auth'], pk)
+ if not roles:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = RoleSerializer(roles[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """role update not implemnted"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_role(data['auth'], pk)
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/planetstack/core/views/site_privileges.py b/planetstack/core/views/site_privileges.py
new file mode 100644
index 0000000..37fc371
--- /dev/null
+++ b/planetstack/core/views/site_privileges.py
@@ -0,0 +1,66 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.site_privileges import add_site_privilege, delete_site_privilege, get_site_privileges, update_site_privilege
+from core.serializers import SitePrivilegeSerializer
+from util.request import parse_request
+
+
+class SitePrivilegeListCreate(APIView):
+ """
+ List all site_privileges or create a new site_privilege.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'site_privilege' in data:
+ site_privilege = add_site_privilege(data['auth'], data['site_privilege'])
+ serializer = SitePrivilegeSerializer(site_privilege)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ site_privileges = get_site_privileges(data['auth'])
+ serializer = SitePrivilegeSerializer(site_privileges, many=True)
+ return Response(serializer.data)
+
+
+class SitePrivilegeRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a site_privilege
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a site_privilege"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ site_privileges = get_site_privileges(data['auth'], pk)
+ if not site_privileges:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = SitePrivilegeSerializer(site_privileges[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update a site_privilege"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'site_privilege' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+
+ site_privilege = update_site_privilege(pk, data['site_privilege'])
+ serializer = SitePrivilegeSerializer(site_privilege)
+ return Response(serializer.data)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_site_privilege(data['auth'], pk)
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/planetstack/core/views/sites.py b/planetstack/core/views/sites.py
new file mode 100644
index 0000000..6449b67
--- /dev/null
+++ b/planetstack/core/views/sites.py
@@ -0,0 +1,66 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.sites import add_site, delete_site, get_sites
+from core.serializers import SiteSerializer
+from util.request import parse_request
+
+
+class SiteListCreate(APIView):
+ """
+ List all sites or create a new site.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'site' in data:
+ site = add_site(data['auth'], data['site'])
+ serializer = SiteSerializer(site)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ sites = get_sites(data['auth'])
+ serializer = SiteSerializer(sites, many=True)
+ return Response(serializer.data)
+
+
+class SiteRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a site
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a site"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ sites = get_sites(data['auth'], {'id': pk})
+ if not sites:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = SiteSerializer(sites[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update a site"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'site' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+
+ site = update_site(pk, data['site'])
+ serializer = SiteSerializer(site)
+ return Response(serializer.data)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_site(data['auth'], {'id': pk})
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/planetstack/core/views/slice_memberships.py b/planetstack/core/views/slice_memberships.py
new file mode 100644
index 0000000..4bb581c
--- /dev/null
+++ b/planetstack/core/views/slice_memberships.py
@@ -0,0 +1,66 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.slice_memberships import add_slice_membership, delete_slice_membership, get_slice_memberships, update_slice_membership
+from core.serializers import SliceMembershipSerializer
+from util.request import parse_request
+
+
+class SliceMembershipListCreate(APIView):
+ """
+ List all slice_memberships or create a new slice_membership.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'slice_membership' in data:
+ slice_membership = add_slice_membership(data['auth'], data['slice_membership'])
+ serializer = SliceMembershipSerializer(slice_membership)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ slice_memberships = get_slice_memberships(data['auth'])
+ serializer = SliceMembershipSerializer(slice_memberships, many=True)
+ return Response(serializer.data)
+
+
+class SliceMembershipRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a slice_membership
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a slice_membership"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ slice_memberships = get_slice_memberships(data['auth'], pk)
+ if not slice_memberships:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = SliceMembershipSerializer(slice_memberships[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update a slice_membership"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'slice_membership' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+
+ slice_membership = update_slice_membership(pk, data['slice_membership'])
+ serializer = SliceMembershipSerializer(slice_membership)
+ return Response(serializer.data)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_slice_membership(data['auth'], pk)
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/planetstack/core/views/slices.py b/planetstack/core/views/slices.py
new file mode 100644
index 0000000..5954d0c
--- /dev/null
+++ b/planetstack/core/views/slices.py
@@ -0,0 +1,66 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.slices import add_slice, delete_slice, get_slices, update_slice
+from core.serializers import SliceSerializer
+from util.request import parse_request
+
+
+class SliceListCreate(APIView):
+ """
+ List all slices or create a new slice.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'slice' in data:
+ slice = add_slice(data['auth'], data['slice'])
+ serializer = SliceSerializer(slice)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ slices = get_slices(data['auth'])
+ serializer = SliceSerializer(slices, many=True)
+ return Response(serializer.data)
+
+
+class SliceRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a slice
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a slice"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ slices = get_slices(data['auth'], pk)
+ if not slices:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = SliceSerializer(slices[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update a slice"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'slice' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+
+ slice = update_slice(pk, data['slice'])
+ serializer = SliceSerializer(slice)
+ return Response(serializer.data)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_slice(data['auth'], pk)
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/planetstack/core/views/slivers.py b/planetstack/core/views/slivers.py
new file mode 100644
index 0000000..3741cce
--- /dev/null
+++ b/planetstack/core/views/slivers.py
@@ -0,0 +1,66 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.slivers import add_sliver, delete_sliver, get_slivers, update_sliver
+from core.serializers import SliverSerializer
+from util.request import parse_request
+
+
+class SliverListCreate(APIView):
+ """
+ List all slivers or create a new sliver.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'sliver' in data:
+ sliver = add_sliver(data['auth'], data['sliver'])
+ serializer = SliverSerializer(sliver)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ slivers = get_slivers(data['auth'])
+ serializer = SliverSerializer(slivers, many=True)
+ return Response(serializer.data)
+
+
+class SliverRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a sliver
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a sliver"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ slivers = get_slivers(data['auth'], pk)
+ if not slivers:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = SliverSerializer(slivers[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update a sliver"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'sliver' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+
+ sliver = update_sliver(pk, data['sliver'])
+ serializer = SliverSerializer(sliver)
+ return Response(serializer.data)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_sliver(data['auth'], pk)
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/planetstack/core/views/subnets.py b/planetstack/core/views/subnets.py
new file mode 100644
index 0000000..881f615
--- /dev/null
+++ b/planetstack/core/views/subnets.py
@@ -0,0 +1,66 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.subnets import add_subnet, delete_subnet, get_subnets, update_subnet
+from core.serializers import SubnetSerializer
+from util.request import parse_request
+
+
+class SubnetListCreate(APIView):
+ """
+ List all subnets or create a new subnet.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'subnet' in data:
+ subnet = add_subnet(data['auth'], data['subnet'])
+ serializer = SubnetSerializer(subnet)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ subnets = get_subnets(data['auth'])
+ serializer = SubnetSerializer(subnets, many=True)
+ return Response(serializer.data)
+
+
+class SubnetRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a subnet
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a subnet"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ subnets = get_subnets(data['auth'], {'id': pk})
+ if not subnets:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = SubnetSerializer(subnets[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update a subnet"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'subnet' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+
+ subnet = update_subnet(pk, data['subnet'])
+ serializer = SubnetSerializer(subnet)
+ return Response(serializer.data)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_subnet(data['auth'], {'id': pk})
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/planetstack/core/views/users.py b/planetstack/core/views/users.py
new file mode 100644
index 0000000..8b27928
--- /dev/null
+++ b/planetstack/core/views/users.py
@@ -0,0 +1,66 @@
+from django.http import Http404
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+
+from core.api.users import add_user, delete_user, get_users, update_user
+from core.serializers import UserSerializer
+from util.request import parse_request
+
+
+class UserListCreate(APIView):
+ """
+ List all users or create a new user.
+ """
+
+ def post(self, request, format = None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'user' in data:
+ user = add_user(data['auth'], data['user'])
+ serializer = UserSerializer(user)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ else:
+ users = get_users(data['auth'])
+ serializer = UserSerializer(users, many=True)
+ return Response(serializer.data)
+
+
+class UserRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete a user
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve a user"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ users = get_users(data['auth'], {'id': pk})
+ if not users:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = UserSerializer(users[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update a user"""
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ elif 'user' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+
+ user = update_user(pk, data['user'])
+ serializer = UserSerializer(user)
+ return Response(serializer.data)
+
+ def delete(self, request, pk, format=None):
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ delete_user(data['auth'], {'id': pk})
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+