Merge branch 'master' of github.com:open-cloud/xos
diff --git a/xos/core/models/controlleruser.py b/xos/core/models/controlleruser.py
index b950901..0900df7 100644
--- a/xos/core/models/controlleruser.py
+++ b/xos/core/models/controlleruser.py
@@ -15,6 +15,8 @@
controller = models.ForeignKey(Controller,related_name='controllersusers')
kuser_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Keystone user id")
+ composite_primary_key = ('user', 'controller', 'kuser_id')
+
def __unicode__(self): return u'%s %s' % (self.controller, self.user)
@staticmethod
@@ -38,6 +40,8 @@
site_privilege = models.ForeignKey('SitePrivilege', related_name='controllersiteprivileges')
role_id = StrippedCharField(null=True, blank=True, max_length=200, db_index=True, help_text="Keystone id")
+ composite_primary_key = ('controller', 'site_privilege', 'role_id')
+
def __unicode__(self): return u'%s %s' % (self.controller, self.site_privilege)
def can_update(self, user):
@@ -69,6 +73,8 @@
slice_privilege = models.ForeignKey('SlicePrivilege', related_name='controllersliceprivileges')
role_id = StrippedCharField(null=True, blank=True, max_length=200, db_index=True, help_text="Keystone id")
+ composite_primary_key = ('controller', 'slice_privilege')
+
def __unicode__(self): return u'%s %s' % (self.controller, self.slice_privilege)
def can_update(self, user):
diff --git a/xos/core/models/image.py b/xos/core/models/image.py
index b2123f8..0e12473 100644
--- a/xos/core/models/image.py
+++ b/xos/core/models/image.py
@@ -19,6 +19,8 @@
image = models.ForeignKey(Image,related_name='imagedeployments')
deployment = models.ForeignKey(Deployment,related_name='imagedeployments')
+ composite_primary_key = ('image', 'deployment')
+
def __unicode__(self): return u'%s %s' % (self.image, self.deployment)
def can_update(self, user):
@@ -30,5 +32,7 @@
image = models.ForeignKey(Image,related_name='controllerimages')
controller = models.ForeignKey(Controller,related_name='controllerimages')
glance_image_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Glance image id")
-
+
+ composite_primary_key = ('image', 'controller')
+
def __unicode__(self): return u'%s %s' % (self.image, self.controller)
diff --git a/xos/core/models/network.py b/xos/core/models/network.py
index 2572847..5346785 100644
--- a/xos/core/models/network.py
+++ b/xos/core/models/network.py
@@ -155,7 +155,10 @@
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")
subnet = models.CharField(max_length=32, blank=True)
-
+
+
+ composite_primary_key = ('network', 'controller')
+
@staticmethod
def select_by_user(user):
if user.is_admin:
@@ -173,6 +176,8 @@
network = models.ForeignKey(Network,related_name='networkslices')
slice = models.ForeignKey(Slice,related_name='networkslices')
+ composite_primary_key = ('network', 'slice')
+
def save(self, *args, **kwds):
slice = self.slice
if (slice not in self.network.permitted_slices.all()) and (slice != self.network.owner) and (not self.network.permitAllSlices):
@@ -204,6 +209,8 @@
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")
+ composite_primary_key = ('network', 'sliver')
+
def save(self, *args, **kwds):
slice = self.sliver.slice
if (slice not in self.network.permitted_slices.all()) and (slice != self.network.owner) and (not self.network.permitAllSlices):
diff --git a/xos/core/models/plcorebase.py b/xos/core/models/plcorebase.py
index 6a2ba34..2b814df 100644
--- a/xos/core/models/plcorebase.py
+++ b/xos/core/models/plcorebase.py
@@ -1,6 +1,7 @@
import datetime
import os
import sys
+from django import db
from django.db import models
from django.forms.models import model_to_dict
from django.core.urlresolvers import reverse
@@ -149,6 +150,10 @@
default="0 - Provisioning in progress")
deleted = models.BooleanField(default=False)
+ # XXX Django has no official support for composite primray keys yet
+ # so we will hack in an inefficient solution here.
+ composite_primary_key = []
+
class Meta:
# Changing abstract to False would require the managers of subclasses of
# PlCoreBase to be customized individually.
@@ -183,12 +188,31 @@
self.enacted=None
self.save(update_fields=['enacted','deleted'], silent=silent)
+ def check_composite_primary_key(self):
+ if not self.composite_primary_key:
+ return
+ # dictionary containing cpk field name and value
+ cpk_fields = dict([(name, getattr(self, name)) for name in self.composite_primary_key])
+ objs = self.__class__.objects.filter(**cpk_fields)
+ # we can only continue if there are no matches or
+ # if this record is updating itself
+ if (len(objs) == 0 or
+ (len(objs) == 1 and self.id and objs[0].id == self.id)):
+ return
+ # if we reach this point then we've matched more than 1
+ # existing record or we are trying to
+ msg = "%s violates composite primray key constraint on fields: %s " % (self, self.composite_primary_key)
+ raise db.Error, msg
+
+
def save(self, *args, **kwargs):
# let the user specify silence as either a kwarg or an instance varible
silent = self.silent
if "silent" in kwargs:
silent=silent or kwargs.pop("silent")
+ self.check_composite_primary_key()
+
super(PlCoreBase, self).save(*args, **kwargs)
# This is a no-op if observer_disabled is set
diff --git a/xos/core/models/site.py b/xos/core/models/site.py
index b26877d..3e8fb82 100644
--- a/xos/core/models/site.py
+++ b/xos/core/models/site.py
@@ -216,6 +216,7 @@
user = models.ForeignKey('User', related_name='deploymentprivileges')
deployment = models.ForeignKey('Deployment', related_name='deploymentprivileges')
role = models.ForeignKey('DeploymentRole',related_name='deploymentprivileges')
+ composite_primary_key = ('user', 'deployment', 'role')
def __unicode__(self): return u'%s %s %s' % (self.deployment, self.user, self.role)
@@ -277,6 +278,8 @@
controller = models.ForeignKey(Controller, null=True, blank=True, related_name='sitedeployments')
availability_zone = StrippedCharField(max_length=200, null=True, blank=True, help_text="OpenStack availability zone")
+ composite_primary_key = ('site', 'deployment', 'controller')
+
def __unicode__(self): return u'%s %s' % (self.deployment, self.site)
class ControllerSite(PlCoreBase):
@@ -284,3 +287,5 @@
site = models.ForeignKey(Site,related_name='controllersite')
controller = models.ForeignKey(Controller, null=True, blank=True, related_name='controllersite')
tenant_id = StrippedCharField(null=True, blank=True, max_length=200, db_index=True, help_text="Keystone tenant id")
+
+ composite_primary_key = ('site', 'controller')
diff --git a/xos/core/models/slice.py b/xos/core/models/slice.py
index 7c4e82f..22340ea 100644
--- a/xos/core/models/slice.py
+++ b/xos/core/models/slice.py
@@ -126,6 +126,8 @@
slice = models.ForeignKey('Slice', related_name='sliceprivileges')
role = models.ForeignKey('SliceRole',related_name='sliceprivileges')
+ composite_primary_key = ('user', 'slice', 'role')
+
def __unicode__(self): return u'%s %s %s' % (self.slice, self.user, self.role)
def can_update(self, user):
@@ -148,6 +150,8 @@
slice = models.ForeignKey(Slice, related_name='controllerslices')
tenant_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")
+ composite_primary_key = ('controller', 'slice')
+
def __unicode__(self): return u'%s %s' % (self.slice, self.controller)
@staticmethod