organized
diff --git a/plstackapi/core/admin.py b/plstackapi/core/admin.py
new file mode 100644
index 0000000..c3b655f
--- /dev/null
+++ b/plstackapi/core/admin.py
@@ -0,0 +1,18 @@
+from plstackapi.core.models import *
+from django.contrib import admin
+
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.auth.models import User
+
+admin.site.register(Role)
+admin.site.register(Site)
+#admin.site.register(User)
+admin.site.register(Key)
+admin.site.register(Slice)
+admin.site.register(Node)
+admin.site.register(DeploymentNetwork)
+admin.site.register(SiteDeploymentNetwork)
+admin.site.register(Sliver)
+admin.site.register(Image)
+admin.site.register(Flavor)
+
diff --git a/plstackapi/core/api/__init__.py b/plstackapi/core/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plstackapi/core/api/__init__.py
diff --git a/plstackapi/core/api/auth.py b/plstackapi/core/api/auth.py
new file mode 100644
index 0000000..4054da6
--- /dev/null
+++ b/plstackapi/core/api/auth.py
@@ -0,0 +1,8 @@
+from plstackapi.openstack.client import OpenStackClient
+
+def auth_check(auth):
+ client = OpenStackClient(username=auth['Username'],
+ password=auth['AuthString'],
+ tenant=auth['LoginBase'])
+ client.authenticate()
+ return client
diff --git a/plstackapi/core/api/deployment_networks.py b/plstackapi/core/api/deployment_networks.py
new file mode 100644
index 0000000..812ca15
--- /dev/null
+++ b/plstackapi/core/api/deployment_networks.py
@@ -0,0 +1,26 @@
+from plstackapi.openstack.client import OpenStackClient
+from plstackapi.openstack.driver import OpenStackDriver
+from plstackapi.core.api.auth import auth_check
+from plstackapi.core.models import DeploymentNetwork
+
+
+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 = DeploymentNetwork.objects.filter(**filter)
+ for deployment in deployments:
+ deployment.delete()
+ return 1
+
+def get_deployment_networks(auth, filter={}):
+ auth_check(auth)
+ deployments = DeploymentNetwork.objects.filter(**filter)
+ return deployments
+
+
+
diff --git a/plstackapi/core/api/flavors.py b/plstackapi/core/api/flavors.py
new file mode 100644
index 0000000..a2d0b23
--- /dev/null
+++ b/plstackapi/core/api/flavors.py
@@ -0,0 +1,21 @@
+from plstackapi.openstack.client import OpenStackClient
+from plstackapi.openstack.driver import OpenStackDriver
+from plstackapi.core.api.auth import auth_check
+from plstackapi.core.models import Flavor
+
+
+def add_flavor(auth, fields={}):
+ """not implemented"""
+ return
+
+def delete_flavor(auth, filter={}):
+ """not implemented"""
+ return 1
+
+def get_flavors(auth, filter={}):
+ auth_check(auth)
+ flavors = Flavor.objects.filter(**filter)
+ return flavors
+
+
+
diff --git a/plstackapi/core/api/images.py b/plstackapi/core/api/images.py
new file mode 100644
index 0000000..b773b0b
--- /dev/null
+++ b/plstackapi/core/api/images.py
@@ -0,0 +1,21 @@
+from plstackapi.openstack.client import OpenStackClient
+from plstackapi.openstack.driver import OpenStackDriver
+from plstackapi.core.api.auth import auth_check
+from plstackapi.core.models import Image
+
+
+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 = Image.objects.filter(**filter)
+ return images
+
+
+
diff --git a/plstackapi/core/api/keys.py b/plstackapi/core/api/keys.py
new file mode 100644
index 0000000..af21f41
--- /dev/null
+++ b/plstackapi/core/api/keys.py
@@ -0,0 +1,45 @@
+from plstackapi.openstack.client import OpenStackClient
+from plstackapi.openstack.driver import OpenStackDriver
+from plstackapi.core.api.auth import auth_check
+from plstackapi.core.models import Key, User
+
+def lookup_user(fields):
+ user = None
+ if 'user' in fields:
+ if isinstance(fields['user'], int):
+ users = User.objects.filter(id=fields['user'])
+ else:
+ users = User.objects.filter(email=fields['user'])
+ if users:
+ user = users[0]
+ return user
+
+def add_key(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ user = lookup_user(fields)
+ if user: fields['user'] = user
+ key = Key(**fields)
+ nova_fields = {'name': key.name,
+ 'key': key.key}
+ nova_key = driver.create_keypair(**nova_fields)
+ key.save()
+ return key
+
+def update_key(auth, id, **fields):
+ return
+
+def delete_key(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ keys = Key.objects.filter(**filter)
+ for key in keys:
+ driver.delete_keypair(name=key.name)
+ key.delete()
+ return 1
+
+def get_keys(auth, filter={}):
+ client = auth_check(auth)
+ keys = Key.objects.filter(**filter)
+ return keys
+
+
+
diff --git a/plstackapi/core/api/roles.py b/plstackapi/core/api/roles.py
new file mode 100644
index 0000000..844fb4f
--- /dev/null
+++ b/plstackapi/core/api/roles.py
@@ -0,0 +1,28 @@
+from plstackapi.openstack.client import OpenStackClient
+from plstackapi.openstack.driver import OpenStackDriver
+from plstackapi.core.api.auth import auth_check
+from plstackapi.core.models import Role
+
+
+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 = Role.objects.filter(**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)
+ roles = Role.objects.filter(**filter)
+ return roles
+
+
+
diff --git a/plstackapi/core/api/sites.py b/plstackapi/core/api/sites.py
new file mode 100644
index 0000000..0d07605
--- /dev/null
+++ b/plstackapi/core/api/sites.py
@@ -0,0 +1,48 @@
+from plstackapi.openstack.client import OpenStackClient
+from plstackapi.openstack.driver import OpenStackDriver
+from plstackapi.core.api.auth import auth_check
+from plstackapi.core.models import Site
+
+
+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 = Site.objects.filter(id=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 = Site.objects.filter(**filter)
+ 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 = Site.objects.filter(**filter)
+ return sites
+
+
+
diff --git a/plstackapi/core/api/users.py b/plstackapi/core/api/users.py
new file mode 100644
index 0000000..6862e30
--- /dev/null
+++ b/plstackapi/core/api/users.py
@@ -0,0 +1,67 @@
+from plstackapi.openstack.client import OpenStackClient
+from plstackapi.openstack.driver import OpenStackDriver
+from plstackapi.core.api.auth import auth_check
+from plstackapi.core.models import User, Site
+
+def lookup_site(fields):
+ site = None
+ if 'site' in fields:
+ if isinstance(fields['site'], int):
+ sites = Site.objects.filter(id=fields['site'])
+ else:
+ sites = Site.objects.filter(login_base=fields['site'])
+ if sites:
+ site = sites[0]
+ return site
+
+def add_user(auth, fields):
+ driver = OpenStackDriver(client = auth_check(auth))
+ site = lookup_site(fields)
+ if site: fields['site'] = site
+ 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_role(user.id, user.site.tenant_id, 'user')
+ user.user_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.user_id, **nova_fields)
+ site = lookup_site(fields)
+ if site: fields['site'] = site
+ user.update(**fields)
+ return user
+
+def delete_user(auth, filter={}):
+ driver = OpenStackDriver(client = auth_check(auth))
+ users = User.objects.filter(**filter)
+ for user in users:
+ driver.delete_user(id=user.user_id)
+ user.delete()
+ return 1
+
+def get_users(auth, filter={}):
+ client = auth_check(auth)
+ users = User.objects.filter(**filter)
+ return users
+
+
+
diff --git a/plstackapi/core/fixtures/__init__.py b/plstackapi/core/fixtures/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plstackapi/core/fixtures/__init__.py
diff --git a/plstackapi/core/fixtures/initial_data.json b/plstackapi/core/fixtures/initial_data.json
new file mode 100644
index 0000000..62d943b
--- /dev/null
+++ b/plstackapi/core/fixtures/initial_data.json
@@ -0,0 +1 @@
+[{"pk": 1, "model": "plstackapi.planetstack.deploymentnetwork", "fields": {"updated": "2013-03-20T01:18:31.247Z", "name": "VICCI", "created": "2013-03-20T01:18:31.247Z"}}, {"pk": 2, "model": "plstackapi.planetstack.deploymentnetwork", "fields": {"updated": "2013-03-20T01:19:00.063Z", "name": "VINI", "created": "2013-03-20T01:19:00.063Z"}}, {"pk": 3, "model": "plstackapi.planetstack.deploymentnetwork", "fields": {"updated": "2013-03-20T01:19:15.143Z", "name": "GENI", "created": "2013-03-20T01:19:15.143Z"}}, {"pk": 4, "model": "plstackapi.planetstack.deploymentnetwork", "fields": {"updated": "2013-03-20T01:19:40.098Z", "name": "PlanetLab Classic", "created": "2013-03-20T01:19:25.672Z"}}]
diff --git a/plstackapi/core/models.py b/plstackapi/core/models.py
new file mode 100644
index 0000000..1ae0a44
--- /dev/null
+++ b/plstackapi/core/models.py
@@ -0,0 +1,261 @@
+import os
+import datetime
+from django.db import models
+from plstackapi.openstack.driver import OpenStackDriver
+
+# Create your models here.
+
+class PlCoreBase(models.Model):
+
+ created = models.DateTimeField(auto_now_add=True)
+ updated = models.DateTimeField(auto_now=True)
+
+ class Meta:
+ abstract = True
+
+ def save(self):
+ if not self.id:
+ self.created = datetime.date.today()
+ self.updated = datetime.datetime.today()
+ super(PlCoreBase, self).save()
+
+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, choices=ROLE_CHOICES)
+
+ def __unicode__(self): return u'%s' % (self.role_type)
+
+ def save(self):
+ if not self.id:
+ self.created = datetime.date.today()
+ self.updated = datetime.datetime.today()
+ super(Role, self).save()
+
+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)
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+
+class User(PlCoreBase):
+ user_id = models.CharField(max_length=256, unique=True)
+ firstname = models.CharField(help_text="person's given name", max_length=200)
+ lastname = models.CharField(help_text="person's surname", max_length=200)
+ email = models.EmailField(help_text="e-mail address")
+ phone = models.CharField(null=True, blank=True, help_text="phone number contact", max_length=100)
+ user_url = models.URLField(null=True, blank=True)
+ is_admin = models.BooleanField(default=False)
+ enabled = models.BooleanField(default=True, help_text="Status for this User")
+ site = models.ForeignKey(Site, related_name='users', verbose_name="Site this user will be homed too")
+
+ def __unicode__(self): return u'%s' % (self.email)
+
+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):
+ driver = OpenStackDriver()
+ driver.add_user_role(user_id=user.user_id,
+ tenant_id=site.tenant_id,
+ role_name=role.name)
+ super(SitePrivilege, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ driver = OpenStackDriver()
+ driver.delete_user_role(user_id=user.user_id,
+ tenant_id=site.tenant_id,
+ role_name=role.name)
+ super(SitePrivilege, self).delete(*args, **kwds)
+
+
+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)
+
+class SiteDeploymentNetwork(PlCoreBase):
+ class Meta:
+ unique_together = ['site', 'deploymentNetwork']
+
+ site = models.ForeignKey(Site, related_name='deployment_networks')
+ deploymentNetwork = models.ForeignKey(DeploymentNetwork, related_name='sites')
+ name = models.CharField(default="Blah", max_length=100)
+
+
+ def __unicode__(self): return u'%s::%s' % (self.site, self.deploymentNetwork)
+
+
+class Slice(PlCoreBase):
+ tenant_id = models.CharField(max_length=200, help_text="Keystone tenant id")
+ name = models.CharField(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")
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+ def save(self, *args, **kwds):
+ # sync keystone tenant
+ driver = OpenStackDriver()
+
+ if not self.id:
+ tenant = driver.create_tenant(tenant_name=self.name,
+ description=self.description,
+ enabled=self.enabled)
+ self.tenant_id = tenant.id
+
+ # create a network
+ network = driver.create_network(name=self.name)
+ self.network_id = network['id']
+ # create router
+ router = driver.create_router(name=self.name)
+ self.router_id = router['id']
+
+ else:
+ # update record
+ self.driver.update_tenant(self.tenant_id, name=self.name,
+ description=self.description, enabled=self.enabled)
+ super(Slice, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ # delete keystone tenant
+ driver = OpenStackDriver()
+ driver.delete_tenant(self.tenant_id)
+ 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):
+ driver = OpenStackDriver()
+ driver.add_user_role(user_id=user.user_id,
+ tenant_id=slice.tenant_id,
+ role_name=role.name)
+ super(SliceMembership, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ driver = OpenStackDriver()
+ driver.delete_user_role(user_id=user.user_id,
+ tenant_id=slice.tenant_id,
+ role_name=role.name)
+ super(SliceMembership, self).delete(*args, **kwds)
+
+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='subnets')
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+ def save(self, *args, **kwargs):
+ driver = OpenStackDriver()
+ if not self.id:
+ subnet = driver.create_subnet(network_name=self.slice.name,
+ cidr_ip = self.cidr,
+ ip_version=self.ip_version,
+ start = self.start,
+ end = self.end)
+
+ self.subnet_id = subnet.id
+
+ # add subnet as interface to slice router
+ driver.add_router_interface(self.slice.router_id, subnet.id)
+
+ super(SubNet, self).save(*args, **kwargs)
+
+
+ def delete(self, *args, **kwargs):
+ # delete quantum network
+ driver = OpenStackDriver()
+ driver.delete_subnet(self.subnet_id)
+ driver.delete_router_interface(self.slice.router_id, self.subnet.id)
+ super(SubNet, self).delete(*args, **kwargs)
+
+class Node(PlCoreBase):
+ name = models.CharField(max_length=200, unique=True, help_text="Name of the Node")
+ siteDeploymentNetwork = models.ForeignKey(SiteDeploymentNetwork, help_text="The Site and Deployment Network this Node belongs too.")
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+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)
+
+
+class Flavor(PlCoreBase):
+ flavor_id = models.IntegerField(unique=True)
+ name = models.CharField(max_length=256, unique=True)
+ memory_mb = models.IntegerField()
+ disk_gb = models.IntegerField()
+ vcpus = models.IntegerField()
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+class Key(PlCoreBase):
+ name = models.CharField(max_length=256, unique=True)
+ key = models.CharField(max_length=512)
+ type = models.CharField(max_length=256)
+ blacklisted = models.BooleanField(default=False)
+ user = models.ForeignKey(User, related_name='keys')
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+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")
+ flavor = models.ForeignKey(Flavor)
+ image = models.ForeignKey(Image)
+ key = models.ForeignKey(Key)
+ slice = models.ForeignKey(Slice)
+ siteDeploymentNetwork = models.ForeignKey(SiteDeploymentNetwork)
+ node = models.ForeignKey(Node)
+
+ def __unicode__(self): return u'%s::%s' % (self.slice, self.siteDeploymentNetwork)
+
+ def save(self, *args, **kwds):
+ driver = OpenStackDriver()
+ instance = driver.spawn_instances(name=self.name,
+ keyname=self.name,
+ hostnames=self.node.name,
+ flavor=self.flavor.name,
+ image=self.image.name)
+ self.instance_id = instance.id
+ super(Sliver, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ driver = OpenStackDriver()
+ driver.destroy_instance(name=self.name, id=self.instance_id)
+ super(Sliver, self).delete(*args, **kwds)
+
diff --git a/plstackapi/core/serializers.py b/plstackapi/core/serializers.py
new file mode 100644
index 0000000..0ffd86b
--- /dev/null
+++ b/plstackapi/core/serializers.py
@@ -0,0 +1,179 @@
+from django.forms import widgets
+from rest_framework import serializers
+from plstackapi.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',
+ 'firstname',
+ 'lastname',
+ 'email',
+ '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')
+
+ class Meta:
+ model = Slice
+ fields = ('id',
+ 'url',
+ 'name',
+ 'instantiation',
+ 'omf_friendly',
+ 'description',
+ 'slice_url',
+ 'site',
+ 'updated',
+ 'created')
+
+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')
+ deployment_networks = serializers.HyperlinkedRelatedField(many=True, read_only=True,view_name='sitedeploymentnetwork-detail')
+
+ class Meta:
+ model = Site
+ fields = ('id',
+ 'url',
+ 'name',
+ 'deployment_networks',
+ 'slices',
+ 'site_url',
+ 'enabled',
+ 'longitude',
+ 'latitude',
+ 'login_base',
+ 'tenant_id',
+ 'is_public',
+ 'abbreviated_name',
+ 'updated',
+ 'created')
+
+class DeploymentNetworkSerializer(serializers.HyperlinkedModelSerializer):
+
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ sites = serializers.HyperlinkedRelatedField(view_name='sitedeploymentnetwork-detail')
+ class Meta:
+ model = DeploymentNetwork
+ fields = ('id',
+ 'name',
+ 'sites'
+ )
+
+class SiteDeploymentNetworkSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ site = serializers.HyperlinkedRelatedField(view_name='site-detail')
+ deploymentNetwork = serializers.HyperlinkedRelatedField(view_name='deploymentnetwork-detail')
+
+ class Meta:
+ model = SiteDeploymentNetwork
+ fields = ('id',
+ 'url',
+ 'site',
+ 'deploymentNetwork')
+
+class SliverSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ slice = serializers.RelatedField(read_only=True)
+ #slice = serializers.PrimaryKeyRelatedField(read_only=True)
+
+ class Meta:
+ model = Sliver
+ fields = ('id',
+ 'slice',
+ 'name')
+
+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')
+
+class FlavorSerializer(serializers.HyperlinkedModelSerializer):
+ # HyperlinkedModelSerializer doesn't include the id by default
+ id = serializers.Field()
+ class Meta:
+ model = Flavor
+ fields = ('id',
+ 'flavor_id',
+ 'name',
+ 'memory_mb',
+ 'disk_gb',
+ 'vcpus')
+
+serializerLookUp = {
+ Role: RoleSerializer,
+ User: UserSerializer,
+ Key: KeySerializer,
+ Site: SiteSerializer,
+ Slice: SliceSerializer,
+ Node: NodeSerializer,
+ Sliver: SliverSerializer,
+ DeploymentNetwork: DeploymentNetworkSerializer,
+ SiteDeploymentNetwork: SiteDeploymentNetworkSerializer,
+ Image: ImageSerializer,
+ Flavor: FlavorSerializer,
+ None: None,
+ }
+
diff --git a/plstackapi/core/urls.py b/plstackapi/core/urls.py
new file mode 100644
index 0000000..b34e89a
--- /dev/null
+++ b/plstackapi/core/urls.py
@@ -0,0 +1,68 @@
+from django.conf.urls import patterns, include, url
+
+# Uncomment the next two lines to enable the admin:
+from django.contrib import admin
+from plstackapi.core.views.roles import RoleListCreate, RoleRetrieveUpdateDestroy
+from plstackapi.core.views.sites import SiteListCreate, SiteRetrieveUpdateDestroy
+from plstackapi.core.views.users import UserListCreate, UserRetrieveUpdateDestroy
+from plstackapi.core.views.keys import KeyListCreate, KeyRetrieveUpdateDestroy
+from plstackapi.core.views.deployment_networks import DeploymentNetworkListCreate, DeploymentNetworkRetrieveUpdateDestroy
+from plstackapi.core.views.images import ImageListCreate, ImageRetrieveUpdateDestroy
+from plstackapi.core.views.flavors import FlavorListCreate, FlavorRetrieveUpdateDestroy
+from plstackapi.core.models import Site
+from plstackapi.planetstack.api_root import api_root
+from rest_framework import generics
+
+admin.autodiscover()
+
+urlpatterns = patterns('',
+ # Examples:
+ # url(r'^$', 'planetstack.views.home', name='home'),
+ # url(r'^planetstack/', include('planetstack.foo.urls')),
+
+ # Uncomment the admin/doc line below to enable admin documentation:
+ # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+ # Uncomment the next line to enable the admin:
+ url(r'^admin/', include(admin.site.urls)),
+
+ url(r'^plstackapi/$', api_root),
+
+ url(r'^plstackapi/roles/$', RoleListCreate.as_view(), name='role-list'),
+ url(r'^plstackapi/roles/(?P<pk>[a-zA-Z0-9]+)/$', RoleRetrieveUpdateDestroy.as_view(), name='role-detail'),
+
+ url(r'^plstackapi/users/$', UserListCreate.as_view(), name='user-list'),
+ url(r'^plstackapi/users/(?P<pk>[a-zA-Z0-9]+)/$', UserRetrieveUpdateDestroy.as_view(), name='user-detail'),
+
+ url(r'^plstackapi/keys/$', KeyListCreate.as_view(), name='key-list'),
+ url(r'^plstackapi/keys/(?P<pk>[a-zA-Z0-9]+)/$', KeyRetrieveUpdateDestroy.as_view(), name='key-detail'),
+
+ url(r'^plstackapi/sites/$', SiteListCreate.as_view(), name='site-list'),
+ url(r'^plstackapi/sites/(?P<pk>[a-zA-Z0-9_]+)/$', SiteRetrieveUpdateDestroy.as_view(), name='site-detail'),
+
+
+ #url(r'^plstackapi/slices/$', views.SliceList.as_view(), name='slice-list'),
+ #url(r'^plstackapi/slices/(?P<pk>[0-9]+)/$', views.SliceDetail.as_view(), name='slice-detail'),
+
+ #url(r'^plstackapi/slivers/$', views.SliverList.as_view()),
+ #url(r'^plstackapi/slivers/(?P<pk>[0-9]+)/$', views.SliverDetail.as_view()),
+
+ #url(r'^plstackapi/nodes/$', views.NodeList.as_view(), name='node-list'),
+ #url(r'^plstackapi/nodes/(?P<pk>[0-9]+)/$', views.NodeDetail.as_view(), name='node-detail'),
+
+
+ url(r'^plstackapi/deploymentnetworks/$', DeploymentNetworkListCreate.as_view(), name='deploymentnetwork-list'),
+ url(r'^plstackapi/deploymentnetworks/(?P<pk>[a-zA-Z0-9]+)/$', DeploymentNetworkRetrieveUpdateDestroy.as_view(), name='deploymentnetwork-detail'),
+
+ #url(r'^plstackapi/sitedeploymentnetworks/$', views.SiteDeploymentNetworkList.as_view(), name='sitedeploymentnetwork-list'),
+ #url(r'^plstackapi/sitedeploymentnetworks/(?P<pk>[0-9]+)/$', views.SiteDeploymentNetworkDetail.as_view(), name='sitedeploymentnetwork-detail'),
+
+ url(r'^plstackapi/images/$', ImageListCreate.as_view(), name='image-list'),
+ url(r'^plstackapi/images/(?P<pk>[a-zA-Z0-9_]+)/$', ImageRetrieveUpdateDestroy.as_view(), name='image-detail'),
+
+ url(r'^plstackapi/flavors/$', FlavorListCreate.as_view(), name='flavor-list'),
+ url(r'^plstackapi/flavors/(?P<pk>[a-zA-Z0-9_]+)/$', FlavorRetrieveUpdateDestroy.as_view(), name='flavor-detail'),
+ #Adding in rest_framework urls
+ url(r'^plstackapi/', include('rest_framework.urls', namespace='rest_framework')),
+
+)
diff --git a/plstackapi/core/views/__init__.py b/plstackapi/core/views/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plstackapi/core/views/__init__.py
diff --git a/plstackapi/core/views/api_root.py b/plstackapi/core/views/api_root.py
new file mode 100644
index 0000000..10ceae1
--- /dev/null
+++ b/plstackapi/core/views/api_root.py
@@ -0,0 +1,17 @@
+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)
+ 'images': reverse('image-list', request=request, format=format),
+ 'flavors': reverse('flavor-list', request=request, format=format),
+ })
diff --git a/plstackapi/core/views/deployment_networks.py b/plstackapi/core/views/deployment_networks.py
new file mode 100644
index 0000000..60e8030
--- /dev/null
+++ b/plstackapi/core/views/deployment_networks.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 plstackapi.core.api.deployment_networks import add_deployment_network, delete_deployment_network, get_deployment_networks
+from plstackapi.core.serializers import DeploymentNetworkSerializer
+from plstackapi.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 'deployment_network' in data:
+ deployment = add_deployment_network(data['auth'], data['deployment_network'].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'], {'name': 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'], {'name': pk})
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/plstackapi/core/views/flavors.py b/plstackapi/core/views/flavors.py
new file mode 100644
index 0000000..ef48499
--- /dev/null
+++ b/plstackapi/core/views/flavors.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 plstackapi.core.api.flavors import add_flavor, delete_flavor, get_flavors
+from plstackapi.core.serializers import FlavorSerializer
+from plstackapi.util.request import parse_request
+
+
+class FlavorListCreate(APIView):
+ """
+ List all flavors or create a new flavor.
+ """
+
+ 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 'flavor' in data:
+ """Not Implemented"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ else:
+ flavors = get_flavors(data['auth'])
+ serializer = FlavorSerializer(flavors, many=True)
+ return Response(serializer.data)
+
+
+class FlavorRetrieveUpdateDestroy(APIView):
+ """
+ Retrieve, update or delete an flavor
+ """
+
+ def post(self, request, pk, format=None):
+ """Retrieve an flavor """
+ data = parse_request(request.DATA)
+ if 'auth' not in data:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ flavors = get_flavors(data['auth'], {'id': pk})
+ if not flavors:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ serializer = FlavorSerializer(flavors[0])
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ """update flavor not implemnted"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+
+ def delete(self, request, pk, format=None):
+ """delete flavor not implemnted"""
+ return Response(status=status.HTTP_404_NOT_FOUND)
+
+
+
+
diff --git a/plstackapi/core/views/images.py b/plstackapi/core/views/images.py
new file mode 100644
index 0000000..f48cb71
--- /dev/null
+++ b/plstackapi/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 plstackapi.core.api.images import add_image, delete_image, get_images
+from plstackapi.core.serializers import ImageSerializer
+from plstackapi.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'], {'id': 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/plstackapi/core/views/keys.py b/plstackapi/core/views/keys.py
new file mode 100644
index 0000000..6b52b8e
--- /dev/null
+++ b/plstackapi/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 plstackapi.core.api.keys import add_key, delete_key, get_keys, update_key
+from plstackapi.core.serializers import KeySerializer
+from plstackapi.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'], {'id': 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'], {'id': pk})
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/plstackapi/core/views/roles.py b/plstackapi/core/views/roles.py
new file mode 100644
index 0000000..05eb77e
--- /dev/null
+++ b/plstackapi/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 plstackapi.core.api.roles import add_role, delete_role, get_roles
+from plstackapi.core.serializers import RoleSerializer
+from plstackapi.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']['name'])
+ 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'], {'role_id': 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'], {'role_id': pk})
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
diff --git a/plstackapi/core/views/sites.py b/plstackapi/core/views/sites.py
new file mode 100644
index 0000000..700547c
--- /dev/null
+++ b/plstackapi/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 plstackapi.core.api.sites import add_site, delete_site, get_sites
+from plstackapi.core.serializers import SiteSerializer
+from plstackapi.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/plstackapi/core/views/users.py b/plstackapi/core/views/users.py
new file mode 100644
index 0000000..0ec867f
--- /dev/null
+++ b/plstackapi/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 plstackapi.core.api.users import add_user, delete_user, get_users, update_user
+from plstackapi.core.serializers import UserSerializer
+from plstackapi.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)
+
+
+