Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi
diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py
index 60a589c..93c14ee 100644
--- a/planetstack/core/admin.py
+++ b/planetstack/core/admin.py
@@ -39,12 +39,62 @@
exclude = ['enacted']
extra = 1
+class NetworkLookerUpper:
+ """ This is a callable that looks up a network name in a sliver and returns
+ the ip address for that network.
+ """
+
+ def __init__(self, name):
+ self.short_description = name
+ self.__name__ = name
+ self.network_name = name
+
+ def __call__(self, obj):
+ if obj is not None:
+ for nbs in obj.networksliver_set.all():
+ if (nbs.network.name == self.network_name):
+ return nbs.ip
+ return ""
+
+ def __str__(self):
+ return self.network_name
+
class SliverInline(PlStackTabularInline):
model = Sliver
fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
extra = 0
- #readonly_fields = ['ip', 'instance_name', 'image']
readonly_fields = ['ip', 'instance_name']
+
+
+ def _declared_fieldsets(self):
+ # Return None so django will call get_fieldsets and we can insert our
+ # dynamic fields
+ return None
+
+ def get_readonly_fields(self, request, obj=None):
+ readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
+
+ # Lookup the networks that are bound to the slivers, and add those
+ # network names to the list of readonly fields.
+
+ for sliver in obj.slivers.all():
+ for nbs in sliver.networksliver_set.all():
+ if nbs.ip:
+ network_name = nbs.network.name
+ if network_name not in [str(x) for x in readonly_fields]:
+ readonly_fields.append(NetworkLookerUpper(network_name))
+
+ return readonly_fields
+
+ def get_fieldsets(self, request, obj=None):
+ form = self.get_formset(request, obj).form
+ # fields = the read/write files + the read-only fields
+ fields = self.fields
+ for fieldName in self.get_readonly_fields(request,obj):
+ if not fieldName in fields:
+ fields.append(fieldName)
+
+ return [(None, {'fields': fields})]
class SiteInline(PlStackTabularInline):
@@ -121,6 +171,12 @@
return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+class SliceNetworkInline(PlStackTabularInline):
+ model = Network.slices.through
+ extra = 0
+ verbose_name = "Network Connection"
+ verbose_name_plural = "Network Connections"
+
class SliceTagInline(PlStackTabularInline):
model = SliceTag
extra = 0
@@ -271,7 +327,7 @@
class SliceAdmin(PlanetStackBaseAdmin):
fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
list_display = ('name', 'site','serviceClass', 'slice_url')
- inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline]
+ inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline, SliceNetworkInline]
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'site':
@@ -402,9 +458,9 @@
class SliverAdmin(PlanetStackBaseAdmin):
form = SliverForm
fieldsets = [
- ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
+ ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']})
]
- list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
+ list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
inlines = [TagInline]
def formfield_for_foreignkey(self, db_field, request, **kwargs):
@@ -549,10 +605,12 @@
return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
class ServiceResourceInline(admin.TabularInline):
+ exclude = ['enacted']
model = ServiceResource
extra = 0
class ServiceClassAdmin(admin.ModelAdmin):
+ exclude = ['enacted']
list_display = ('name', 'commitment', 'membershipFee')
inlines = [ServiceResourceInline]
@@ -677,6 +735,53 @@
else:
return []
+class NetworkParameterTypeAdmin(admin.ModelAdmin):
+ exclude = ['enacted']
+ list_display = ("name", )
+
+class RouterAdmin(admin.ModelAdmin):
+ exclude = ['enacted']
+ list_display = ("name", )
+
+class RouterInline(admin.TabularInline):
+ # exclude = ['enacted']
+ model = Router.networks.through
+ extra = 0
+ verbose_name_plural = "Routers"
+ verbose_name = "Router"
+
+class NetworkParameterInline(generic.GenericTabularInline):
+ exclude = ['enacted']
+ model = NetworkParameter
+ extra = 1
+ verbose_name_plural = "Parameters"
+ verbose_name = "Parameter"
+
+class NetworkSliversInline(admin.TabularInline):
+ exclude = ['enacted']
+ readonly_fields = ("ip", )
+ model = NetworkSliver
+ extra = 0
+ verbose_name_plural = "Slivers"
+ verbose_name = "Sliver"
+
+class NetworkSlicesInline(admin.TabularInline):
+ exclude = ['enacted']
+ model = NetworkSlice
+ extra = 0
+ verbose_name_plural = "Slices"
+ verbose_name = "Slice"
+
+class NetworkAdmin(admin.ModelAdmin):
+ exclude = ['enacted']
+ list_display = ("name", "subnet", "ports", "labels")
+ readonly_fields = ("subnet", )
+ inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
+
+class NetworkTemplateAdmin(admin.ModelAdmin):
+ exclude = ['enacted']
+ list_display = ("name", "guaranteedBandwidth", "visibility")
+
# 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'],
@@ -706,6 +811,10 @@
admin.site.register(Project, ProjectAdmin)
admin.site.register(ServiceClass, ServiceClassAdmin)
admin.site.register(Reservation, ReservationAdmin)
+admin.site.register(Network, NetworkAdmin)
+admin.site.register(Router, RouterAdmin)
+admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
+admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
if showAll:
admin.site.register(Tag, TagAdmin)
diff --git a/planetstack/core/api_root.py b/planetstack/core/api_root.py
index 61e76da..4ac267a 100644
--- a/planetstack/core/api_root.py
+++ b/planetstack/core/api_root.py
@@ -5,14 +5,17 @@
@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),
+ 'deployments': reverse('deployment-list', request=request, format=format),
'images': reverse('image-list', request=request, format=format),
+ 'nodes': reverse('node-list', request=request, format=format),
+ 'projects': reverse('project-list', request=request, format=format),
+ 'reservations': reverse('reservation-list', request=request, format=format),
+ 'roles': reverse('role-list', request=request, format=format),
+ 'serviceclasses': reverse('serviceclass-list', request=request, format=format),
+ 'serviceresources': reverse('serviceresource-list', request=request, format=format),
+ 'sites': reverse('site-list', request=request, format=format),
+ 'slices': reverse('slice-list', request=request, format=format),
+ 'slivers': reverse('sliver-list', request=request, format=format),
+ 'tags': reverse('tag-list', request=request, format=format),
+ 'users': reverse('user-list', request=request, format=format),
})
diff --git a/planetstack/core/models/__init__.py b/planetstack/core/models/__init__.py
index 2280822..9b19821 100644
--- a/planetstack/core/models/__init__.py
+++ b/planetstack/core/models/__init__.py
@@ -16,3 +16,4 @@
from .sliver import Sliver
from .reservation import ReservedResource
from .reservation import Reservation
+from .network import Network, NetworkParameterType, NetworkParameter, NetworkSliver, NetworkTemplate, Router, NetworkSlice
diff --git a/planetstack/core/models/network.py b/planetstack/core/models/network.py
new file mode 100644
index 0000000..55711a4
--- /dev/null
+++ b/planetstack/core/models/network.py
@@ -0,0 +1,122 @@
+import os
+import socket
+from django.db import models
+from core.models import PlCoreBase, Site, Slice, Sliver
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+
+# If true, then IP addresses will be allocated by the model. If false, then
+# we will assume the observer handles it.
+NO_OBSERVER=False
+
+class NetworkTemplate(PlCoreBase):
+ VISIBILITY_CHOICES = (('public', 'public'), ('private', 'private'))
+ TRANSLATION_CHOICES = (('none', 'none'), ('NAT', 'NAT'))
+
+ name = models.CharField(max_length=32)
+ description = models.CharField(max_length=1024, blank=True, null=True)
+ guaranteedBandwidth = models.IntegerField(default=0)
+ visibility = models.CharField(max_length=30, choices=VISIBILITY_CHOICES, default="private")
+ translation = models.CharField(max_length=30, choices=TRANSLATION_CHOICES, default="none")
+ sharedNetworkName = models.CharField(max_length=30, blank=True, null=True)
+ sharedNetworkId = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network")
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+class Network(PlCoreBase):
+ name = models.CharField(max_length=32)
+ template = models.ForeignKey(NetworkTemplate)
+ subnet = models.CharField(max_length=32, blank=True)
+ ports = models.CharField(max_length=1024, blank=True, null=True)
+ labels = models.CharField(max_length=1024, blank=True, null=True)
+ owner = models.ForeignKey(Slice, related_name="ownedNetworks")
+
+ guaranteedBandwidth = models.IntegerField(default=0)
+ permitAllSlices = models.BooleanField(default=False)
+ permittedSlices = models.ManyToManyField(Slice, blank=True, related_name="availableNetworks")
+ slices = models.ManyToManyField(Slice, blank=True, related_name="networks", through="NetworkSlice")
+ slivers = models.ManyToManyField(Sliver, blank=True, related_name="networks", through="NetworkSliver")
+
+ # for observer/manager
+ network_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network")
+ router_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum router id")
+ subnet_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum subnet id")
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+ def save(self, *args, **kwds):
+ if (not self.subnet) and (NO_OBSERVER):
+ from util.network_subnet_allocator import find_unused_subnet
+ self.subnet = find_unused_subnet(existing_subnets=[x.subnet for x in Network.objects.all()])
+ super(Network, self).save(*args, **kwds)
+
+class NetworkSlice(PlCoreBase):
+ # This object exists solely so we can implement the permission check when
+ # adding slices to networks. It adds no additional fields to the relation.
+
+ network = models.ForeignKey(Network)
+ slice = models.ForeignKey(Slice)
+
+ def save(self, *args, **kwds):
+ slice = self.slice
+ if (slice not in self.network.permittedSlices.all()) and (slice != self.network.owner) and (not self.network.permitAllSlices):
+ # to add a sliver to the network, then one of the following must be true:
+ # 1) sliver's slice is in network's permittedSlices list,
+ # 2) sliver's slice is network's owner, or
+ # 3) network's permitAllSlices is true
+ raise ValueError("Slice %s is not allowed to connect to network %s" % (str(slice), str(self.network)))
+
+ super(NetworkSlice, self).save(*args, **kwds)
+
+ def __unicode__(self): return u'%s-%s' % (self.network.name, self.slice.name)
+
+class NetworkSliver(PlCoreBase):
+ network = models.ForeignKey(Network)
+ sliver = models.ForeignKey(Sliver)
+ ip = models.GenericIPAddressField(help_text="Sliver ip address", blank=True, null=True)
+ port_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum port id")
+
+ def save(self, *args, **kwds):
+ slice = self.sliver.slice
+ if (slice not in self.network.permittedSlices.all()) and (slice != self.network.owner) and (not self.network.permitAllSlices):
+ # to add a sliver to the network, then one of the following must be true:
+ # 1) sliver's slice is in network's permittedSlices list,
+ # 2) sliver's slice is network's owner, or
+ # 3) network's permitAllSlices is true
+ raise ValueError("Slice %s is not allowed to connect to network %s" % (str(slice), str(self.network)))
+
+ if (not self.ip) and (NO_OBSERVER):
+ from util.network_subnet_allocator import find_unused_address
+ self.ip = find_unused_address(self.network.subnet,
+ [x.ip for x in self.network.networksliver_set.all()])
+ super(NetworkSliver, self).save(*args, **kwds)
+
+ def __unicode__(self): return u'%s-%s' % (self.network.name, self.sliver.instance_name)
+
+class Router(PlCoreBase):
+ name = models.CharField(max_length=32)
+ owner = models.ForeignKey(Slice, related_name="routers")
+ permittedNetworks = models.ManyToManyField(Network, blank=True, related_name="availableRouters")
+ networks = models.ManyToManyField(Network, blank=True, related_name="routers")
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+class NetworkParameterType(PlCoreBase):
+ name = models.SlugField(help_text="The name of this parameter", max_length=128)
+ description = models.CharField(max_length=1024)
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+class NetworkParameter(PlCoreBase):
+ parameter = models.ForeignKey(NetworkParameterType, related_name="parameters", help_text="The type of the parameter")
+ value = models.CharField(help_text="The value of this parameter", max_length=1024)
+
+ # The required fields to do a ObjectType lookup, and object_id assignment
+ content_type = models.ForeignKey(ContentType)
+ object_id = models.PositiveIntegerField()
+ content_object = generic.GenericForeignKey('content_type', 'object_id')
+
+ def __unicode__(self):
+ return self.parameter.name
+
+
diff --git a/planetstack/core/models/plcorebase.py b/planetstack/core/models/plcorebase.py
index 709fdc6..30d4df3 100644
--- a/planetstack/core/models/plcorebase.py
+++ b/planetstack/core/models/plcorebase.py
@@ -1,6 +1,8 @@
import os
from django.db import models
from django.forms.models import model_to_dict
+from openstack.event_manager import EventSender
+
class PlCoreBase(models.Model):
@@ -36,6 +38,10 @@
def save(self, *args, **kwargs):
super(PlCoreBase, self).save(*args, **kwargs)
+
+ # Tell the observer that the source database has been updated
+ EventSender().fire()
+
self.__initial = self._dict
@property
diff --git a/planetstack/core/models/role.py b/planetstack/core/models/role.py
index f6c2f2c..fd29848 100644
--- a/planetstack/core/models/role.py
+++ b/planetstack/core/models/role.py
@@ -5,8 +5,8 @@
class Role(PlCoreBase):
- #ROLE_CHOICES = (('admin', 'Admin'), ('pi', 'Principle Investigator'), ('user','User'))
- role = models.CharField(null=True, blank=True,max_length=256, unique=True)
+ ROLE_CHOICES = (('admin', 'Admin'), ('pi', 'Principle Investigator'), ('tech', 'Technician'), ('user','User'))
+ role = models.CharField(null=True, blank=True,max_length=256, unique=True, choices=ROLE_CHOICES)
role_type = models.CharField(max_length=80, unique=True)
def __unicode__(self): return u'%s' % (self.role_type)
diff --git a/planetstack/core/serializers.py b/planetstack/core/serializers.py
index 00d7160..94f5c3c 100644
--- a/planetstack/core/serializers.py
+++ b/planetstack/core/serializers.py
@@ -9,7 +9,6 @@
class Meta:
model = Role
fields = ('id',
- 'role_id',
'role',
'role_type')
@@ -19,11 +18,10 @@
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')
+ site_privileges = serializers.HyperlinkedRelatedField(view_name='siteprivilege-detail')
class Meta:
model = User
fields = ('id',
- 'user_id',
'kuser_id',
'firstname',
'lastname',
@@ -66,7 +64,7 @@
user = serializers.HyperlinkedRelatedField(view_name='user-detail')
role = serializers.HyperlinkedRelatedField(view_name='role-detail')
class Meta:
- model = SitePrivilege
+ model = SliceMembership
fields = ('id',
'user',
'slice',
@@ -115,7 +113,7 @@
# HyperlinkedModelSerializer doesn't include the id by default
id = serializers.Field()
- sites = serializers.HyperlinkedRelatedField(view_name='deploymentnetwork-detail')
+ sites = serializers.HyperlinkedRelatedField(view_name='site-detail')
class Meta:
model = Deployment
fields = ('id',
@@ -127,9 +125,8 @@
# 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')
+ deployment = serializers.HyperlinkedRelatedField(view_name='deployment-detail')
node = serializers.HyperlinkedRelatedField(view_name='node-detail')
@@ -143,9 +140,8 @@
'instance_name',
'ip',
'image',
- 'key',
'slice',
- 'deploymentNetwork',
+ 'deployment',
'node')
class NodeSerializer(serializers.HyperlinkedModelSerializer):
diff --git a/planetstack/core/views/deployment_networks.py b/planetstack/core/views/deployment_networks.py
deleted file mode 100644
index ef569ac..0000000
--- a/planetstack/core/views/deployment_networks.py
+++ /dev/null
@@ -1,59 +0,0 @@
-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 DeploymentSerializer
-from util.request import parse_request
-
-
-class DeploymentListCreate(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 = DeploymentSerializer(deployment)
- return Response(serializer.data, status=status.HTTP_201_CREATED)
- else:
- deployment_networks = get_deployment_networks(data['auth'])
- serializer = DeploymentSerializer(deployment_networks, many=True)
- return Response(serializer.data)
-
-
-class DeploymentRetrieveUpdateDestroy(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 = DeploymentSerializer(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/deployments.py b/planetstack/core/views/deployments.py
new file mode 100644
index 0000000..285a53a
--- /dev/null
+++ b/planetstack/core/views/deployments.py
@@ -0,0 +1,12 @@
+from core.serializers import DeploymentSerializer
+from rest_framework import generics
+from core.models import Deployment
+
+class DeploymentList(generics.ListCreateAPIView):
+ queryset = Deployment.objects.all()
+ serializer_class = DeploymentSerializer
+
+class DeploymentDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Deployment.objects.all()
+ serializer_class = DeploymentSerializer
+
diff --git a/planetstack/core/views/images.py b/planetstack/core/views/images.py
index 7e0ab59..5ea5d76 100644
--- a/planetstack/core/views/images.py
+++ b/planetstack/core/views/images.py
@@ -1,55 +1,12 @@
-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
+from rest_framework import generics
+from core.models import Image
+class ImageList(generics.ListCreateAPIView):
+ queryset = Image.objects.all()
+ serializer_class = ImageSerializer
-class ImageListCreate(APIView):
- """
- List all images or create a new image.
- """
+class ImageDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Image.objects.all()
+ serializer_class = ImageSerializer
- 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/nodes.py b/planetstack/core/views/nodes.py
index 0f1977e..8706114 100644
--- a/planetstack/core/views/nodes.py
+++ b/planetstack/core/views/nodes.py
@@ -1,55 +1,13 @@
-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
+from rest_framework import generics
+from core.models import Node
+
+class NodeList(generics.ListCreateAPIView):
+ queryset = Node.objects.all()
+ serializer_class = NodeSerializer
+
+class NodeDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Node.objects.all()
+ serializer_class = NodeSerializer
-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/projects.py b/planetstack/core/views/projects.py
new file mode 100644
index 0000000..c5311d5
--- /dev/null
+++ b/planetstack/core/views/projects.py
@@ -0,0 +1,13 @@
+from core.serializers import ProjectSerializer
+from rest_framework import generics
+from core.models import Project
+
+class ProjectList(generics.ListCreateAPIView):
+ queryset = Project.objects.all()
+ serializer_class = ProjectSerializer
+
+class ProjectDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Project.objects.all()
+ serializer_class = ProjectSerializer
+
+
diff --git a/planetstack/core/views/reservations.py b/planetstack/core/views/reservations.py
new file mode 100644
index 0000000..03f79eb
--- /dev/null
+++ b/planetstack/core/views/reservations.py
@@ -0,0 +1,13 @@
+from core.serializers import ReservationSerializer
+from rest_framework import generics
+from core.models import Reservation
+
+class ReservationList(generics.ListCreateAPIView):
+ queryset = Reservation.objects.all()
+ serializer_class = ReservationSerializer
+
+class ReservationDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Reservation.objects.all()
+ serializer_class = ReservationSerializer
+
+
diff --git a/planetstack/core/views/roles.py b/planetstack/core/views/roles.py
index 37bb149..13c9917 100644
--- a/planetstack/core/views/roles.py
+++ b/planetstack/core/views/roles.py
@@ -1,58 +1,13 @@
-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
+from rest_framework import generics
+from core.models import Role
+
+class RoleList(generics.ListCreateAPIView):
+ queryset = Role.objects.all()
+ serializer_class = RoleSerializer
+
+class RoleDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Role.objects.all()
+ serializer_class = RoleSerializer
-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/serviceclasses.py b/planetstack/core/views/serviceclasses.py
new file mode 100644
index 0000000..b8b1b70
--- /dev/null
+++ b/planetstack/core/views/serviceclasses.py
@@ -0,0 +1,13 @@
+from core.serializers import ServiceClassSerializer
+from rest_framework import generics
+from core.models import ServiceClass
+
+class ServiceClassList(generics.ListCreateAPIView):
+ queryset = ServiceClass.objects.all()
+ serializer_class = ServiceClassSerializer
+
+class ServiceClassDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = ServiceClass.objects.all()
+ serializer_class = ServiceClassSerializer
+
+
diff --git a/planetstack/core/views/serviceresources.py b/planetstack/core/views/serviceresources.py
new file mode 100644
index 0000000..e394c18
--- /dev/null
+++ b/planetstack/core/views/serviceresources.py
@@ -0,0 +1,13 @@
+from core.serializers import ServiceResourceSerializer
+from rest_framework import generics
+from core.models import ServiceResource
+
+class ServiceResourceList(generics.ListCreateAPIView):
+ queryset = ServiceResource.objects.all()
+ serializer_class = ServiceResourceSerializer
+
+class ServiceResourceDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = ServiceResource.objects.all()
+ serializer_class = ServiceResourceSerializer
+
+
diff --git a/planetstack/core/views/site_privileges.py b/planetstack/core/views/site_privileges.py
index 37fc371..90053e5 100644
--- a/planetstack/core/views/site_privileges.py
+++ b/planetstack/core/views/site_privileges.py
@@ -1,66 +1,13 @@
-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
+from rest_framework import generics
+from core.models import SitePrivilege
+
+class SitePrivilegeList(generics.ListCreateAPIView):
+ queryset = SitePrivilege.objects.all()
+ serializer_class = SitePrivilegeSerializer
+
+class SitePrivilegeDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = SitePrivilege.objects.all()
+ serializer_class = SitePrivilegeSerializer
-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
index 6449b67..4ec9cb2 100644
--- a/planetstack/core/views/sites.py
+++ b/planetstack/core/views/sites.py
@@ -1,66 +1,11 @@
-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
+from rest_framework import generics
+from core.models import Site
+class SiteList(generics.ListCreateAPIView):
+ queryset = Site.objects.all()
+ serializer_class = SiteSerializer
-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)
-
-
-
+class SiteDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Site.objects.all()
+ serializer_class = SiteSerializer
diff --git a/planetstack/core/views/slice_memberships.py b/planetstack/core/views/slice_memberships.py
index 4bb581c..13f0707 100644
--- a/planetstack/core/views/slice_memberships.py
+++ b/planetstack/core/views/slice_memberships.py
@@ -1,66 +1,13 @@
-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
+from rest_framework import generics
+from core.models import SliceMembership
+
+class SliceMembershipList(generics.ListCreateAPIView):
+ queryset = SliceMembership.objects.all()
+ serializer_class = SliceMembershipSerializer
+
+class SliceMembershipDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = SliceMembership.objects.all()
+ serializer_class = SliceMembershipSerializer
-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
index 5954d0c..e3ab139 100644
--- a/planetstack/core/views/slices.py
+++ b/planetstack/core/views/slices.py
@@ -1,66 +1,13 @@
-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
+from rest_framework import generics
+from core.models import Slice
+
+class SliceList(generics.ListCreateAPIView):
+ queryset = Slice.objects.all()
+ serializer_class = SliceSerializer
+
+class SliceDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Slice.objects.all()
+ serializer_class = SliceSerializer
-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
index 3741cce..bb310da 100644
--- a/planetstack/core/views/slivers.py
+++ b/planetstack/core/views/slivers.py
@@ -1,66 +1,13 @@
-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
+from rest_framework import generics
+from core.models import Sliver
+
+class SliverList(generics.ListCreateAPIView):
+ queryset = Sliver.objects.all()
+ serializer_class = SliverSerializer
+
+class SliverDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Sliver.objects.all()
+ serializer_class = SliverSerializer
-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/tags.py b/planetstack/core/views/tags.py
new file mode 100644
index 0000000..ba8a035
--- /dev/null
+++ b/planetstack/core/views/tags.py
@@ -0,0 +1,13 @@
+from core.serializers import TagSerializer
+from rest_framework import generics
+from core.models import Tag
+
+class TagList(generics.ListCreateAPIView):
+ queryset = Tag.objects.all()
+ serializer_class = TagSerializer
+
+class TagDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = Tag.objects.all()
+ serializer_class = TagSerializer
+
+
diff --git a/planetstack/core/views/users.py b/planetstack/core/views/users.py
index 8b27928..06ac0f3 100644
--- a/planetstack/core/views/users.py
+++ b/planetstack/core/views/users.py
@@ -1,66 +1,11 @@
-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
+from rest_framework import generics
+from core.models import User
+class UserList(generics.ListCreateAPIView):
+ queryset = User.objects.all()
+ serializer_class = UserSerializer
-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)
-
-
-
+class UserDetail(generics.RetrieveUpdateDestroyAPIView):
+ queryset = User.objects.all()
+ serializer_class = UserSerializer
diff --git a/planetstack/openstack/backend.py b/planetstack/openstack/backend.py
index 43afba7..2f4aa71 100644
--- a/planetstack/openstack/backend.py
+++ b/planetstack/openstack/backend.py
@@ -1,6 +1,6 @@
import threading
from openstack.observer import OpenStackObserver
-from openstack.event_listener import EventListener
+from openstack.event_manager import EventListener
class Backend:
@@ -11,7 +11,7 @@
observer_thread.start()
# start event listene
- event_listener = EventListener()
- event_listener_thread = threading.Thread(target=event_listener.run)
- event_listener_thread.start()
+ event_manager = EventListener(wake_up=observer.wake_up)
+ event_manager_thread = threading.Thread(target=event_manager.run)
+ event_manager_thread.start()
diff --git a/planetstack/openstack/driver.py b/planetstack/openstack/driver.py
index b9faa97..5bb1eb2 100644
--- a/planetstack/openstack/driver.py
+++ b/planetstack/openstack/driver.py
@@ -18,12 +18,12 @@
else:
self.shell = OpenStackClient()
- def create_role(self, name):
+ def create_role(self, name):
roles = self.shell.keystone.roles.findall(name=name)
if not roles:
role = self.shell.keystone.roles.create(name)
else:
- role = roles[0]
+ role = roles[0]
return role
def delete_role(self, filter):
@@ -56,9 +56,9 @@
for tenant in tenants:
# nova does not automatically delete the tenant's instances
# so we manually delete instances before deleteing the tenant
- instances = self.shell.nova_db.instance_get_all_by_filters(ctx,
+ instances = self.shell.nova_db.instance_get_all_by_filters(ctx,
{'project_id': tenant.id}, 'id', 'asc')
- client = OpenStackClient(tenant=tenant)
+ client = OpenStackClient(tenant=tenant.name)
driver = OpenStackDriver(client=client)
for instance in instances:
driver.destroy_instance(instance.id)
@@ -160,12 +160,12 @@
if router and subnet:
self.shell.quantum.remove_interface_router(router_id, {'subnet_id': subnet_id})
- def create_network(self, name):
+ def create_network(self, name, shared=False):
nets = self.shell.quantum.list_networks(name=name)['networks']
if nets:
net = nets[0]
else:
- net = self.shell.quantum.create_network({'network': {'name': name}})['network']
+ net = self.shell.quantum.create_network({'network': {'name': name, 'shared': shared}})['network']
return net
def delete_network(self, id):
@@ -210,7 +210,7 @@
for snet in subnets:
if snet['cidr'] == cidr_ip and snet['network_id'] == network_id:
subnet = snet
-
+
if not subnet:
allocation_pools = [{'start': start, 'end': end}]
subnet = {'subnet': {'name': name,
@@ -218,7 +218,7 @@
'ip_version': ip_version,
'cidr': cidr_ip,
'dns_nameservers': ['8.8.8.8', '8.8.4.4'],
- 'allocation_pools': allocation_pools}}
+ 'allocation_pools': allocation_pools}}
subnet = self.shell.quantum.create_subnet(subnet)['subnet']
self.add_external_route(subnet)
# TODO: Add route to external network
@@ -239,7 +239,15 @@
self.delete_external_route(subnet)
return 1
- def add_external_route(self, subnet):
+ def get_external_routes(self):
+ status, output = commands.getstatusoutput('route')
+ routes = output.split('\n')[3:]
+ return routes
+
+ def add_external_route(self, subnet, routes=[]):
+ if not routes:
+ routes = self.get_external_routes()
+
ports = self.shell.quantum.list_ports()['ports']
gw_ip = subnet['gateway_ip']
@@ -256,14 +264,23 @@
gw_port = port
router_id = gw_port['device_id']
router = self.shell.quantum.show_router(router_id)['router']
- ext_net = router['external_gateway_info']['network_id']
- for port in ports:
- if port['device_id'] == router_id and port['network_id'] == ext_net:
- ip_address = port['fixed_ips'][0]['ip_address']
+ if router and router.get('external_gateway_info'):
+ ext_net = router['external_gateway_info']['network_id']
+ for port in ports:
+ if port['device_id'] == router_id and port['network_id'] == ext_net:
+ ip_address = port['fixed_ips'][0]['ip_address']
if ip_address:
- cmd = "route add -net %s dev br-ex gw %s" % (subnet['cidr'], ip_address)
- commands.getstatusoutput(cmd)
+ # check if external route already exists
+ route_exists = False
+ if routes:
+ for route in routes:
+ if subnet['cidr'] in route and ip_address in route:
+ route_exists = True
+ if not route_exists:
+ cmd = "route add -net %s dev br-ex gw %s" % (subnet['cidr'], ip_address)
+ s, o = commands.getstatusoutput(cmd)
+ #print cmd, "\n", s, o
return 1
@@ -311,9 +328,37 @@
keys = self.shell.nova.keypairs.findall(id=id)
for key in keys:
self.shell.nova.keypairs.delete(key)
- return 1
+ return 1
- def spawn_instance(self, name, key_name=None, hostname=None, image_id=None, security_group=None, pubkeys=[]):
+ def get_private_networks(self, tenant=None):
+ if not tenant:
+ tenant = self.shell.nova.tenant
+ tenant = self.shell.keystone.tenants.find(name=tenant)
+ search_opts = {"tenant_id": tenant.id, "shared": False}
+ private_networks = self.shell.quantum.list_networks(**search_opts)
+ return private_networks
+
+ def get_shared_networks(self):
+ search_opts = {"shared": True}
+ shared_networks = self.shell.quantum.list_networks(**search_opts)
+ return shared_networks
+
+ def get_network_subnet(self, network_id):
+ subnet_id = None
+ subnet = None
+ if network_id:
+ os_networks = self.shell.quantum.list_networks(id=network_id)["networks"]
+ if os_networks:
+ os_network = os_networks[0]
+ if os_network['subnets']:
+ subnet_id = os_network['subnets'][0]
+ os_subnets = self.shell.quantum.list_subnets(id=subnet_id)['subnets']
+ if os_subnets:
+ subnet = os_subnets[0]['cidr']
+
+ return (subnet_id, subnet)
+
+ def spawn_instance(self, name, key_name=None, hostname=None, image_id=None, security_group=None, pubkeys=[], nics=None):
flavor_name = self.config.nova_default_flavor
flavor = self.shell.nova.flavors.find(name=flavor_name)
#if not image:
@@ -337,7 +382,8 @@
security_group = security_group,
files=files,
scheduler_hints=hints,
- availability_zone=availability_zone)
+ availability_zone=availability_zone,
+ nics=nics)
return server
def destroy_instance(self, id):
diff --git a/planetstack/openstack/event_listener.py b/planetstack/openstack/event_manager.py
similarity index 68%
rename from planetstack/openstack/event_listener.py
rename to planetstack/openstack/event_manager.py
index 5e0afff..ab50f66 100644
--- a/planetstack/openstack/event_listener.py
+++ b/planetstack/openstack/event_manager.py
@@ -1,11 +1,13 @@
import threading
import requests, json
+
from core.models import *
-from openstack.manager import OpenStackManager
+#from openstack.manager import OpenStackManager
+from planetstack.config import Config
import os
import base64
-import fofum
+from fofum import Fofum
# decorator that marks dispatachable event methods
def event(func):
@@ -13,9 +15,9 @@
return func
class EventHandler:
-
+ # This code is currently not in use.
def __init__(self):
- self.manager = OpenStackManager()
+ pass #self.manager = OpenStackManager()
@staticmethod
def get_events():
@@ -82,22 +84,52 @@
self.manager.destroy_instance(instance_id)
+class EventSender:
+ def __init__(self,user=None,clientid=None):
+ try:
+ clid = Config().feefie_client_id
+ user = Config().feefie_client_user
+ except:
+ clid = 'planetstack_core_team'
+ user = 'pl'
+
+ self.fofum = Fofum(user=user)
+ self.fofum.make(clid)
+
+ def fire(self):
+ self.fofum.fire()
class EventListener:
- def __init__(self):
+ def __init__(self,wake_up=None):
self.handler = EventHandler()
+ self.wake_up = wake_up
def handle_event(self, payload):
payload_dict = json.loads(payload)
- event = payload_dict['event']
- ctx = payload_dict['ctx']
- self.handler.dispatch(event,**ctx)
+
+ # The code below will come back when we optimize the observer syncs
+ # into 'small' and 'big' syncs.
+
+ #event = payload_dict['event']
+ #ctx = payload_dict['ctx']
+ #self.handler.dispatch(event,**ctx)
+
+ if (self.wake_up):
+ self.wake_up()
+
def run(self):
# This is our unique client id, to be used when firing and receiving events
- clid = base64.urlsafe_b64encode(os.urandom(12))
+ # It needs to be generated once and placed in the config file
- f = Fofum()
+ try:
+ clid = Config().feefie_client_id
+ user = Config().feefie_client_user
+ except:
+ clid = 'planetstack_core_team'
+ user = 'pl'
+
+ f = Fofum(user=user)
listener_thread = threading.Thread(target=f.listen_for_event,args=(clid,self.handle_event))
listener_thread.start()
diff --git a/planetstack/openstack/manager.py b/planetstack/openstack/manager.py
index 3ae7dea..2fb4ff8 100644
--- a/planetstack/openstack/manager.py
+++ b/planetstack/openstack/manager.py
@@ -301,17 +301,32 @@
#del_route = 'route del -net %s' % self.cidr
#commands.getstatusoutput(del_route)
+ def get_requested_networks(self, slice):
+ network_ids = [x.network_id for x in slice.networks.all()]
+
+ if slice.network_id is not None:
+ network_ids.append(slice.network_id)
+
+ networks = []
+ for network_id in network_ids:
+ networks.append({"net-id": network_id})
+
+ return networks
+
@require_enabled
def save_sliver(self, sliver):
if not sliver.instance_id:
+ nics = self.get_requested_networks(sliver.slice)
+ file("/tmp/scott-manager","a").write("slice: %s\nreq: %s\n" % (str(sliver.slice.name), str(nics)))
slice_memberships = SliceMembership.objects.filter(slice=sliver.slice)
pubkeys = [sm.user.public_key for sm in slice_memberships if sm.user.public_key]
- pubkeys.append(sliver.creator.public_key)
+ pubkeys.append(sliver.creator.public_key)
instance = self.driver.spawn_instance(name=sliver.name,
key_name = sliver.creator.keyname,
image_id = sliver.image.image_id,
hostname = sliver.node.name,
- pubkeys = pubkeys )
+ pubkeys = pubkeys,
+ nics = nics )
sliver.instance_id = instance.id
sliver.instance_name = getattr(instance, 'OS-EXT-SRV-ATTR:instance_name')
@@ -368,7 +383,7 @@
from core.models.image import Image
# collect local images
images = Image.objects.all()
- images_dict = {}
+ images_dict = {}
for image in images:
images_dict[image.name] = image
@@ -391,4 +406,149 @@
old_image_names = set(images_dict.keys()).difference(glance_images_dict.keys())
Image.objects.filter(name__in=old_image_names).delete()
+ @require_enabled
+ def save_network(self, network):
+ if not network.network_id:
+ if network.template.sharedNetworkName:
+ network.network_id = network.template.sharedNetworkId
+ (network.subnet_id, network.subnet) = self.driver.get_network_subnet(network.network_id)
+ else:
+ network_name = network.name
+
+ # create network
+ os_network = self.driver.create_network(network_name, shared=True)
+ network.network_id = os_network['id']
+
+ # create router
+ router = self.driver.create_router(network_name)
+ network.router_id = router['id']
+
+ # create subnet
+ next_subnet = self.get_next_subnet()
+ cidr = str(next_subnet.cidr)
+ ip_version = next_subnet.version
+ start = str(next_subnet[2])
+ end = str(next_subnet[-2])
+ subnet = self.driver.create_subnet(name=network_name,
+ network_id = network.network_id,
+ cidr_ip = cidr,
+ ip_version = ip_version,
+ start = start,
+ end = end)
+ network.subnet = cidr
+ network.subnet_id = subnet['id']
+ # add subnet as interface to slice's router
+ self.driver.add_router_interface(router['id'], subnet['id'])
+ # add external route
+ self.driver.add_external_route(subnet)
+
+ network.save()
+ network.enacted = datetime.now()
+ network.save(update_fields=['enacted'])
+
+ def delete_network(self, network):
+ if (network.router_id) and (network.subnet_id):
+ self.driver.delete_router_interface(network.router_id, network.subnet_id)
+ if network.subnet_id:
+ self.driver.delete_subnet(network.subnet_id)
+ if network.router_id:
+ self.driver.delete_router(network.router_id)
+ if network.network_id:
+ self.driver.delete_network(network.network_id)
+
+ def save_network_template(self, template):
+ if (template.sharedNetworkName) and (not template.sharedNetworkId):
+ os_networks = self.driver.shell.quantum.list_networks(name=template.sharedNetworkName)['networks']
+ if os_networks:
+ template.sharedNetworkId = os_networks[0]["id"]
+
+ template.save()
+ template.enacted = datetime.now()
+ template.save(update_fields=['enacted'])
+
+ def find_or_make_template_for_network(self, name):
+ """ Given a network name, try to guess the right template for it """
+
+ # templates for networks we may encounter
+ if name=='nat-net':
+ template_dict = None # {"name": "private-nat", "visibility": "private", "translation": "nat"}
+ elif name=='sharednet1':
+ template_dict = {"name": "dedicated-public", "visibility": "public", "translation": "none"}
+ else:
+ template_dict = {"name": "private", "visibility": "private", "translation": "none"}
+
+ # if we have an existing template return it
+ templates = NetworkTemplate.objects.filter(name=template_dict["name"])
+ if templates:
+ return templates[0]
+
+ if template_dict == None:
+ return None
+
+ template = NetworkTemplate(**template_dict)
+ template.save()
+ return template
+
+ def refresh_network_templates(self):
+ for template in NetworkTemplate.objects.all():
+ if (template.sharedNetworkName) and (not template.sharedNetworkId):
+ # this will cause us to try to fill in the sharedNetworkId
+ self.save_network_template(template)
+
+ def refresh_networks(self):
+ # get a list of all networks in the model
+
+ networks = Network.objects.all()
+ networks_by_name = {}
+ networks_by_id = {}
+ for network in networks:
+ networks_by_name[network.name] = network
+ networks_by_id[network.network_id] = network
+
+ # Get a list of all shared networks in OS
+
+ os_networks = self.driver.shell.quantum.list_networks()['networks']
+ os_networks_by_name = {}
+ os_networks_by_id = {}
+ for os_network in os_networks:
+ os_networks_by_name[os_network['name']] = os_network
+ os_networks_by_id[os_network['id']] = os_network
+
+ for (uuid, os_network) in os_networks_by_id.items():
+ #print "checking OS network", os_network['name']
+ if (os_network['shared']) and (uuid not in networks_by_id):
+ # Only automatically create shared networks. This is for Andy's
+ # nat-net and sharednet1.
+
+ owner_slice = Slice.objects.get(tenant_id = os_network['tenant_id'])
+ template = self.find_or_make_template_for_network(os_network['name'])
+
+ if (template is None):
+ # This is our way of saying we don't want to auto-instantiate
+ # this network type.
+ continue
+
+ (subnet_id, subnet) = self.driver.get_network_subnet(os_network['id'])
+
+ if owner_slice:
+ #print "creating model object for OS network", os_network['name']
+ new_network = Network(name = os_network['name'],
+ template = template,
+ owner = owner_slice,
+ network_id = uuid,
+ subnet_id = subnet_id)
+ new_network.save()
+
+ for (network_id, network) in networks_by_id.items():
+ # If the network disappeared from OS, then reset its network_id to None
+ if (network.network_id is not None) and (network.network_id not in os_networks_by_id):
+ network.network_id = None
+
+ # If no OS object exists, then saving the network will create one
+ if (network.network_id is None):
+ #print "creating OS network for", network.name
+ self.save_network(network)
+ else:
+ pass #print "network", network.name, "has its OS object"
+
diff --git a/planetstack/openstack/observer.py b/planetstack/openstack/observer.py
index 6fcb3b4..73bb114 100644
--- a/planetstack/openstack/observer.py
+++ b/planetstack/openstack/observer.py
@@ -1,11 +1,15 @@
import time
import traceback
+import commands
+import threading
+
from datetime import datetime
from collections import defaultdict
from core.models import *
from django.db.models import F, Q
from openstack.manager import OpenStackManager
-from util.logger import Logger, logging
+from util.logger import Logger, logging, logger
+#from timeout import timeout
logger = Logger(logfile='observer.log', level=logging.INFO)
@@ -14,21 +18,98 @@
def __init__(self):
self.manager = OpenStackManager()
+ # The Condition object that gets signalled by Feefie events
+ self.event_cond = threading.Condition()
+
+ def wait_for_event(self, timeout):
+ self.event_cond.acquire()
+ self.event_cond.wait(timeout)
+ self.event_cond.release()
+
+ def wake_up(self):
+ logger.info('Wake up routine called. Event cond %r'%self.event_cond)
+ self.event_cond.acquire()
+ self.event_cond.notify()
+ self.event_cond.release()
def run(self):
if not self.manager.enabled or not self.manager.has_openstack:
return
while True:
try:
+ logger.info('Observer run loop')
#self.sync_roles()
- self.sync_tenants()
- self.sync_users()
- self.sync_user_tenant_roles()
- self.sync_slivers()
- self.sync_sliver_ips()
- time.sleep(7)
+
+ logger.info('Calling sync tenants')
+ try:
+ self.sync_tenants()
+ except:
+ logger.log_exc("Exception in sync_tenants")
+ traceback.print_exc()
+
+ logger.info('Calling sync users')
+ try:
+ self.sync_users()
+ except:
+ logger.log_exc("Exception in sync_users")
+ traceback.print_exc()
+
+ logger.info('Calling sync tenant roles')
+ try:
+ self.sync_user_tenant_roles()
+ except:
+ logger.log_exc("Exception in sync_users")
+ traceback.print_exc()
+
+ logger.info('Calling sync slivers')
+ try:
+ self.sync_slivers()
+ except:
+ logger.log_exc("Exception in sync slivers")
+ traceback.print_exc()
+
+ logger.info('Calling sync sliver ips')
+ try:
+ self.sync_sliver_ips()
+ except:
+ logger.log_exc("Exception in sync_sliver_ips")
+ traceback.print_exc()
+
+ logger.info('Calling sync networks')
+ try:
+ self.sync_networks()
+ except:
+ logger.log_exc("Exception in sync_networks")
+ traceback.print_exc()
+
+ logger.info('Calling sync network slivers')
+ try:
+ self.sync_network_slivers()
+ except:
+ logger.log_exc("Exception in sync_network_slivers")
+ traceback.print_exc()
+
+ logger.info('Calling sync external routes')
+ try:
+ self.sync_external_routes()
+ except:
+ logger.log_exc("Exception in sync_external_routes")
+ traceback.print_exc()
+
+ logger.info('Waiting for event')
+ tBeforeWait = time.time()
+ self.wait_for_event(timeout=300)
+
+ # Enforce 5 minutes between wakeups
+ tSleep = 300 - (time.time() - tBeforeWait)
+ if tSleep > 0:
+ logger.info('Sleeping for %d seconds' % tSleep)
+ time.sleep(tSleep)
+
+ logger.info('Observer woken up')
except:
- traceback.print_exc()
+ logger.log_exc("Exception in observer run loop")
+ traceback.print_exc()
def sync_roles(self):
"""
@@ -231,7 +312,7 @@
# update manager context
self.manager.init_caller(sliver.creator, sliver.slice.name)
self.manager.save_sliver(sliver)
- logger.info("saved sliver: %s %s" % (sliver))
+ logger.info("saved sliver: %s" % (sliver))
except:
logger.log_exc("save sliver failed: %s" % sliver)
@@ -243,7 +324,7 @@
sliver_dict[sliver.instance_id] = sliver
# delete sliver that don't have a sliver record
- ctx = self.manager.driver.shell.nova_db.ctx
+ ctx = self.manager.driver.shell.nova_db.ctx
instances = self.manager.driver.shell.nova_db.instance_get_all(ctx)
for instance in instances:
if instance.uuid not in sliver_dict:
@@ -263,7 +344,7 @@
for sliver in slivers:
# update connection
self.manager.init_admin(tenant=sliver.slice.name)
- servers = self.manager.client.nova.servers.findall(id=sliver.instance_id)
+ servers = self.manager.driver.shell.nova.servers.findall(id=sliver.instance_id)
if not servers:
continue
server = servers[0]
@@ -273,3 +354,106 @@
sliver.ip = ips[0]['addr']
sliver.save()
logger.info("saved sliver ip: %s %s" % (sliver, ips[0]))
+
+ def sync_external_routes(self):
+ routes = self.manager.driver.get_external_routes()
+ subnets = self.manager.driver.shell.quantum.list_subnets()['subnets']
+ for subnet in subnets:
+ try:
+ self.manager.driver.add_external_route(subnet, routes)
+ except:
+ logger.log_exc("failed to add external route for subnet %s" % subnet)
+
+ def sync_network_slivers(self):
+ networkSlivers = NetworkSliver.objects.all()
+ networkSlivers_by_id = {}
+ networkSlivers_by_port = {}
+ for networkSliver in networkSlivers:
+ networkSlivers_by_id[networkSliver.id] = networkSliver
+ networkSlivers_by_port[networkSliver.port_id] = networkSliver
+
+ networks = Network.objects.all()
+ networks_by_id = {}
+ for network in networks:
+ networks_by_id[network.network_id] = network
+
+ slivers = Sliver.objects.all()
+ slivers_by_instance_id = {}
+ for sliver in slivers:
+ slivers_by_instance_id[sliver.instance_id] = sliver
+
+ ports = self.manager.driver.shell.quantum.list_ports()["ports"]
+ for port in ports:
+ if port["id"] in networkSlivers_by_port:
+ # we already have it
+ print "already accounted for port", port["id"]
+ continue
+
+ if port["device_owner"] != "compute:nova":
+ # we only want the ports that connect to instances
+ continue
+
+ network = networks_by_id.get(port['network_id'], None)
+ if not network:
+ #print "no network for port", port["id"], "network", port["network_id"]
+ continue
+
+ sliver = slivers_by_instance_id.get(port['device_id'], None)
+ if not sliver:
+ print "no sliver for port", port["id"], "device_id", port['device_id']
+ continue
+
+ if network.template.sharedNetworkId is not None:
+ # If it's a shared network template, then more than one network
+ # object maps to the quantum network. We have to do a whole bunch
+ # of extra work to find the right one.
+ networks = network.template.network_set.all()
+ network = None
+ for candidate_network in networks:
+ if (candidate_network.owner == sliver.slice):
+ print "found network", candidate_network
+ network = candidate_network
+
+ if not network:
+ print "failed to find the correct network for a shared template for port", port["id"], "network", port["network_id"]
+ continue
+
+ if not port["fixed_ips"]:
+ print "port", port["id"], "has no fixed_ips"
+ continue
+
+# print "XXX", port
+
+ ns = NetworkSliver(network=network,
+ sliver=sliver,
+ ip=port["fixed_ips"][0]["ip_address"],
+ port_id=port["id"])
+ ns.save()
+
+ def sync_networks(self):
+ """
+ save all networks where enacted < updated or enacted == None. Remove networks that
+ no don't exist in openstack db if they have an enacted time (enacted != None).
+ """
+ # get all users that need to be synced (enacted < updated or enacted is None)
+ pending_networks = Network.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+ for network in pending_networks:
+ if network.owner and network.owner.creator:
+ try:
+ # update manager context
+ self.manager.init_caller(network.owner.creator, network.owner.name)
+ self.manager.save_network(network)
+ logger.info("saved network: %s" % (network))
+ except:
+ logger.log_exc("save network failed: %s" % network)
+
+ # get all networks where enacted != null. We can assume these users
+ # have previously been synced and need to be checed for deletion.
+ networks = Network.objects.filter(enacted__isnull=False)
+ network_dict = {}
+ for network in networks:
+ network_dict[network.network_id] = network
+
+ # TODO: delete Network objects if quantum network doesn't exist
+ # (need to write self.manager.driver.shell.quantum_db)
+
diff --git a/planetstack/openstack/openstack-db-cleanup.sh b/planetstack/openstack/openstack-db-cleanup.sh
new file mode 100755
index 0000000..9baca6e
--- /dev/null
+++ b/planetstack/openstack/openstack-db-cleanup.sh
@@ -0,0 +1,16 @@
+#! /bin/bash
+
+# to install
+# chmod 0755 /opt/planetstack/openstack/openstack-db-cleanup.sh
+# ln -s /opt/planetstack/openstack/openstack-db-cleanup.sh /etc/cron.daily/openstack-db-cleanup.cron
+
+mkdir -p /opt/planetstack/ovs-backups
+BACKUP_NAME=/opt/planetstack/ovs-backups/backup-`date "+%Y-%M-%d"`.sql
+mysqldump --create-options --routines --triggers --databases keystone ovs_quantum nova glance cinder > $BACKUP_NAME
+gzip $BACKUP_NAME
+
+mysql keystone -e "DELETE FROM token WHERE NOT DATE_SUB(CURDATE(),INTERVAL 2 DAY) <= expires;"
+mysqlcheck --optimize --databases keystone ovs_quantum nova glance cinder
+
+date >> /var/log/openstack-db-cleanup.log
+mysql keystone -e "select count(*) from token;" >> /var/log/openstack-db-cleanup.log
diff --git a/planetstack/planetstack/urls.py b/planetstack/planetstack/urls.py
index 30eed05..66f376a 100644
--- a/planetstack/planetstack/urls.py
+++ b/planetstack/planetstack/urls.py
@@ -2,17 +2,17 @@
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
-from core.views.roles import RoleListCreate, RoleRetrieveUpdateDestroy
-from core.views.sites import SiteListCreate, SiteRetrieveUpdateDestroy
-from core.views.site_privileges import SitePrivilegeListCreate, SitePrivilegeRetrieveUpdateDestroy
-from core.views.users import UserListCreate, UserRetrieveUpdateDestroy
-from core.views.slices import SliceListCreate, SliceRetrieveUpdateDestroy
-from core.views.slice_memberships import SliceMembershipListCreate, SliceMembershipRetrieveUpdateDestroy
-from core.views.slivers import SliverListCreate, SliverRetrieveUpdateDestroy
-from core.views.deployment_networks import DeploymentListCreate, DeploymentRetrieveUpdateDestroy
-from core.views.images import ImageListCreate, ImageRetrieveUpdateDestroy
-from core.views.nodes import NodeListCreate, NodeRetrieveUpdateDestroy
-from core.models import Site
+from core.views.roles import RoleList, RoleDetail
+from core.views.sites import SiteList, SiteDetail
+from core.views.site_privileges import SitePrivilegeList, SitePrivilegeDetail
+from core.views.users import UserList, UserDetail
+from core.views.slices import SliceList, SliceDetail
+from core.views.slice_memberships import SliceMembershipList, SliceMembershipDetail
+from core.views.slivers import SliverList, SliverDetail
+from core.views.deployments import DeploymentList, DeploymentDetail
+from core.views.images import ImageList, ImageDetail
+from core.views.nodes import NodeList, NodeDetail
+from core.models import *
from core.api_root import api_root
from rest_framework import generics
@@ -31,35 +31,36 @@
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/roles/$', RoleList.as_view(), name='role-list'),
+ url(r'^plstackapi/roles/(?P<pk>[a-zA-Z0-9]+)/$', RoleDetail.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/users/$', UserList.as_view(), name='user-list'),
+ url(r'^plstackapi/users/(?P<pk>[a-zA-Z0-9_\-]+)/$', UserDetail.as_view(), name='user-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/sites/$', SiteList.as_view(), name='site-list'),
+ url(r'^plstackapi/sites/(?P<pk>[a-zA-Z0-9_\-]+)/$', SiteDetail.as_view(), name='site-detail'),
- url(r'^plstackapi/site_privileges/$', SitePrivilegeListCreate.as_view(), name='siteprivilege-list'),
- url(r'^plstackapi/site_privileges/(?P<pk>[a-zA-Z0-9_]+)/$', SitePrivilegeRetrieveUpdateDestroy.as_view(), name='siteprivilege-detail'),
+ url(r'^plstackapi/site_privileges/$', SitePrivilegeList.as_view(), name='siteprivilege-list'),
+ url(r'^plstackapi/site_privileges/(?P<pk>[a-zA-Z0-9_]+)/$', SitePrivilegeDetail.as_view(), name='siteprivilege-detail'),
+
+ url(r'^plstackapi/slices/$', SliceList.as_view(), name='slice-list'),
- url(r'^plstackapi/slices/$', SliceListCreate.as_view(), name='slice-list'),
- url(r'^plstackapi/slices/(?P<pk>[a-zA-Z0-9_\-]+)/$', SliceRetrieveUpdateDestroy.as_view(), name='slice-detail'),
+ url(r'^plstackapi/slices/(?P<pk>[a-zA-Z0-9_\-]+)/$', SliceDetail.as_view(), name='slice-detail'),
- url(r'^plstackapi/slice_memberships/$', SliceMembershipListCreate.as_view(), name='slice_membership-list'),
- url(r'^plstackapi/slice_memberships/(?P<pk>[0-9]+)/$', SliceMembershipRetrieveUpdateDestroy.as_view(), name='slice_membership-detail'),
+ url(r'^plstackapi/slice_memberships/$', SliceMembershipList.as_view(), name='slice-membership-list'),
+ url(r'^plstackapi/slice_memberships/(?P<pk>[0-9]+)/$', SliceMembershipDetail.as_view(), name='slice-membership-detail'),
- url(r'^plstackapi/slivers/$', SliverListCreate.as_view(), name='sliver-list'),
- url(r'^plstackapi/slivers/(?P<pk>[a-zA-Z0-9_\-]+)/$', SliverRetrieveUpdateDestroy.as_view(), name='sliver-detail'),
+ url(r'^plstackapi/slivers/$', SliverList.as_view(), name='sliver-list'),
+ url(r'^plstackapi/slivers/(?P<pk>[a-zA-Z0-9_\-]+)/$', SliverDetail.as_view(), name='sliver-detail'),
- url(r'^plstackapi/nodes/$', NodeListCreate.as_view(), name='node-list'),
- url(r'^plstackapi/nodes/(?P<pk>[a-zA-Z0-9_\-]+)/$', NodeRetrieveUpdateDestroy.as_view(), name='node-detail'),
+ url(r'^plstackapi/nodes/$', NodeList.as_view(), name='node-list'),
+ url(r'^plstackapi/nodes/(?P<pk>[a-zA-Z0-9_\-]+)/$', NodeDetail.as_view(), name='node-detail'),
- url(r'^plstackapi/deploymentnetworks/$', DeploymentListCreate.as_view(), name='deploymentnetwork-list'),
- url(r'^plstackapi/deploymentnetworks/(?P<pk>[a-zA-Z0-9\-]+)/$', DeploymentRetrieveUpdateDestroy.as_view(), name='deploymentnetwork-detail'),
+ url(r'^plstackapi/deployments/$', DeploymentList.as_view(), name='deployment-list'),
+ url(r'^plstackapi/deployments/(?P<pk>[a-zA-Z0-9\-]+)/$', DeploymentDetail.as_view(), name='deployment-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/images/$', ImageList.as_view(), name='image-list'),
+ url(r'^plstackapi/images/(?P<pk>[a-zA-Z0-9_\-]+)/$', ImageDetail.as_view(), name='image-detail'),
#Adding in rest_framework urls
url(r'^plstackapi/', include('rest_framework.urls', namespace='rest_framework')),