CORD-1154: Integrate xproto generator with corebuilder
Change-Id: Id3fb73f5368a15a79097a56b097726b6a57573b0
diff --git a/README.md b/README.md
index dc673ad..0b93d3f 100644
--- a/README.md
+++ b/README.md
@@ -21,4 +21,3 @@
version is configured with a service graph that includes
`ExampleService`, which is a good platform for understanding how to
build and use XOS.
-
diff --git a/containers/xos/Dockerfile.corebuilder b/containers/xos/Dockerfile.corebuilder
index f1e16a8..6b364b7 100644
--- a/containers/xos/Dockerfile.corebuilder
+++ b/containers/xos/Dockerfile.corebuilder
@@ -5,6 +5,9 @@
ADD xos/tools/corebuilder /opt/xos/tools/corebuilder
ADD xos/tosca/custom_types /opt/xos/tools/corebuilder/custom_types
+# Temporary fix. This should go away when we update xos-core to a more recent image.
+RUN pip install git+https://github.com/sb98052/plyprotobuf
+
ENV HOME /root
WORKDIR /opt/xos/tools/corebuilder
diff --git a/xos/core/core-onboard.yaml b/xos/core/core-onboard.yaml
new file mode 100644
index 0000000..59aefac
--- /dev/null
+++ b/xos/core/core-onboard.yaml
@@ -0,0 +1,14 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard XOS Core
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ servicecontroller#core:
+ type: tosca.nodes.ServiceController
+ properties:
+ base_url: file:///opt/xos/core
+ xproto: core/models
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
deleted file mode 100644
index 7bfdb58..0000000
--- a/xos/core/models/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from .plcorebase import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager,PlModelMixIn,ModelLink
-from .project import Project
-from .singletonmodel import SingletonModel
-from .xosmodel import XOS, XOSVolume
-from .service import Service, Tenant, TenantWithContainer, ServiceDependency, ServicePrivilege, TenantRoot, TenantRootPrivilege, TenantRootRole, TenantPrivilege, TenantRole
-from .service import ServiceAttribute, TenantAttribute, ServiceRole, ServiceMonitoringAgentInfo
-from .service import ServiceController, LoadableModule, LoadableModuleResource, Library
-from .service import XOSComponent, XOSComponentLink, XOSComponentVolume, XOSComponentVolumeContainer
-from .tag import Tag
-from .role import Role
-from .site import Site, Deployment, DeploymentRole, DeploymentPrivilege, Controller, ControllerRole, ControllerSite, SiteDeployment,Diag
-from .dashboard import DashboardView, ControllerDashboardView, XOSGuiExtension
-from .user import User, UserDashboardView
-from .serviceclass import ServiceClass
-from .site import ControllerManager, ControllerDeletionManager, ControllerLinkManager,ControllerLinkDeletionManager
-from .flavor import Flavor
-from .image import Image
-from .slice import Slice, ControllerSlice
-from .controlleruser import ControllerUser, ControllerSitePrivilege, ControllerSlicePrivilege
-from .image import ImageDeployments, ControllerImages
-from .serviceresource import ServiceResource
-from .slice import SliceRole
-from .slice import SlicePrivilege
-from .credential import UserCredential,SiteCredential,SliceCredential
-from .site import SiteRole
-from .site import SitePrivilege
-from .node import Node, NodeLabel
-from .slicetag import SliceTag
-from .instance import Instance
-from .reservation import ReservedResource
-from .reservation import Reservation
-from .network import Network, NetworkParameterType, NetworkParameter, Port, NetworkTemplate, Router, NetworkSlice, ControllerNetwork, AddressPool
-from .billing import Account, Invoice, Charge, UsableObject, Payment
-from .program import Program
-from .journal import JournalEntry, journal_object
diff --git a/xos/core/models/account.xproto b/xos/core/models/account.xproto
new file mode 100644
index 0000000..ba24140
--- /dev/null
+++ b/xos/core/models/account.xproto
@@ -0,0 +1,5 @@
+
+
+message Account (PlCoreBase){
+ required manytoone site->Site:accounts = 1 [help_text = "Site for this account", null = False, db_index = True, blank = False];
+}
diff --git a/xos/core/models/addresspool.xproto b/xos/core/models/addresspool.xproto
new file mode 100644
index 0000000..737de26
--- /dev/null
+++ b/xos/core/models/addresspool.xproto
@@ -0,0 +1,11 @@
+
+
+message AddressPool (PlCoreBase){
+ required string name = 1 [db_index = False, max_length = 32, null = False, blank = False];
+ optional string addresses = 2 [db_index = False, null = True, blank = True];
+ optional string gateway_ip = 3 [db_index = False, max_length = 32, null = True, blank = False];
+ optional string gateway_mac = 4 [db_index = False, max_length = 32, null = True, blank = False];
+ optional string cidr = 5 [db_index = False, max_length = 32, null = True, blank = False];
+ optional string inuse = 6 [db_index = False, null = True, blank = True];
+ optional manytoone service->Service:addresspools = 7 [db_index = True, null = True, blank = True];
+}
diff --git a/xos/core/models/attic/README.md b/xos/core/models/attic/README.md
new file mode 100644
index 0000000..784a8b6
--- /dev/null
+++ b/xos/core/models/attic/README.md
@@ -0,0 +1 @@
+This directory contains legacy code that needs to be refactored and eliminated. Eventually, the attic will be empty.
diff --git a/xos/core/models/attic/account_model.py b/xos/core/models/attic/account_model.py
new file mode 100644
index 0000000..3e75dc2
--- /dev/null
+++ b/xos/core/models/attic/account_model.py
@@ -0,0 +1,23 @@
+@property
+def total_invoices(self):
+ # Since the amount of an invoice is the sum of it's charges, we can
+ # compute the sum of the invoices by summing all charges where
+ # charge.invoice != Null.
+ x=self.charges.filter(invoice__isnull=False).aggregate(Sum('amount'))["amount__sum"]
+ if (x==None):
+ return 0.0
+ return x
+
+@property
+def total_payments(self):
+ x=self.payments.all().aggregate(Sum('amount'))["amount__sum"]
+ if (x==None):
+ return 0.0
+ return x
+
+@property
+def balance_due(self):
+ return self.total_invoices - self.total_payments
+
+def __unicode__(self): return u'%s' % (self.site.name)
+
diff --git a/xos/core/models/attic/addresspool_model.py b/xos/core/models/attic/addresspool_model.py
new file mode 100644
index 0000000..47576f1
--- /dev/null
+++ b/xos/core/models/attic/addresspool_model.py
@@ -0,0 +1,52 @@
+def __unicode__(self): return u'%s' % (self.name)
+
+def get_address(self):
+ with transaction.atomic():
+ ap = AddressPool.objects.get(pk=self.pk)
+ if ap.addresses:
+ avail_ips = ap.addresses.split()
+ else:
+ avail_ips = []
+
+ if ap.inuse:
+ inuse_ips = ap.inuse.split()
+ else:
+ inuse_ips = []
+
+ while avail_ips:
+ addr = avail_ips.pop(0)
+
+ if addr in inuse_ips:
+ # This may have happened if someone re-ran the tosca
+ # recipe and 'refilled' the AddressPool while some addresses
+ # were still in use.
+ continue
+
+ inuse_ips.insert(0,addr)
+
+ ap.inuse = " ".join(inuse_ips)
+ ap.addresses = " ".join(avail_ips)
+ ap.save()
+ return addr
+
+ addr = None
+ return addr
+
+def put_address(self, addr):
+ with transaction.atomic():
+ ap = AddressPool.objects.get(pk=self.pk)
+ addresses = ap.addresses or ""
+ parts = addresses.split()
+ if addr not in parts:
+ parts.insert(0,addr)
+ ap.addresses = " ".join(parts)
+
+ inuse = ap.inuse or ""
+ parts = inuse.split()
+ if addr in parts:
+ parts.remove(addr)
+ ap.inuse = " ".join(parts)
+
+ ap.save()
+
+
diff --git a/xos/core/models/attic/charge_model.py b/xos/core/models/attic/charge_model.py
new file mode 100644
index 0000000..0eed5ac
--- /dev/null
+++ b/xos/core/models/attic/charge_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s-%0.2f-%s' % (self.account.site.name, self.amount, str(self.date))
diff --git a/xos/core/models/attic/controller_model.py b/xos/core/models/attic/controller_model.py
new file mode 100644
index 0000000..b053cab
--- /dev/null
+++ b/xos/core/models/attic/controller_model.py
@@ -0,0 +1,26 @@
+objects = ControllerManager()
+deleted_objects = ControllerDeletionManager()
+
+def __init__(self, *args, **kwargs):
+ super(Controller, self).__init__(*args, **kwargs)
+ self.no_sync=True
+
+def __unicode__(self): return u'%s %s %s' % (self.name, self.backend_type, self.version)
+
+@property
+def auth_url_v3(self):
+ if self.auth_url and self.auth_url[-1] == '/':
+ return '{}/v3/'.format('/'.join(self.auth_url.split('/')[:-2]))
+ else:
+ return '{}/v3/'.format('/'.join(self.auth_url.split('/')[:-1]))
+
+@staticmethod
+def select_by_user(user):
+
+ if user.is_admin:
+ qs = Controller.objects.all()
+ else:
+ from core.models.deploymentprivilege import DeploymentPrivilege
+ deployments = [dp.deployment for dp in DeploymentPrivilege.objects.filter(user=user, role__role__in=['Admin', 'admin'])]
+ qs = Controller.objects.filter(deployment__in=deployments)
+ return qs
diff --git a/xos/core/models/attic/controllercredential_model.py b/xos/core/models/attic/controllercredential_model.py
new file mode 100644
index 0000000..64ee81b
--- /dev/null
+++ b/xos/core/models/attic/controllercredential_model.py
@@ -0,0 +1,5 @@
+objects = ControllerLinkManager()
+deleted_objects = ControllerLinkDeletionManager()
+
+def __unicode__(self):
+ return self.name
diff --git a/xos/core/models/attic/controllerdashboardview_model.py b/xos/core/models/attic/controllerdashboardview_model.py
new file mode 100644
index 0000000..bb2ede2
--- /dev/null
+++ b/xos/core/models/attic/controllerdashboardview_model.py
@@ -0,0 +1,2 @@
+objects = ControllerLinkManager()
+deleted_objects = ControllerLinkDeletionManager()
diff --git a/xos/core/models/attic/controllerimages_model.py b/xos/core/models/attic/controllerimages_model.py
new file mode 100644
index 0000000..42f2d1a
--- /dev/null
+++ b/xos/core/models/attic/controllerimages_model.py
@@ -0,0 +1,7 @@
+class Meta:
+ unique_together = ('image', 'controller')
+
+def __unicode__(self): return u'%s %s' % (self.image, self.controller)
+
+objects = ControllerLinkManager()
+deleted_objects = ControllerLinkDeletionManager()
diff --git a/xos/core/models/attic/controllernetwork_model.py b/xos/core/models/attic/controllernetwork_model.py
new file mode 100644
index 0000000..b1c9247
--- /dev/null
+++ b/xos/core/models/attic/controllernetwork_model.py
@@ -0,0 +1,26 @@
+objects = ControllerLinkManager()
+deleted_objects = ControllerLinkDeletionManager()
+
+class Meta:
+ unique_together = ('network', 'controller')
+
+def tologdict(self):
+ d=super(ControllerNetwork,self).tologdict()
+ try:
+ d['network_name']=self.network.name
+ d['controller_name']=self.controller.name
+ except:
+ pass
+ return d
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = ControllerNetwork.objects.all()
+ else:
+ from core.models.slice import Slice
+ slices = Slice.select_by_user(user)
+ networks = Network.objects.filter(owner__in=slices)
+ qs = ControllerNetwork.objects.filter(network__in=networks)
+ return qs
+
diff --git a/xos/core/models/attic/controllerrole_model.py b/xos/core/models/attic/controllerrole_model.py
new file mode 100644
index 0000000..c5ebd53
--- /dev/null
+++ b/xos/core/models/attic/controllerrole_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.role)
diff --git a/xos/core/models/attic/controllersite_model.py b/xos/core/models/attic/controllersite_model.py
new file mode 100644
index 0000000..987ce4c
--- /dev/null
+++ b/xos/core/models/attic/controllersite_model.py
@@ -0,0 +1,2 @@
+class Meta:
+ unique_together = ('site', 'controller')
diff --git a/xos/core/models/attic/controllersiteprivilege_model.py b/xos/core/models/attic/controllersiteprivilege_model.py
new file mode 100644
index 0000000..a3b3451
--- /dev/null
+++ b/xos/core/models/attic/controllersiteprivilege_model.py
@@ -0,0 +1,27 @@
+objects = ControllerLinkManager()
+deleted_objects = ControllerLinkDeletionManager()
+
+class Meta:
+ unique_together = ('controller', 'site_privilege', 'role_id')
+
+def __unicode__(self): return u'%s %s' % (self.controller, self.site_privilege)
+
+def can_update(self, user):
+ if user.is_readonly:
+ return False
+ if user.is_admin:
+ return True
+ cprivs = ControllerSitePrivilege.objects.filter(site_privilege__user=user)
+ for cpriv in dprivs:
+ if cpriv.site_privilege.role.role == ['admin', 'Admin']:
+ return True
+ return False
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = ControllerSitePrivilege.objects.all()
+ else:
+ cpriv_ids = [cp.id for cp in ControllerSitePrivilege.objects.filter(site_privilege__user=user)]
+ qs = ControllerSitePrivilege.objects.filter(id__in=cpriv_ids)
+ return qs
diff --git a/xos/core/models/attic/controllerslice_model.py b/xos/core/models/attic/controllerslice_model.py
new file mode 100644
index 0000000..9e9fdc3
--- /dev/null
+++ b/xos/core/models/attic/controllerslice_model.py
@@ -0,0 +1,36 @@
+objects = ControllerLinkManager()
+deleted_objects = ControllerLinkDeletionManager()
+
+class Meta:
+ unique_together = ('controller', 'slice')
+
+def tologdict(self):
+ d=super(ControllerSlice,self).tologdict()
+ try:
+ d['slice_name']=self.slice.name
+ d['controller_name']=self.controller.name
+ except:
+ pass
+ return d
+
+def __unicode__(self): return u'%s %s' % (self.slice, self.controller)
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = ControllerSlice.objects.all()
+ else:
+ slices = Slice.select_by_user(user)
+ qs = ControllerSlice.objects.filter(slice__in=slices)
+ return qs
+
+def get_cpu_stats(self):
+ filter = 'project_id=%s'%self.tenant_id
+ return monitor.get_meter('cpu',filter,None)
+
+def get_bw_stats(self):
+ filter = 'project_id=%s'%self.tenant_id
+ return monitor.get_meter('network.outgoing.bytes',filter,None)
+
+def get_node_stats(self):
+ return len(self.slice.instances)
diff --git a/xos/core/models/attic/controllersliceprivilege_model.py b/xos/core/models/attic/controllersliceprivilege_model.py
new file mode 100644
index 0000000..6414464
--- /dev/null
+++ b/xos/core/models/attic/controllersliceprivilege_model.py
@@ -0,0 +1,24 @@
+class Meta:
+ unique_together = ('controller', 'slice_privilege')
+
+def __unicode__(self): return u'%s %s' % (self.controller, self.slice_privilege)
+
+def can_update(self, user):
+ if user.is_readonly:
+ return False
+ if user.is_admin:
+ return True
+ cprivs = ControllerSlicePrivilege.objects.filter(slice_privilege__user=user)
+ for cpriv in dprivs:
+ if cpriv.role.role == ['admin', 'Admin']:
+ return True
+ return False
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = ControllerSlicePrivilege.objects.all()
+ else:
+ cpriv_ids = [cp.id for cp in ControllerSlicePrivilege.objects.filter(slice_privilege__user=user)]
+ qs = ControllerSlicePrivilege.objects.filter(id__in=cpriv_ids)
+ return qs
diff --git a/xos/core/models/attic/controlleruser_model.py b/xos/core/models/attic/controlleruser_model.py
new file mode 100644
index 0000000..d6d73cb
--- /dev/null
+++ b/xos/core/models/attic/controlleruser_model.py
@@ -0,0 +1,20 @@
+objects = ControllerLinkManager()
+deleted_objects = ControllerLinkDeletionManager()
+
+class Meta:
+ unique_together = ('user', 'controller')
+
+def __unicode__(self): return u'%s %s' % (self.controller, self.user)
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = ControllerUser.objects.all()
+ else:
+ users = User.select_by_user(user)
+ qs = ControllerUser.objects.filter(user__in=users)
+ return qs
+
+def can_update(self, user):
+ return user.can_update_root()
+
diff --git a/xos/core/models/attic/dashboardview_model.py b/xos/core/models/attic/dashboardview_model.py
new file mode 100644
index 0000000..087b164
--- /dev/null
+++ b/xos/core/models/attic/dashboardview_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/attic/deployment_model.py b/xos/core/models/attic/deployment_model.py
new file mode 100644
index 0000000..a055df3
--- /dev/null
+++ b/xos/core/models/attic/deployment_model.py
@@ -0,0 +1,40 @@
+def __init__(self, *args, **kwargs):
+ super(Deployment, self).__init__(*args, **kwargs)
+ self.no_sync=True
+
+def get_acl(self):
+ return AccessControlList(self.accessControl)
+
+def test_acl(self, slice=None, user=None):
+ potential_users=[]
+
+ if user:
+ potential_users.append(user)
+
+ if slice:
+ potential_users.append(slice.creator)
+ for priv in slice.sliceprivileges.all():
+ if priv.user not in potential_users:
+ potential_users.append(priv.user)
+
+ acl = self.get_acl()
+ for user in potential_users:
+ if acl.test(user) == "allow":
+ return True
+
+ return False
+
+@staticmethod
+def select_by_acl(user):
+ ids = []
+ for deployment in Deployment.objects.all():
+ acl = deployment.get_acl()
+ if acl.test(user) == "allow":
+ ids.append(deployment.id)
+
+ return Deployment.objects.filter(id__in=ids)
+
+def can_update(self, user):
+ return user.can_update_deployment(self)
+
+def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/attic/deploymentprivilege_model.py b/xos/core/models/attic/deploymentprivilege_model.py
new file mode 100644
index 0000000..539234c
--- /dev/null
+++ b/xos/core/models/attic/deploymentprivilege_model.py
@@ -0,0 +1,17 @@
+class Meta:
+ unique_together = ('user', 'deployment', 'role')
+
+def __unicode__(self): return u'%s %s %s' % (self.deployment, self.user, self.role)
+
+def can_update(self, user):
+ return user.can_update_deployment(self)
+
+@staticmethod
+def select_by_user(user):
+ from core.models.deploymentprivilege import DeploymentPrivilege
+ if user.is_admin:
+ qs = DeploymentPrivilege.objects.all()
+ else:
+ dpriv_ids = [dp.id for dp in DeploymentPrivilege.objects.filter(user=user)]
+ qs = DeploymentPrivilege.objects.filter(id__in=dpriv_ids)
+ return qs
diff --git a/xos/core/models/attic/deploymentrole_model.py b/xos/core/models/attic/deploymentrole_model.py
new file mode 100644
index 0000000..b35a54b
--- /dev/null
+++ b/xos/core/models/attic/deploymentrole_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.role)
diff --git a/xos/core/models/attic/diag_model.py b/xos/core/models/attic/diag_model.py
new file mode 100644
index 0000000..bf6bd68
--- /dev/null
+++ b/xos/core/models/attic/diag_model.py
@@ -0,0 +1,7 @@
+@property
+def enacted(self):
+ return None
+
+@enacted.setter
+def enacted(self, value):
+ pass # Ignore sets, Diag objects are always pending.
diff --git a/xos/core/models/attic/flavor_model.py b/xos/core/models/attic/flavor_model.py
new file mode 100644
index 0000000..f5403f7
--- /dev/null
+++ b/xos/core/models/attic/flavor_model.py
@@ -0,0 +1,9 @@
+class Meta:
+ app_label = "core"
+ ordering = ('order', 'name')
+
+def __init__(self, *args, **kwargs):
+ super(Flavor, self).__init__(*args, **kwargs)
+ self.no_sync=True
+
+def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/attic/header.py b/xos/core/models/attic/header.py
new file mode 100644
index 0000000..fe0a7f6
--- /dev/null
+++ b/xos/core/models/attic/header.py
@@ -0,0 +1,226 @@
+from __future__ import absolute_import
+
+import sys
+import json
+import operator
+from operator import attrgetter
+from core.models.plcorebase import *
+from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
+from django.contrib.contenttypes.models import ContentType
+from django.utils.timezone import now
+from core.acl import AccessControlList
+from django.core.exceptions import ValidationError,PermissionDenied
+
+from distutils.version import LooseVersion
+from django.db import models,transaction
+from django.db.models import *
+from django.core.validators import URLValidator
+from xos.exceptions import *
+import urlparse
+from xos.config import Config
+
+config = Config()
+
+# If true, then IP addresses will be allocated by the model. If false, then
+# we will assume the observer handles it.
+NO_OBSERVER=False
+
+def ParseNatList(ports):
+ """ Support a list of ports in the format "protocol:port, protocol:port, ..."
+ examples:
+ tcp 123
+ tcp 123:133
+ tcp 123, tcp 124, tcp 125, udp 201, udp 202
+
+ User can put either a "/" or a " " between protocol and ports
+ Port ranges can be specified with "-" or ":"
+ """
+ nats = []
+ if ports:
+ parts = ports.split(",")
+ for part in parts:
+ part = part.strip()
+ if "/" in part:
+ (protocol, ports) = part.split("/",1)
+ elif " " in part:
+ (protocol, ports) = part.split(None,1)
+ else:
+ raise TypeError('malformed port specifier %s, format example: "tcp 123, tcp 201:206, udp 333"' % part)
+
+ protocol = protocol.strip()
+ ports = ports.strip()
+
+ if not (protocol in ["udp", "tcp"]):
+ raise ValueError('unknown protocol %s' % protocol)
+
+ if "-" in ports:
+ (first, last) = ports.split("-")
+ first = int(first.strip())
+ last = int(last.strip())
+ portStr = "%d:%d" % (first, last)
+ elif ":" in ports:
+ (first, last) = ports.split(":")
+ first = int(first.strip())
+ last = int(last.strip())
+ portStr = "%d:%d" % (first, last)
+ else:
+ portStr = "%d" % int(ports)
+
+ nats.append( {"l4_protocol": protocol, "l4_port": portStr} )
+
+ return nats
+
+def ValidateNatList(ports):
+ try:
+ ParseNatList(ports)
+ except Exception,e:
+ raise ValidationError(str(e))
+
+
+
+def get_default_flavor(controller = None):
+ # Find a default flavor that can be used for a instance. This is particularly
+ # useful in evolution. It's also intended this helper function can be used
+ # for admin.py when users
+
+ if controller:
+ flavors = controller.flavors.all()
+ else:
+ from core.models.flavor import Flavor
+ flavors = Flavor.objects.all()
+
+ if not flavors:
+ return None
+
+ for flavor in flavors:
+ if flavor.default:
+ return flavor
+
+ return flavors[0]
+
+class InstanceDeletionManager(PlCoreBaseDeletionManager):
+ def get_queryset(self):
+ parent=super(InstanceDeletionManager, self)
+ try:
+ backend_type = config.observer_backend_type
+ except AttributeError:
+ backend_type = None
+
+ parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+ if (backend_type):
+ return parent_queryset.filter(Q(node__controller__backend_type=backend_type))
+ else:
+ return parent_queryset
+
+ # deprecated in django 1.7 in favor of get_queryset().
+ def get_query_set(self):
+ return self.get_queryset()
+
+
+class InstanceManager(PlCoreBaseManager):
+ def get_queryset(self):
+ parent=super(InstanceManager, self)
+
+ try:
+ backend_type = config.observer_backend_type
+ except AttributeError:
+ backend_type = None
+
+ parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+
+ if backend_type:
+ return parent_queryset.filter(Q(node__controller__backend_type=backend_type))
+ else:
+ return parent_queryset
+
+ # deprecated in django 1.7 in favor of get_queryset().
+ def get_query_set(self):
+ return self.get_queryset()
+
+def get_default_serviceclass():
+ from core.models.serviceclass import ServiceClass
+ try:
+ return ServiceClass.objects.get(name="Best Effort")
+ except ServiceClass.DoesNotExist:
+ return None
+
+class ControllerLinkDeletionManager(PlCoreBaseDeletionManager):
+ def get_queryset(self):
+ parent=super(ControllerLinkDeletionManager, self)
+ try:
+ backend_type = config.observer_backend_type
+ except AttributeError:
+ backend_type = None
+
+ parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+ if (backend_type):
+ return parent_queryset.filter(Q(controller__backend_type=backend_type))
+ else:
+ return parent_queryset
+
+ # deprecated in django 1.7 in favor of get_queryset().
+ def get_query_set(self):
+ return self.get_queryset()
+
+
+class ControllerDeletionManager(PlCoreBaseDeletionManager):
+ def get_queryset(self):
+ parent=super(ControllerDeletionManager, self)
+
+ try:
+ backend_type = config.observer_backend_type
+ except AttributeError:
+ backend_type = None
+
+ parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+
+ if backend_type:
+ return parent_queryset.filter(Q(backend_type=backend_type))
+ else:
+ return parent_queryset
+
+ # deprecated in django 1.7 in favor of get_queryset().
+ def get_query_set(self):
+ return self.get_queryset()
+
+class ControllerLinkManager(PlCoreBaseManager):
+ def get_queryset(self):
+ parent=super(ControllerLinkManager, self)
+
+ try:
+ backend_type = config.observer_backend_type
+ except AttributeError:
+ backend_type = None
+
+ parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+
+ if backend_type:
+ return parent_queryset.filter(Q(controller__backend_type=backend_type))
+ else:
+ return parent_queryset
+
+ # deprecated in django 1.7 in favor of get_queryset().
+ def get_query_set(self):
+ return self.get_queryset()
+
+
+class ControllerManager(PlCoreBaseManager):
+ def get_queryset(self):
+ parent=super(ControllerManager, self)
+
+ try:
+ backend_type = config.observer_backend_type
+ except AttributeError:
+ backend_type = None
+
+ parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+
+ if backend_type:
+ return parent_queryset.filter(Q(backend_type=backend_type))
+ else:
+ return parent_queryset
+
+ # deprecated in django 1.7 in favor of get_queryset().
+ def get_query_set(self):
+ return self.get_queryset()
+
diff --git a/xos/core/models/attic/image_model.py b/xos/core/models/attic/image_model.py
new file mode 100644
index 0000000..32aa211
--- /dev/null
+++ b/xos/core/models/attic/image_model.py
@@ -0,0 +1,4 @@
+objects = ControllerLinkManager()
+deleted_objects = ControllerLinkDeletionManager()
+
+def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/attic/imagedeployments_model.py b/xos/core/models/attic/imagedeployments_model.py
new file mode 100644
index 0000000..612cbb2
--- /dev/null
+++ b/xos/core/models/attic/imagedeployments_model.py
@@ -0,0 +1,7 @@
+class Meta:
+ unique_together = ('image', 'deployment')
+
+def __unicode__(self): return u'%s %s' % (self.image, self.deployment)
+
+def can_update(self, user):
+ return user.can_update_deployment(self.deployment)
diff --git a/xos/core/models/attic/instance_bottom.py b/xos/core/models/attic/instance_bottom.py
new file mode 100644
index 0000000..7b87eab
--- /dev/null
+++ b/xos/core/models/attic/instance_bottom.py
@@ -0,0 +1,7 @@
+def controller_setter(instance, **kwargs):
+ try:
+ instance.controller = instance.node.site_deployment.controller
+ except:
+ instance.controller = None
+
+models.signals.post_init.connect(controller_setter, Instance)
diff --git a/xos/core/models/attic/instance_model.py b/xos/core/models/attic/instance_model.py
new file mode 100644
index 0000000..b42dcfc
--- /dev/null
+++ b/xos/core/models/attic/instance_model.py
@@ -0,0 +1,153 @@
+objects = InstanceManager()
+deleted_objects = InstanceDeletionManager()
+
+def get_controller (self):
+ return self.node.site_deployment.controller
+
+def tologdict(self):
+ d=super(Instance,self).tologdict()
+ try:
+ d['slice_name']=self.slice.name
+ d['controller_name']=self.get_controller().name
+ except:
+ pass
+ return d
+
+def __unicode__(self):
+ if self.name and Slice.objects.filter(id=self.slice_id) and (self.name != self.slice.name):
+ # NOTE: The weird check on self.slice_id was due to a problem when
+ # deleting the slice before the instance.
+ return u'%s' % self.name
+ elif self.instance_name:
+ return u'%s' % (self.instance_name)
+ elif self.id:
+ return u'uninstantiated-%s' % str(self.id)
+ elif self.slice:
+ return u'unsaved-instance on %s' % self.slice.name
+ else:
+ return u'unsaved-instance'
+
+def save(self, *args, **kwds):
+ if not self.name:
+ self.name = self.slice.name
+ if not self.creator and hasattr(self, 'caller'):
+ self.creator = self.caller
+ if not self.creator:
+ raise ValidationError('instance has no creator')
+
+ if (self.isolation == "container") or (self.isolation == "container_vm"):
+ if (self.image.kind != "container"):
+ raise ValidationError("Container instance must use container image")
+ elif (self.isolation == "vm"):
+ if (self.image.kind != "vm"):
+ raise ValidationError("VM instance must use VM image")
+
+ if (self.isolation == "container_vm") and (not self.parent):
+ raise ValidationError("Container-vm instance must have a parent")
+
+ if (self.parent) and (self.isolation != "container_vm"):
+ raise ValidationError("Parent field can only be set on Container-vm instances")
+
+ if (self.slice.creator != self.creator):
+ from core.models.sliceprivilege import SlicePrivilege
+ # Check to make sure there's a slice_privilege for the user. If there
+ # isn't, then keystone will throw an exception inside the observer.
+ slice_privs = SlicePrivilege.objects.filter(slice=self.slice, user=self.creator)
+ if not slice_privs:
+ raise ValidationError('instance creator has no privileges on slice')
+
+# XXX smbaker - disabled for now, was causing fault in tenant view create slice
+# if not self.controllerNetwork.test_acl(slice=self.slice):
+# raise exceptions.ValidationError("Deployment %s's ACL does not allow any of this slice %s's users" % (self.controllerNetwork.name, self.slice.name))
+
+ super(Instance, self).save(*args, **kwds)
+
+def can_update(self, user):
+ return user.can_update_slice(self.slice)
+
+def all_ips(self):
+ ips={}
+ for ns in self.ports.all():
+ if ns.ip:
+ ips[ns.network.name] = ns.ip
+ return ips
+
+def all_ips_string(self):
+ result = []
+ ips = self.all_ips()
+ for key in sorted(ips.keys()):
+ #result.append("%s = %s" % (key, ips[key]))
+ result.append(ips[key])
+ return ", ".join(result)
+all_ips_string.short_description = "addresses"
+
+def get_public_ip(self):
+ for ns in self.ports.all():
+ if (ns.ip) and (ns.network.template.visibility=="public") and (ns.network.template.translation=="none"):
+ return ns.ip
+ return None
+
+# return an address on nat-net
+def get_network_ip(self, pattern):
+ for ns in self.ports.all():
+ if pattern in ns.network.name.lower():
+ return ns.ip
+ return None
+
+# return an address that the synchronizer can use to SSH to the instance
+def get_ssh_ip(self):
+ # first look specifically for a management_local network
+ for ns in self.ports.all():
+ if ns.network.template and ns.network.template.vtn_kind=="MANAGEMENT_LOCAL":
+ return ns.ip
+
+ # for compatibility, now look for any management network
+ management=self.get_network_ip("management")
+ if management:
+ return management
+
+ # if all else fails, look for nat-net (for OpenCloud?)
+ return self.get_network_ip("nat")
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = Instance.objects.all()
+ else:
+ slices = Slice.select_by_user(user)
+ qs = Instance.objects.filter(slice__in=slices)
+ return qs
+
+def get_cpu_stats(self):
+ filter = 'instance_id=%s'%self.instance_id
+ return monitor.get_meter('cpu',filter,None)
+
+def get_bw_stats(self):
+ filter = 'instance_id=%s'%self.instance_id
+ return monitor.get_meter('network.outgoing.bytes',filter,None)
+
+def get_node_stats(self):
+ # Note sure what should go back here
+ return 1
+
+def get_ssh_command(self):
+ if (not self.instance_id) or (not self.node) or (not self.instance_name):
+ return None
+ else:
+ return 'ssh -o "ProxyCommand ssh -q %s@%s" ubuntu@%s' % (self.instance_id, self.node.name, self.instance_name)
+
+def get_public_keys(self):
+ from core.models.sliceprivilege import SlicePrivilege
+ slice_memberships = SlicePrivilege.objects.filter(slice=self.slice)
+ pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
+
+ if self.creator.public_key:
+ pubkeys.add(self.creator.public_key)
+
+ if self.slice.creator.public_key:
+ pubkeys.add(self.slice.creator.public_key)
+
+ if self.slice.service and self.slice.service.public_key:
+ pubkeys.add(self.slice.service.public_key)
+
+ return pubkeys
diff --git a/xos/core/models/attic/invoice_model.py b/xos/core/models/attic/invoice_model.py
new file mode 100644
index 0000000..73dea2c
--- /dev/null
+++ b/xos/core/models/attic/invoice_model.py
@@ -0,0 +1,5 @@
+@property
+def amount(self):
+ return str(self.charges.all().aggregate(Sum('amount'))["amount__sum"])
+
+def __unicode__(self): return u'%s-%s' % (self.account.site.name, str(self.date))
diff --git a/xos/core/models/attic/loadable_top.py b/xos/core/models/attic/loadable_top.py
new file mode 100644
index 0000000..474a085
--- /dev/null
+++ b/xos/core/models/attic/loadable_top.py
@@ -0,0 +1 @@
+from service_header import *
diff --git a/xos/core/models/attic/loadablemodule_model.py b/xos/core/models/attic/loadablemodule_model.py
new file mode 100644
index 0000000..53d4404
--- /dev/null
+++ b/xos/core/models/attic/loadablemodule_model.py
@@ -0,0 +1,74 @@
+def __unicode__(self): return u'%s' % (self.name)
+
+def save(self, *args, **kwargs):
+ super(LoadableModule, self).save(*args, **kwargs)
+
+ # This is necessary, as the XOS syncstep handles rerunning the docker-
+ # compose.
+ # TODO: Update synchronizer and replace with watcher functionality
+ if self.xos:
+ # force XOS to rebuild
+ self.xos.save(update_fields=["updated"])
+
+def get_provides_list(self):
+ prov_list = []
+ if self.provides and self.provides.strip():
+ for prov in self.provides.split(","):
+ prov=prov.strip()
+ if "=" in prov:
+ (name, version) = prov.split("=",1)
+ name = name.strip()
+ version = version.strip()
+ else:
+ name = prov
+ version = "1.0.0"
+ prov_list.append( {"name": name, "version": version} )
+
+ # every controller provides itself
+ prov_list.append( {"name": self.name, "version": self.version} )
+
+ return prov_list
+
+
+@classmethod
+def dependency_check(cls, dep_list):
+ missing = []
+ satisfied = []
+ operators = {">=": operator.ge,
+ "<=": operator.le,
+ ">": operator.gt,
+ "<": operator.lt,
+ "!=": operator.ne,
+ "=": operator.eq}
+ from core.models.servicecontroller import ServiceController
+
+ for dep in dep_list:
+ dep = dep.strip()
+ name = dep
+ version = None
+ this_op = None
+ for op in operators.keys():
+ if op in dep:
+ (name, version) = dep.split(op,1)
+ name = name.strip()
+ version = version.strip()
+ this_op = operators[op]
+ break
+ found=False
+ scs = ServiceController.objects.all()
+ for sc in scs:
+ for provide in sc.get_provides_list():
+ if (provide["name"] != name):
+ continue
+ if not this_op:
+ satisfied.append(sc)
+ found=True
+ break
+ elif this_op(LooseVersion(provide["version"]), LooseVersion(version)):
+ satisfied.append(sc)
+ found=True
+ break
+ if not found:
+ missing.append(dep)
+
+ return (satisfied, missing)
diff --git a/xos/core/models/attic/loadablemoduleresource_model.py b/xos/core/models/attic/loadablemoduleresource_model.py
new file mode 100644
index 0000000..d248f33
--- /dev/null
+++ b/xos/core/models/attic/loadablemoduleresource_model.py
@@ -0,0 +1,8 @@
+def __unicode__(self): return u'%s' % (self.name)
+
+@property
+def full_url(self):
+ if self.loadable_module and self.loadable_module.base_url:
+ return urlparse.urljoin(self.loadable_module.base_url, self.url)
+ else:
+ return self.url
diff --git a/xos/core/models/attic/network_header.py b/xos/core/models/attic/network_header.py
new file mode 100644
index 0000000..e7c67bf
--- /dev/null
+++ b/xos/core/models/attic/network_header.py
@@ -0,0 +1,3 @@
+# If true, then IP addresses will be allocated by the model. If false, then
+# we will assume the observer handles it.
+NO_OBSERVER=False
diff --git a/xos/core/models/attic/network_model.py b/xos/core/models/attic/network_model.py
new file mode 100644
index 0000000..b3a3493
--- /dev/null
+++ b/xos/core/models/attic/network_model.py
@@ -0,0 +1,34 @@
+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()])
+ print "DEF_MOD_NET_IP", self.start_ip
+ super(Network, self).save(*args, **kwds)
+
+def can_update(self, user):
+ return user.can_update_slice(self.owner)
+
+@property
+def nat_list(self):
+ return ParseNatList(self.ports)
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = Network.objects.all()
+ else:
+ slices = Slice.select_by_user(user)
+ #slice_ids = [s.id for s in Slice.select_by_user(user)]
+ qs = Network.objects.filter(owner__in=slices)
+ return qs
+
+def get_parameters(self):
+ # returns parameters from the template, updated by self.
+ p={}
+ if self.template:
+ p = self.template.get_parameters()
+ p.update(ParameterMixin.get_parameters(self))
+ return p
+
diff --git a/xos/core/models/attic/network_top.py b/xos/core/models/attic/network_top.py
new file mode 100644
index 0000000..47ae705
--- /dev/null
+++ b/xos/core/models/attic/network_top.py
@@ -0,0 +1,34 @@
+
+from core.models.networkparameter import NetworkParameter
+
+class ParameterMixin(object):
+ # helper classes for dealing with NetworkParameter
+
+ def get_parameters(self):
+ parameter_dict = {}
+
+ instance_type = ContentType.objects.get_for_model(self)
+ for param in NetworkParameter.objects.filter(content_type__pk=instance_type.id, object_id=self.id):
+ parameter_dict[param.parameter.name] = param.value
+
+ return parameter_dict
+
+ def set_parameter(self, name, value):
+ instance_type = ContentType.objects.get_for_model(self)
+ existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
+ if existing_params:
+ p=existing_params[0]
+ p.value = value
+ p.save()
+ else:
+ from core.models.networkparametertype import NetworkParameterType
+ pt = NetworkParameterType.objects.get(name=name)
+ p = NetworkParameter(parameter=pt, content_type=instance_type, object_id=self.id, value=value)
+ p.save()
+
+ def unset_parameter(self, name):
+ instance_type = ContentType.objects.get_for_model(self)
+ existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
+ for p in existing_params:
+ p.delete()
+
diff --git a/xos/core/models/attic/networkparameter_model.py b/xos/core/models/attic/networkparameter_model.py
new file mode 100644
index 0000000..2bbfbe7
--- /dev/null
+++ b/xos/core/models/attic/networkparameter_model.py
@@ -0,0 +1,5 @@
+content_object = GenericForeignKey('content_type', 'object_id')
+
+def __unicode__(self):
+ return self.parameter.name
+
diff --git a/xos/core/models/attic/networkparametertype_model.py b/xos/core/models/attic/networkparametertype_model.py
new file mode 100644
index 0000000..3fd623e
--- /dev/null
+++ b/xos/core/models/attic/networkparametertype_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/attic/networkslice_model.py b/xos/core/models/attic/networkslice_model.py
new file mode 100644
index 0000000..9c038fa
--- /dev/null
+++ b/xos/core/models/attic/networkslice_model.py
@@ -0,0 +1,29 @@
+class Meta:
+ unique_together = ('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.permit_all_slices):
+ # to add a instance to the network, then one of the following must be true:
+ # 1) instance's slice is in network's permittedSlices list,
+ # 2) instance'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)
+
+def can_update(self, user):
+ return user.can_update_slice(self.slice)
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = NetworkSlice.objects.all()
+ else:
+ slice_ids = [s.id for s in Slice.select_by_user(user)]
+ network_ids = [network.id for network in Network.select_by_user(user)]
+ qs = NetworkSlice.objects.filter(Q(slice__in=slice_ids) | Q(network__in=network_ids))
+ return qs
+
diff --git a/xos/core/models/attic/networktemplate_model.py b/xos/core/models/attic/networktemplate_model.py
new file mode 100644
index 0000000..2bd4db3
--- /dev/null
+++ b/xos/core/models/attic/networktemplate_model.py
@@ -0,0 +1,21 @@
+ACCESS_CHOICES = ((None, 'None'), ('indirect', 'Indirect'), ('direct', 'Direct'))
+
+def __init__(self, *args, **kwargs):
+ super(NetworkTemplate, self).__init__(*args, **kwargs)
+
+ if (self.topology_kind=="BigSwitch"):
+ print >> sys.stderr, "XXX warning: topology_kind invalid case"
+ self.topology_kind="bigswitch"
+ elif (self.topology_kind=="Physical"):
+ print >> sys.stderr, "XXX warning: topology_kind invalid case"
+ self.topology_kind="physical"
+ elif (self.topology_kind=="Custom"):
+ print >> sys.stderr, "XXX warning: topology_kind invalid case"
+ self.toplogy_kind="custom"
+
+def save(self, *args, **kwargs):
+ self.enforce_choices(self.access, self.ACCESS_CHOICES)
+ super(NetworkTemplate, self).save(*args, **kwargs)
+
+def __unicode__(self): return u'%s' % (self.name)
+
diff --git a/xos/core/models/attic/node_model.py b/xos/core/models/attic/node_model.py
new file mode 100644
index 0000000..71b769c
--- /dev/null
+++ b/xos/core/models/attic/node_model.py
@@ -0,0 +1,14 @@
+def __unicode__(self): return u'%s' % (self.name)
+
+def __init__(self, *args, **kwargs):
+ super(Node, self).__init__(*args, **kwargs)
+ self.no_sync=True
+
+def can_update(self, user):
+ return user.can_update_site(self.site, allow=['tech'])
+
+def save(self, *args, **kwds):
+ if self.site is None and self.site_deployment is not None:
+ self.site = self.site_deployment.site
+
+ super(Node, self).save(*args, **kwds)
diff --git a/xos/core/models/attic/nodelabel_model.py b/xos/core/models/attic/nodelabel_model.py
new file mode 100644
index 0000000..087b164
--- /dev/null
+++ b/xos/core/models/attic/nodelabel_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/attic/payment_model.py b/xos/core/models/attic/payment_model.py
new file mode 100644
index 0000000..75d7580
--- /dev/null
+++ b/xos/core/models/attic/payment_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s-%0.2f-%s' % (self.account.site.name, self.amount, str(self.date))
diff --git a/xos/core/models/attic/port_model.py b/xos/core/models/attic/port_model.py
new file mode 100644
index 0000000..3b3ffcc
--- /dev/null
+++ b/xos/core/models/attic/port_model.py
@@ -0,0 +1,48 @@
+class Meta:
+ unique_together = ('network', 'instance')
+
+def save(self, *args, **kwds):
+ if self.instance:
+ slice = self.instance.slice
+ if (slice not in self.network.permitted_slices.all()) and (slice != self.network.owner) and (not self.network.permit_all_slices):
+ # to add a instance to the network, then one of the following must be true:
+ # 1) instance's slice is in network's permittedSlices list,
+ # 2) instance'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(Port, self).save(*args, **kwds)
+
+def __unicode__(self):
+ if self.instance:
+ return u'%s-%s' % (self.network.name, self.instance.instance_name)
+ else:
+ return u'%s-unboundport-%s' % (self.network.name, self.id)
+
+def can_update(self, user):
+ if self.instance:
+ return user.can_update_slice(self.instance.slice)
+ if self.network:
+ return user.can_update_slice(self.network.owner)
+ return False
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = Port.objects.all()
+ else:
+ instances = Instance.select_by_user(user)
+ instance_ids = [instance.id for instance in instances]
+ networks = Network.select_by_user(user)
+ network_ids = [network.id for network in networks]
+ qs = Port.objects.filter(Q(instance__in=instance_ids) | Q(network__in=network_ids))
+ return qs
+
+def get_parameters(self):
+ # returns parameters from the network, updated by self.
+ p={}
+ if self.network:
+ p = self.network.get_parameters()
+ p.update(ParameterMixin.get_parameters(self))
+ return p
+
diff --git a/xos/core/models/attic/port_top.py b/xos/core/models/attic/port_top.py
new file mode 100644
index 0000000..67dabf0
--- /dev/null
+++ b/xos/core/models/attic/port_top.py
@@ -0,0 +1,34 @@
+
+from core.models.networkparameter import NetworkParameter
+from core.models.networkparametertype import NetworkParameterType
+
+class ParameterMixin(object):
+ # helper classes for dealing with NetworkParameter
+
+ def get_parameters(self):
+ parameter_dict = {}
+
+ instance_type = ContentType.objects.get_for_model(self)
+ for param in NetworkParameter.objects.filter(content_type__pk=instance_type.id, object_id=self.id):
+ parameter_dict[param.parameter.name] = param.value
+
+ return parameter_dict
+
+ def set_parameter(self, name, value):
+ instance_type = ContentType.objects.get_for_model(self)
+ existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
+ if existing_params:
+ p=existing_params[0]
+ p.value = value
+ p.save()
+ else:
+ pt = NetworkParameterType.objects.get(name=name)
+ p = NetworkParameter(parameter=pt, content_type=instance_type, object_id=self.id, value=value)
+ p.save()
+
+ def unset_parameter(self, name):
+ instance_type = ContentType.objects.get_for_model(self)
+ existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
+ for p in existing_params:
+ p.delete()
+
diff --git a/xos/core/models/attic/program_model.py b/xos/core/models/attic/program_model.py
new file mode 100644
index 0000000..dc7ccdf
--- /dev/null
+++ b/xos/core/models/attic/program_model.py
@@ -0,0 +1,18 @@
+@classmethod
+def select_by_user(cls, user):
+ return cls.objects.all()
+
+def __unicode__(self): return u'%s' % (self.name)
+
+def can_update(self, user):
+ return True
+
+def save(self, *args, **kwargs):
+ # set creator on first save
+ if not self.owner and hasattr(self, 'caller'):
+ self.owner = self.caller
+
+ if (self.command in ["run", "destroy"]) and (self.status in ["complete", "exception"]):
+ self.status = "queued"
+
+ super(Program, self).save(*args, **kwargs)
diff --git a/xos/core/models/attic/project_model.py b/xos/core/models/attic/project_model.py
new file mode 100644
index 0000000..3fd623e
--- /dev/null
+++ b/xos/core/models/attic/project_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/attic/reservation_model.py b/xos/core/models/attic/reservation_model.py
new file mode 100644
index 0000000..e5e9cda
--- /dev/null
+++ b/xos/core/models/attic/reservation_model.py
@@ -0,0 +1,17 @@
+def __unicode__(self): return u'%s to %s' % (self.startTime, self.endTime)
+
+@property
+def endTime(self):
+ return self.startTime + datetime.timedelta(hours=self.duration)
+
+def can_update(self, user):
+ return user.can_update_slice(self.slice)
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = Reservation.objects.all()
+ else:
+ slice_ids = [s.id for s in Slice.select_by_user(user)]
+ qs = Reservation.objects.filter(id__in=slice_ids)
+ return qs
diff --git a/xos/core/models/attic/reservedresource_model.py b/xos/core/models/attic/reservedresource_model.py
new file mode 100644
index 0000000..d2caa15
--- /dev/null
+++ b/xos/core/models/attic/reservedresource_model.py
@@ -0,0 +1,16 @@
+class Meta(PlCoreBase.Meta):
+ verbose_name_plural = "Reserved Resources"
+
+def __unicode__(self): return u'%d %s on %s' % (self.quantity, self.resource, self.instance)
+
+def can_update(self, user):
+ return user.can_update(self.instance.slice)
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = ReservedResource.objects.all()
+ else:
+ instance_ids = [s.id for s in Instance.select_by_user(user)]
+ qs = ReservedResource.objects.filter(id__in=instance_ids)
+ return qs
diff --git a/xos/core/models/attic/role_model.py b/xos/core/models/attic/role_model.py
new file mode 100644
index 0000000..81bd86e
--- /dev/null
+++ b/xos/core/models/attic/role_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s:%s' % (self.content_type,self.role_type)
diff --git a/xos/core/models/attic/router_model.py b/xos/core/models/attic/router_model.py
new file mode 100644
index 0000000..a538cd4
--- /dev/null
+++ b/xos/core/models/attic/router_model.py
@@ -0,0 +1,5 @@
+def __unicode__(self): return u'%s' % (self.name)
+
+def can_update(self, user):
+ return user.can_update_slice(self.owner)
+
diff --git a/xos/core/models/attic/service_header.py b/xos/core/models/attic/service_header.py
new file mode 100644
index 0000000..04e7353
--- /dev/null
+++ b/xos/core/models/attic/service_header.py
@@ -0,0 +1,187 @@
+from __future__ import absolute_import
+
+from core.models.xos import XOS
+from core.models.plcorebase import *
+from django.core.validators import URLValidator
+import urlparse
+from operator import attrgetter
+import json
+from distutils.version import LooseVersion
+from django.core.validators import URLValidator
+from xos.exceptions import *
+from xos.config import Config
+
+
+COARSE_KIND = "coarse"
+
+def get_xos():
+ xos = XOS.objects.all()
+
+ if xos:
+ return xos[0]
+ else:
+ return None
+
+class AttributeMixin(object):
+ # helper for extracting things from a json-encoded
+ # service_specific_attribute
+
+ def get_attribute(self, name, default=None):
+ if self.service_specific_attribute:
+ attributes = json.loads(self.service_specific_attribute)
+ else:
+ attributes = {}
+ return attributes.get(name, default)
+
+ def set_attribute(self, name, value):
+ if self.service_specific_attribute:
+ attributes = json.loads(self.service_specific_attribute)
+ else:
+ attributes = {}
+ attributes[name] = value
+ self.service_specific_attribute = json.dumps(attributes)
+
+ def get_initial_attribute(self, name, default=None):
+ if self._initial["service_specific_attribute"]:
+ attributes = json.loads(
+ self._initial["service_specific_attribute"])
+ else:
+ attributes = {}
+ return attributes.get(name, default)
+
+ @classmethod
+ def get_default_attribute(cls, name):
+ for (attrname, default) in cls.simple_attributes:
+ if attrname == name:
+ return default
+ if hasattr(cls, "default_attributes"):
+ if name in cls.default_attributes:
+ return cls.default_attributes[name]
+
+ return None
+
+ @classmethod
+ def setup_simple_attributes(cls):
+ for (attrname, default) in cls.simple_attributes:
+ setattr(cls, attrname, property(lambda self, attrname=attrname, default=default: self.get_attribute(attrname, default),
+ lambda self, value, attrname=attrname: self.set_attribute(
+ attrname, value),
+ None,
+ attrname))
+
+
+class Scheduler(object):
+ # XOS Scheduler Abstract Base Class
+ # Used to implement schedulers that pick which node to put instances on
+
+ def __init__(self, slice):
+ self.slice = slice
+
+ def pick(self):
+ # this method should return a tuple (node, parent)
+ # node is the node to instantiate on
+ # parent is for container_vm instances only, and is the VM that will
+ # hold the container
+
+ raise Exception("Abstract Base")
+
+
+class LeastLoadedNodeScheduler(Scheduler):
+ # This scheduler always return the node with the fewest number of
+ # instances.
+
+ def __init__(self, slice, label=None):
+ super(LeastLoadedNodeScheduler, self).__init__(slice)
+ self.label = label
+
+ def pick(self):
+ from core.models import Node
+
+ # start with all nodes
+ nodes = Node.objects.all()
+
+ # if a label is set, then filter by label
+ if self.label:
+ nodes = nodes.filter(nodelabels__name=self.label)
+
+ # if slice.default_node is set, then filter by default_node
+ if self.slice.default_node:
+ nodes = nodes.filter(name = self.slice.default_node)
+
+ # convert to list
+ nodes = list(nodes)
+
+ # sort so that we pick the least-loaded node
+ nodes = sorted(nodes, key=lambda node: node.instances.all().count())
+
+ if not nodes:
+ raise Exception(
+ "LeastLoadedNodeScheduler: No suitable nodes to pick from")
+
+ # TODO: logic to filter nodes by which nodes are up, and which
+ # nodes the slice can instantiate on.
+# nodes = sorted(nodes, key=lambda node: node.instances.all().count())
+ return [nodes[0], None]
+
+
+class ContainerVmScheduler(Scheduler):
+ # This scheduler picks a VM in the slice with the fewest containers inside
+ # of it. If no VMs are suitable, then it creates a VM.
+
+ MAX_VM_PER_CONTAINER = 10
+
+ def __init__(self, slice):
+ super(ContainerVmScheduler, self).__init__(slice)
+
+ @property
+ def image(self):
+ from core.models import Image
+
+ # If slice has default_image set then use it
+ if self.slice.default_image:
+ return self.slice.default_image
+
+ raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
+
+ def make_new_instance(self):
+ from core.models import Instance, Flavor
+
+ flavors = Flavor.objects.filter(name="m1.small")
+ if not flavors:
+ raise XOSConfigurationError("No m1.small flavor")
+
+ (node, parent) = LeastLoadedNodeScheduler(self.slice).pick()
+
+ instance = Instance(slice=self.slice,
+ node=node,
+ image=self.image,
+ creator=self.slice.creator,
+ deployment=node.site_deployment.deployment,
+ flavor=flavors[0],
+ isolation="vm",
+ parent=parent)
+ instance.save()
+ # We rely on a special naming convention to identify the VMs that will
+ # hole containers.
+ instance.name = "%s-outer-%s" % (instance.slice.name, instance.id)
+ instance.save()
+ return instance
+
+ def pick(self):
+ from core.models import Instance, Flavor
+
+ for vm in self.slice.instances.filter(isolation="vm"):
+ avail_vms = []
+ if (vm.name.startswith("%s-outer-" % self.slice.name)):
+ container_count = Instance.objects.filter(parent=vm).count()
+ if (container_count < self.MAX_VM_PER_CONTAINER):
+ avail_vms.append((vm, container_count))
+ # sort by least containers-per-vm
+ avail_vms = sorted(avail_vms, key=lambda x: x[1])
+ print "XXX", avail_vms
+ if avail_vms:
+ instance = avail_vms[0][0]
+ return (instance.node, instance)
+
+ instance = self.make_new_instance()
+ return (instance.node, instance)
diff --git a/xos/core/models/attic/service_model.py b/xos/core/models/attic/service_model.py
new file mode 100644
index 0000000..1798018
--- /dev/null
+++ b/xos/core/models/attic/service_model.py
@@ -0,0 +1,196 @@
+KIND="generic"
+
+def __init__(self, *args, **kwargs):
+ # for subclasses, set the default kind appropriately
+ self._meta.get_field("kind").default = self.KIND
+ super(Service, self).__init__(*args, **kwargs)
+
+@classmethod
+def get_service_objects(cls):
+ return cls.objects.filter(kind=cls.KIND)
+
+@classmethod
+def get_deleted_service_objects(cls):
+ return cls.deleted_objects.filter(kind=cls.KIND)
+
+@classmethod
+def get_service_objects_by_user(cls, user):
+ return cls.select_by_user(user).filter(kind=cls.KIND)
+
+@classmethod
+def select_by_user(cls, user):
+ if user.is_admin:
+ return cls.objects.all()
+ else:
+ from core.models.serviceprivilege import ServicePrivilege
+ service_ids = [
+ sp.slice.id for sp in ServicePrivilege.objects.filter(user=user)]
+ return cls.objects.filter(id__in=service_ids)
+
+@property
+def serviceattribute_dict(self):
+ attrs = {}
+ for attr in self.serviceattributes.all():
+ attrs[attr.name] = attr.value
+ return attrs
+
+def __unicode__(self): return u'%s' % (self.name)
+
+def can_update(self, user):
+ return user.can_update_service(self, allow=['admin'])
+
+def get_scalable_nodes(self, slice, max_per_node=None, exclusive_slices=[]):
+ """
+ Get a list of nodes that can be used to scale up a slice.
+
+ slice - slice to scale up
+ max_per_node - maximum numbers of instances that 'slice' can have on a single node
+ exclusive_slices - list of slices that must have no nodes in common with 'slice'.
+ """
+
+ # late import to get around order-of-imports constraint in __init__.py
+ from core.models import Node, Instance
+
+ nodes = list(Node.objects.all())
+
+ conflicting_instances = Instance.objects.filter(
+ slice__in=exclusive_slices)
+ conflicting_nodes = Node.objects.filter(
+ instances__in=conflicting_instances)
+
+ nodes = [x for x in nodes if x not in conflicting_nodes]
+
+ # If max_per_node is set, then limit the number of instances this slice
+ # can have on a single node.
+ if max_per_node:
+ acceptable_nodes = []
+ for node in nodes:
+ existing_count = node.instances.filter(slice=slice).count()
+ if existing_count < max_per_node:
+ acceptable_nodes.append(node)
+ nodes = acceptable_nodes
+
+ return nodes
+
+def pick_node(self, slice, max_per_node=None, exclusive_slices=[]):
+ # Pick the best node to scale up a slice.
+
+ nodes = self.get_scalable_nodes(slice, max_per_node, exclusive_slices)
+ nodes = sorted(nodes, key=lambda node: node.instances.all().count())
+ if not nodes:
+ return None
+ return nodes[0]
+
+def adjust_scale(self, slice_hint, scale, max_per_node=None, exclusive_slices=[]):
+ # late import to get around order-of-imports constraint in __init__.py
+ from core.models import Instance
+
+ slices = [x for x in self.slices.all() if slice_hint in x.name]
+ for slice in slices:
+ while slice.instances.all().count() > scale:
+ s = slice.instances.all()[0]
+ # print "drop instance", s
+ s.delete()
+
+ while slice.instances.all().count() < scale:
+ node = self.pick_node(slice, max_per_node, exclusive_slices)
+ if not node:
+ # no more available nodes
+ break
+
+ image = slice.default_image
+ if not image:
+ raise XOSConfigurationError(
+ "No default_image for slice %s" % slice.name)
+
+ flavor = slice.default_flavor
+ if not flavor:
+ raise XOSConfigurationError(
+ "No default_flavor for slice %s" % slice.name)
+
+ s = Instance(slice=slice,
+ node=node,
+ creator=slice.creator,
+ image=image,
+ flavor=flavor,
+ deployment=node.site_deployment.deployment)
+ s.save()
+
+ # print "add instance", s
+
+def get_vtn_src_nets(self):
+ nets = []
+ for slice in self.slices.all():
+ for ns in slice.networkslices.all():
+ if not ns.network:
+ continue
+# if ns.network.template.access in ["direct", "indirect"]:
+# # skip access networks; we want to use the private network
+# continue
+ if "management" in ns.network.name:
+ # don't try to connect the management network to anything
+ continue
+ if ns.network.name in ["wan_network", "lan_network"]:
+ # we don't want to attach to the vCPE's lan or wan network
+ # we only want to attach to its private network
+ # TODO: fix hard-coding of network name
+ continue
+ for cn in ns.network.controllernetworks.all():
+ if cn.net_id:
+ net = {"name": ns.network.name, "net_id": cn.net_id}
+ nets.append(net)
+ return nets
+
+def get_vtn_nets(self):
+ nets = []
+ for slice in self.slices.all():
+ for ns in slice.networkslices.all():
+ if not ns.network:
+ continue
+ if ns.network.template.access not in ["direct", "indirect"]:
+ # skip anything that's not an access network
+ continue
+ for cn in ns.network.controllernetworks.all():
+ if cn.net_id:
+ net = {"name": ns.network.name, "net_id": cn.net_id}
+ nets.append(net)
+ return nets
+
+def get_vtn_dependencies_nets(self):
+ provider_nets = []
+ for tenant in self.subscribed_tenants.all():
+ if tenant.provider_service:
+ for net in tenant.provider_service.get_vtn_nets():
+ if not net in provider_nets:
+ net["bidirectional"] = tenant.connect_method!="private-unidirectional"
+ provider_nets.append(net)
+ return provider_nets
+
+def get_vtn_dependencies_ids(self):
+ return [x["net_id"] for x in self.get_vtn_dependencies_nets()]
+
+def get_vtn_dependencies_names(self):
+ return [x["name"] + "_" + x["net_id"] for x in self.get_vtn_dependencies_nets()]
+
+def get_vtn_src_ids(self):
+ return [x["net_id"] for x in self.get_vtn_src_nets()]
+
+def get_vtn_src_names(self):
+ return [x["name"] + "_" + x["net_id"] for x in self.get_vtn_src_nets()]
+
+def get_composable_networks(self):
+ SUPPORTED_VTN_SERVCOMP_KINDS = ['VSG','PRIVATE']
+
+ nets = []
+ for slice in self.slices.all():
+ for net in slice.networks.all():
+ if (net.template.vtn_kind not in SUPPORTED_VTN_SERVCOMP_KINDS) or (net.owner != slice):
+ continue
+
+ if not net.controllernetworks.exists():
+ continue
+ nets.append(net)
+ return nets
+
+
+
diff --git a/xos/core/models/attic/serviceclass_model.py b/xos/core/models/attic/serviceclass_model.py
new file mode 100644
index 0000000..ebdfdfe
--- /dev/null
+++ b/xos/core/models/attic/serviceclass_model.py
@@ -0,0 +1,8 @@
+class Meta(PlCoreBase.Meta):
+ verbose_name_plural = "Service classes"
+
+def __unicode__(self): return u'%s' % (self.name)
+
+def save_by_user(self, user, *args, **kwds):
+ if self.can_update(user):
+ super(ServiceClass, self).save(*args, **kwds)
diff --git a/xos/core/models/attic/servicedependency_model.py b/xos/core/models/attic/servicedependency_model.py
new file mode 100644
index 0000000..dce32e7
--- /dev/null
+++ b/xos/core/models/attic/servicedependency_model.py
@@ -0,0 +1,11 @@
+KIND="coarse"
+
+def save(self, *args, **kwargs):
+ if (not self.subscriber_service):
+ raise XOSValidationError("subscriber_service cannot be null")
+ if (self.subscriber_tenant or self.subscriber_user):
+ raise XOSValidationError(
+ "subscriber_tenant and subscriber_user must be null")
+
+ super(ServiceDependency, self).save()
+
diff --git a/xos/core/models/attic/serviceprivilege_model.py b/xos/core/models/attic/serviceprivilege_model.py
new file mode 100644
index 0000000..64ca985
--- /dev/null
+++ b/xos/core/models/attic/serviceprivilege_model.py
@@ -0,0 +1,28 @@
+class Meta:
+ unique_together = ('user', 'service', 'role')
+
+def __unicode__(self): return u'%s %s %s' % (
+ self.service, self.user, self.role)
+
+def can_update(self, user):
+ if not self.service.enabled:
+ raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
+ return self.service.can_update(user)
+
+def save(self, *args, **kwds):
+ if not self.service.enabled:
+ raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
+ super(ServicePrivilege, self).save(*args, **kwds)
+
+def delete(self, *args, **kwds):
+ if not self.service.enabled:
+ raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
+ super(ServicePrivilege, self).delete(*args, **kwds)
+
+@classmethod
+def select_by_user(cls, user):
+ if user.is_admin:
+ qs = cls.objects.all()
+ else:
+ qs = cls.objects.filter(user=user)
+ return qs
diff --git a/xos/core/models/attic/serviceresource_model.py b/xos/core/models/attic/serviceresource_model.py
new file mode 100644
index 0000000..3fd623e
--- /dev/null
+++ b/xos/core/models/attic/serviceresource_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/attic/servicerole_model.py b/xos/core/models/attic/servicerole_model.py
new file mode 100644
index 0000000..b35a54b
--- /dev/null
+++ b/xos/core/models/attic/servicerole_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.role)
diff --git a/xos/core/models/attic/singletonmodel.py b/xos/core/models/attic/singletonmodel.py
new file mode 100644
index 0000000..4ab6f6e
--- /dev/null
+++ b/xos/core/models/attic/singletonmodel.py
@@ -0,0 +1,16 @@
+from django.db import models
+
+class SingletonModel(models.Model):
+ class Meta:
+ abstract = True
+
+ def save(self, *args, **kwargs):
+ self.__class__.objects.exclude(id=self.id).delete()
+ super(SingletonModel, self).save(*args, **kwargs)
+
+ @classmethod
+ def load(cls):
+ try:
+ return cls.objects.get()
+ except cls.DoesNotExist:
+ return cls()
diff --git a/xos/core/models/attic/site_model.py b/xos/core/models/attic/site_model.py
new file mode 100644
index 0000000..a256049
--- /dev/null
+++ b/xos/core/models/attic/site_model.py
@@ -0,0 +1,9 @@
+objects = ControllerManager()
+deleted_objects = ControllerDeletionManager()
+
+def __unicode__(self): return u'%s' % (self.name)
+
+def can_update(self, user):
+ return user.can_update_site(self, allow=['pi'])
+
+
diff --git a/xos/core/models/attic/sitecredential_model.py b/xos/core/models/attic/sitecredential_model.py
new file mode 100644
index 0000000..df937ad
--- /dev/null
+++ b/xos/core/models/attic/sitecredential_model.py
@@ -0,0 +1,4 @@
+def __unicode__(self):
+ return self.name
+
+
diff --git a/xos/core/models/attic/sitedeployment_model.py b/xos/core/models/attic/sitedeployment_model.py
new file mode 100644
index 0000000..a4383f3
--- /dev/null
+++ b/xos/core/models/attic/sitedeployment_model.py
@@ -0,0 +1,7 @@
+objects = ControllerLinkManager()
+deleted_objects = ControllerLinkDeletionManager()
+
+class Meta:
+ unique_together = ('site', 'deployment', 'controller')
+
+def __unicode__(self): return u'%s %s' % (self.deployment, self.site)
diff --git a/xos/core/models/attic/siteprivilege_model.py b/xos/core/models/attic/siteprivilege_model.py
new file mode 100644
index 0000000..fde823f
--- /dev/null
+++ b/xos/core/models/attic/siteprivilege_model.py
@@ -0,0 +1,18 @@
+def __unicode__(self): return u'%s %s %s' % (self.site, self.user, self.role)
+
+def can_update(self, user):
+ return user.can_update_site(self, allow=['pi'])
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = SitePrivilege.objects.all()
+ else:
+ sp_ids = [sp.id for sp in SitePrivilege.objects.filter(user=user)]
+ qs = SitePrivilege.objects.filter(id__in=sp_ids)
+ return qs
+
+def save(self, *args, **kwds):
+ if not self.user.is_active:
+ raise PermissionDenied, "Cannot modify role(s) of a disabled user"
+ super(SitePrivilege, self).save(*args, **kwds)
diff --git a/xos/core/models/attic/siterole_model.py b/xos/core/models/attic/siterole_model.py
new file mode 100644
index 0000000..c5ebd53
--- /dev/null
+++ b/xos/core/models/attic/siterole_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.role)
diff --git a/xos/core/models/attic/slice_model.py b/xos/core/models/attic/slice_model.py
new file mode 100644
index 0000000..b9aba1b
--- /dev/null
+++ b/xos/core/models/attic/slice_model.py
@@ -0,0 +1,81 @@
+NETWORK_CHOICES = ((None, 'Default'), ('host', 'Host'), ('bridged', 'Bridged'), ('noauto', 'No Automatic Networks'))
+
+def __unicode__(self): return u'%s' % (self.name)
+
+@property
+def slicename(self):
+ return "%s_%s" % (self.site.login_base, self.name)
+
+def save(self, *args, **kwds):
+ site = Site.objects.get(id=self.site.id)
+ # allow preexisting slices to keep their original name for now
+ if not self.id and not self.name.startswith(site.login_base):
+ raise XOSValidationError('slice name must begin with %s' % site.login_base)
+
+ if self.name == site.login_base+"_":
+ raise XOSValidationError('slice name is too short')
+
+ if " " in self.name:
+ raise XOSValidationError('slice name must not contain spaces')
+
+ # set creator on first save
+ if not self.creator and hasattr(self, 'caller'):
+ self.creator = self.caller
+
+ # only admins change a slice's creator
+ if 'creator' in self.changed_fields and \
+ (not hasattr(self, 'caller') or not self.caller.is_admin):
+
+ if (self._initial["creator"]==None) and (self.creator==getattr(self,"caller",None)):
+ # it's okay if the creator is being set by the caller to
+ # himeself on a new slice object.
+ pass
+ else:
+ raise PermissionDenied("Insufficient privileges to change slice creator")
+
+ if not self.creator:
+ raise XOSValidationError('slice has no creator')
+
+ if self.network=="Private Only":
+ # "Private Only" was the default from the old Tenant View
+ self.network=None
+ self.enforce_choices(self.network, self.NETWORK_CHOICES)
+
+ super(Slice, self).save(*args, **kwds)
+
+def can_update(self, user):
+ return user.can_update_slice(self)
+
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = Slice.objects.all()
+ else:
+ from core.models.sliceprivilege import SlicePrivilege
+ from core.models.siteprivilege import SitePrivilege
+ # users can see slices they belong to
+ slice_ids = [sp.slice.id for sp in SlicePrivilege.objects.filter(user=user)]
+ # pis and admins can see slices at their sites
+ sites = [sp.site for sp in SitePrivilege.objects.filter(user=user)\
+ if (sp.role.role == 'pi') or (sp.role.role == 'admin')]
+ slice_ids.extend([s.id for s in Slice.objects.filter(site__in=sites)])
+ qs = Slice.objects.filter(id__in=slice_ids)
+ return qs
+
+"""
+def delete(self, *args, **kwds):
+ # delete networks associated with this slice
+ from core.models.network import Network
+ nets = Network.objects.filter(slices=self)
+ nets.delete()
+ # delete slice controllers
+ slice_controllers = ControllerSlice.objects.filter(slice=self)
+ slice_controllers.delete()
+ # delete slice privilege
+ slice_privileges = SlicePrivilege.objects.filter(slice=self)
+ slice_privileges.delete()
+ # continue with normal delete
+ super(Slice, self).delete(*args, **kwds)
+"""
+
diff --git a/xos/core/models/attic/slicecredential_model.py b/xos/core/models/attic/slicecredential_model.py
new file mode 100644
index 0000000..f876fd6
--- /dev/null
+++ b/xos/core/models/attic/slicecredential_model.py
@@ -0,0 +1,3 @@
+def __unicode__(self):
+ return self.name
+
diff --git a/xos/core/models/attic/sliceprivilege_model.py b/xos/core/models/attic/sliceprivilege_model.py
new file mode 100644
index 0000000..c7e0bfb
--- /dev/null
+++ b/xos/core/models/attic/sliceprivilege_model.py
@@ -0,0 +1,31 @@
+class Meta:
+ unique_together = ('user', 'slice', 'role')
+
+def __unicode__(self): return u'%s %s %s' % (self.slice, self.user, self.role)
+
+def save(self, *args, **kwds):
+ super(SlicePrivilege, self).save(*args, **kwds)
+
+def can_update(self, user):
+ return user.can_update_slice(self.slice)
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = SlicePrivilege.objects.all()
+ else:
+ # You can see your own SlicePrivileges
+ sp_ids = [sp.id for sp in SlicePrivilege.objects.filter(user=user)]
+
+ from core.models.siteprivilege import SitePrivilege
+ # A site pi or site admin can see the SlicePrivileges for all slices in his Site
+ for priv in SitePrivilege.objects.filter(user=user):
+ if priv.role.role in ['pi', 'admin']:
+ sp_ids.extend( [sp.id for sp in SlicePrivilege.objects.filter(slice__site = priv.site)] )
+
+ # A slice admin can see the SlicePrivileges for his Slice
+ for priv in SlicePrivilege.objects.filter(user=user, role__role="admin"):
+ sp_ids.extend( [sp.id for sp in SlicePrivilege.objects.filter(slice=priv.slice)] )
+
+ qs = SlicePrivilege.objects.filter(id__in=sp_ids)
+ return qs
diff --git a/xos/core/models/attic/slicerole_model.py b/xos/core/models/attic/slicerole_model.py
new file mode 100644
index 0000000..c5ebd53
--- /dev/null
+++ b/xos/core/models/attic/slicerole_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.role)
diff --git a/xos/core/models/attic/slicetag_model.py b/xos/core/models/attic/slicetag_model.py
new file mode 100644
index 0000000..87f00e4
--- /dev/null
+++ b/xos/core/models/attic/slicetag_model.py
@@ -0,0 +1,11 @@
+def can_update(self, user):
+ return user.can_update_slice(self.slice)
+
+@staticmethod
+def select_by_user(user):
+ if user.is_admin:
+ qs = SliceTag.objects.all()
+ else:
+ slices = Slice.select_by_user(user)
+ qs = SliceTag.objects.filter(slice__in=slices)
+ return qs
diff --git a/xos/core/models/attic/tag_model.py b/xos/core/models/attic/tag_model.py
new file mode 100644
index 0000000..c6437e8
--- /dev/null
+++ b/xos/core/models/attic/tag_model.py
@@ -0,0 +1,15 @@
+content_object = GenericForeignKey('content_type', 'object_id') # Not generated by xproto
+
+def __unicode__(self):
+ return self.name
+
+def can_update(self, user):
+ return user.can_update_root()
+
+@classmethod
+def select_by_content_object(cls, obj):
+ return cls.objects.filter(content_type=ContentType.objects.get_for_model(obj), object_id=obj.id)
+
+@staticmethod
+def select_by_user(user):
+ return Tag.objects.all()
diff --git a/xos/core/models/attic/tenant_model.py b/xos/core/models/attic/tenant_model.py
new file mode 100644
index 0000000..6a2e074
--- /dev/null
+++ b/xos/core/models/attic/tenant_model.py
@@ -0,0 +1,62 @@
+KIND="generic"
+
+def __init__(self, *args, **kwargs):
+ # for subclasses, set the default kind appropriately
+ self._meta.get_field("kind").default = self.KIND
+ super(Tenant, self).__init__(*args, **kwargs)
+
+def __unicode__(self):
+ return u"%s-tenant-%s" % (str(self.kind), str(self.id))
+
+@classmethod
+def get_tenant_objects(cls):
+ return cls.objects.filter(kind=cls.KIND)
+
+@classmethod
+def get_tenant_objects_by_user(cls, user):
+ return cls.select_by_user(user).filter(kind=cls.KIND)
+
+@classmethod
+def get_deleted_tenant_objects(cls):
+ return cls.deleted_objects.filter(kind=cls.KIND)
+
+@property
+def tenantattribute_dict(self):
+ attrs = {}
+ for attr in self.tenantattributes.all():
+ attrs[attr.name] = attr.value
+ return attrs
+
+# helper function to be used in subclasses that want to ensure
+# service_specific_id is unique
+def validate_unique_service_specific_id(self):
+ if self.pk is None:
+ if self.service_specific_id is None:
+ raise XOSMissingField("subscriber_specific_id is None, and it's a required field", fields={
+ "service_specific_id": "cannot be none"})
+
+ conflicts = self.get_tenant_objects().filter(
+ service_specific_id=self.service_specific_id)
+ if conflicts:
+ raise XOSDuplicateKey("service_specific_id %s already exists" % self.service_specific_id, fields={
+ "service_specific_id": "duplicate key"})
+
+def save(self, *args, **kwargs):
+ subCount = sum([1 for e in [self.subscriber_service, self.subscriber_tenant,
+ self.subscriber_user, self.subscriber_root] if e is not None])
+ if (subCount > 1):
+ raise XOSConflictingField(
+ "Only one of subscriber_service, subscriber_tenant, subscriber_user, subscriber_root should be set")
+
+ super(Tenant, self).save(*args, **kwargs)
+
+def get_subscribed_tenants(self, tenant_class):
+ ids = self.subscribed_tenants.filter(kind=tenant_class.KIND)
+ return tenant_class.objects.filter(id__in=ids)
+
+def get_newest_subscribed_tenant(self, kind):
+ st = list(self.get_subscribed_tenants(kind))
+ if not st:
+ return None
+ return sorted(st, key=attrgetter('id'))[0]
+
diff --git a/xos/core/models/attic/tenant_top.py b/xos/core/models/attic/tenant_top.py
new file mode 100644
index 0000000..474a085
--- /dev/null
+++ b/xos/core/models/attic/tenant_top.py
@@ -0,0 +1 @@
+from service_header import *
diff --git a/xos/core/models/attic/tenantattribute_model.py b/xos/core/models/attic/tenantattribute_model.py
new file mode 100644
index 0000000..ec771ed
--- /dev/null
+++ b/xos/core/models/attic/tenantattribute_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s-%s' % (self.name, self.id)
diff --git a/xos/core/models/attic/tenantprivilege_model.py b/xos/core/models/attic/tenantprivilege_model.py
new file mode 100644
index 0000000..165eb89
--- /dev/null
+++ b/xos/core/models/attic/tenantprivilege_model.py
@@ -0,0 +1,25 @@
+def __unicode__(self): return u'%s %s %s' % (
+ self.tenant, self.user, self.role)
+
+def save(self, *args, **kwds):
+ if not self.user.is_active:
+ raise PermissionDenied, "Cannot modify role(s) of a disabled user"
+ super(TenantPrivilege, self).save(*args, **kwds)
+
+def can_update(self, user):
+ return user.can_update_tenant_privilege(self)
+
+@classmethod
+def select_by_user(cls, user):
+ if user.is_admin:
+ return cls.objects.all()
+ else:
+ # User can see his own privilege
+ trp_ids = [trp.id for trp in cls.objects.filter(user=user)]
+
+ # A tenant admin can see the TenantPrivileges for their Tenants
+ for priv in cls.objects.filter(user=user, role__role="admin"):
+ trp_ids.extend(
+ [trp.id for trp in cls.objects.filter(tenant=priv.tenant)])
+
+ return cls.objects.filter(id__in=trp_ids)
diff --git a/xos/core/models/attic/tenantrole_model.py b/xos/core/models/attic/tenantrole_model.py
new file mode 100644
index 0000000..b35a54b
--- /dev/null
+++ b/xos/core/models/attic/tenantrole_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.role)
diff --git a/xos/core/models/attic/tenantroot_model.py b/xos/core/models/attic/tenantroot_model.py
new file mode 100644
index 0000000..b9501af
--- /dev/null
+++ b/xos/core/models/attic/tenantroot_model.py
@@ -0,0 +1,60 @@
+KIND="generic"
+
+def __init__(self, *args, **kwargs):
+ # for subclasses, set the default kind appropriately
+ self._meta.get_field("kind").default = self.KIND
+ super(TenantRoot, self).__init__(*args, **kwargs)
+
+def __unicode__(self):
+ if not self.name:
+ return u"%s-tenant_root-#%s" % (str(self.kind), str(self.id))
+ else:
+ return self.name
+
+def can_update(self, user):
+ return user.can_update_tenant_root(self, allow=['admin'])
+
+def get_subscribed_tenants(self, tenant_class):
+ ids = self.subscribed_tenants.filter(kind=tenant_class.KIND)
+ return tenant_class.objects.filter(id__in=ids)
+
+def get_newest_subscribed_tenant(self, kind):
+ st = list(self.get_subscribed_tenants(kind))
+ if not st:
+ return None
+ return sorted(st, key=attrgetter('id'))[0]
+
+@classmethod
+def get_tenant_objects(cls):
+ return cls.objects.filter(kind=cls.KIND)
+
+@classmethod
+def get_tenant_objects_by_user(cls, user):
+ return cls.select_by_user(user).filter(kind=cls.KIND)
+
+@classmethod
+def select_by_user(cls, user):
+ if user.is_admin:
+ return cls.objects.all()
+ else:
+ from core.models.tenantrootprivilege import TenantRootPrivilege
+ tr_ids = [
+ trp.tenant_root.id for trp in TenantRootPrivilege.objects.filter(user=user)]
+ return cls.objects.filter(id__in=tr_ids)
+
+# helper function to be used in subclasses that want to ensure
+# service_specific_id is unique
+def validate_unique_service_specific_id(self, none_okay=False):
+ if not none_okay and (self.service_specific_id is None):
+ raise XOSMissingField("subscriber_specific_id is None, and it's a required field", fields={
+ "service_specific_id": "cannot be none"})
+
+ if self.service_specific_id:
+ conflicts = self.get_tenant_objects().filter(
+ service_specific_id=self.service_specific_id)
+ if self.pk:
+ conflicts = conflicts.exclude(pk=self.pk)
+ if conflicts:
+ raise XOSDuplicateKey("service_specific_id %s already exists" % self.service_specific_id, fields={
+ "service_specific_id": "duplicate key"})
+
diff --git a/xos/core/models/attic/tenantrootprivilege_model.py b/xos/core/models/attic/tenantrootprivilege_model.py
new file mode 100644
index 0000000..158f1c0
--- /dev/null
+++ b/xos/core/models/attic/tenantrootprivilege_model.py
@@ -0,0 +1,29 @@
+class Meta:
+ unique_together = ('user', 'tenant_root', 'role')
+
+def __unicode__(self): return u'%s %s %s' % (
+ self.tenant_root, self.user, self.role)
+
+def save(self, *args, **kwds):
+ if not self.user.is_active:
+ raise PermissionDenied, "Cannot modify role(s) of a disabled user"
+ super(TenantRootPrivilege, self).save(*args, **kwds)
+
+def can_update(self, user):
+ return user.can_update_tenant_root_privilege(self)
+
+@classmethod
+def select_by_user(cls, user):
+ if user.is_admin:
+ return cls.objects.all()
+ else:
+ # User can see his own privilege
+ trp_ids = [trp.id for trp in cls.objects.filter(user=user)]
+
+ # A slice admin can see the SlicePrivileges for his Slice
+ for priv in cls.objects.filter(user=user, role__role="admin"):
+ trp_ids.extend(
+ [trp.id for trp in cls.objects.filter(tenant_root=priv.tenant_root)])
+
+ return cls.objects.filter(id__in=trp_ids)
+
diff --git a/xos/core/models/attic/tenantrootrole_model.py b/xos/core/models/attic/tenantrootrole_model.py
new file mode 100644
index 0000000..b35a54b
--- /dev/null
+++ b/xos/core/models/attic/tenantrootrole_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.role)
diff --git a/xos/core/models/attic/tenantwithcontainer_model.py b/xos/core/models/attic/tenantwithcontainer_model.py
new file mode 100644
index 0000000..7b11323
--- /dev/null
+++ b/xos/core/models/attic/tenantwithcontainer_model.py
@@ -0,0 +1,141 @@
+def __init__(self, *args, **kwargs):
+ super(TenantWithContainer, self).__init__(*args, **kwargs)
+
+ # vSG service relies on knowing when instance id has changed
+ self.orig_instance_id = self.get_attribute("instance_id")
+
+# vSG service relies on instance_id attribute
+def get_attribute(self, name, default=None):
+ if name=="instance_id":
+ if self.instance:
+ return self.instance.id
+ else:
+ return None
+ else:
+ return super(TenantWithContainer, self).get_attribute(name, default)
+
+# Services may wish to override the image() function to return different
+# images based on criteria in the tenant object. For example,
+# if (self.has_feature_A):
+# return Instance.object.get(name="image_with_feature_a")
+# elif (self.has_feature_B):
+# return Instance.object.get(name="image_with_feature_b")
+# else:
+# return super(MyTenantClass,self).image()
+
+@property
+def image(self):
+ from core.models import Image
+ # Implement the logic here to pick the image that should be used when
+ # instantiating the VM that will hold the container.
+
+ slice = self.provider_service.slices.all()
+ if not slice:
+ raise XOSProgrammingError("provider service has no slice")
+ slice = slice[0]
+
+ # If slice has default_image set then use it
+ if slice.default_image:
+ return slice.default_image
+
+ raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
+
+def save_instance(self, instance):
+ # Override this function to do custom pre-save or post-save processing,
+ # such as creating ports for containers.
+ instance.save()
+
+def pick_least_loaded_instance_in_slice(self, slices, image):
+ for slice in slices:
+ if slice.instances.all().count() > 0:
+ for instance in slice.instances.all():
+ if instance.image != image:
+ continue
+ # Pick the first instance that has lesser than 5 tenants
+ if self.count_of_tenants_of_an_instance(instance) < 5:
+ return instance
+ return None
+
+# TODO: Ideally the tenant count for an instance should be maintained using a
+# many-to-one relationship attribute, however this model being proxy, it does
+# not permit any new attributes to be defined. Find if any better solutions
+def count_of_tenants_of_an_instance(self, instance):
+ tenant_count = 0
+ for tenant in self.get_tenant_objects().all():
+ if tenant.get_attribute("instance_id", None) == instance.id:
+ tenant_count += 1
+ return tenant_count
+
+def manage_container(self):
+ from core.models import Instance, Flavor
+
+ if self.deleted:
+ return
+
+ if (self.instance is not None) and (self.instance.image != self.image):
+ self.instance.delete()
+ self.instance = None
+
+ if self.instance is None:
+ if not self.provider_service.slices.count():
+ raise XOSConfigurationError("The service has no slices")
+
+ new_instance_created = False
+ instance = None
+ if self.get_attribute("use_same_instance_for_multiple_tenants", default=False):
+ # Find if any existing instances can be used for this tenant
+ slices = self.provider_service.slices.all()
+ instance = self.pick_least_loaded_instance_in_slice(slices, self.image)
+
+ if not instance:
+ slice = self.provider_service.slices.all()[0]
+
+ flavor = slice.default_flavor
+ if not flavor:
+ flavors = Flavor.objects.filter(name="m1.small")
+ if not flavors:
+ raise XOSConfigurationError("No m1.small flavor")
+ flavor = flavors[0]
+
+ if slice.default_isolation == "container_vm":
+ (node, parent) = ContainerVmScheduler(slice).pick()
+ else:
+ (node, parent) = LeastLoadedNodeScheduler(slice).pick()
+
+ instance = Instance(slice=slice,
+ node=node,
+ image=self.image,
+ creator=self.creator,
+ deployment=node.site_deployment.deployment,
+ flavor=flavor,
+ isolation=slice.default_isolation,
+ parent=parent)
+ self.save_instance(instance)
+ new_instance_created = True
+
+ try:
+ self.instance = instance
+ super(TenantWithContainer, self).save()
+ except:
+ if new_instance_created:
+ instance.delete()
+ raise
+
+def cleanup_container(self):
+ if self.instance:
+ if self.get_attribute("use_same_instance_for_multiple_tenants", default=False):
+ # Delete the instance only if this is last tenant in that
+ # instance
+ tenant_count = self.count_of_tenants_of_an_instance(
+ self.instance)
+ if tenant_count == 0:
+ self.instance.delete()
+ else:
+ self.instance.delete()
+ self.instance = None
+
+def save(self, *args, **kwargs):
+ if (not self.creator) and (hasattr(self, "caller")) and (self.caller):
+ self.creator = self.caller
+ super(TenantWithContainer, self).save(*args, **kwargs)
+
diff --git a/xos/core/models/attic/usableobject_model.py b/xos/core/models/attic/usableobject_model.py
new file mode 100644
index 0000000..3fd623e
--- /dev/null
+++ b/xos/core/models/attic/usableobject_model.py
@@ -0,0 +1 @@
+def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/attic/usercredential_model.py b/xos/core/models/attic/usercredential_model.py
new file mode 100644
index 0000000..e6feca2
--- /dev/null
+++ b/xos/core/models/attic/usercredential_model.py
@@ -0,0 +1,3 @@
+
+def __unicode__(self):
+ return self.name
diff --git a/xos/core/models/attic/xos_model.py b/xos/core/models/attic/xos_model.py
new file mode 100644
index 0000000..12b5979
--- /dev/null
+++ b/xos/core/models/attic/xos_model.py
@@ -0,0 +1,22 @@
+def __unicode__(self): return u'%s' % (self.name)
+
+def __init__(self, *args, **kwargs):
+ super(XOS, self).__init__(*args, **kwargs)
+
+def save(self, *args, **kwds):
+ super(XOS, self).save(*args, **kwds)
+
+# def can_update(self, user):
+# return user.can_update_site(self.site, allow=['tech'])
+
+def rebuild(self, services=[]):
+ # If `services` is empty, then only rebuild the UI
+ # Otherwise, only rebuild the services listed in `services`
+ with transaction.atomic():
+ for loadable_module in self.loadable_modules.all():
+ if (services) and (loadable_module.name not in services):
+ continue
+ for lmr in loadable_module.loadable_module_resources.all():
+ lmr.save()
+ loadable_module.save()
+ self.save()
diff --git a/xos/core/models/attic/xoscomponentlink_model.py b/xos/core/models/attic/xoscomponentlink_model.py
new file mode 100644
index 0000000..413ce07
--- /dev/null
+++ b/xos/core/models/attic/xoscomponentlink_model.py
@@ -0,0 +1,7 @@
+def save(self, *args, **kwds):
+ # If this is a new object, then check to make sure it doesn't already exist
+ if not self.pk:
+ existing = XOSComponentLink.objects.filter(container=self.container, alias=self.alias)
+ if len(existing) > 0:
+ raise XOSValidationError('XOSComponentLink for %s:%s already defined' % (self.container, self.alias))
+ super(XOSComponentLink, self).save(*args, **kwds)
diff --git a/xos/core/models/attic/xoscomponentvolume_model.py b/xos/core/models/attic/xoscomponentvolume_model.py
new file mode 100644
index 0000000..a2ae229
--- /dev/null
+++ b/xos/core/models/attic/xoscomponentvolume_model.py
@@ -0,0 +1,8 @@
+def save(self, *args, **kwds):
+ # If this is a new object, then check to make sure it doesn't already exist
+ if not self.pk:
+ existing = XOSComponentVolume.objects.filter(container_path=self.container_path, host_path=self.host_path)
+ if len(existing) > 0:
+ raise XOSValidationError('XOSComponentVolume for %s:%s already defined' % (self.container_path, self.host_path))
+ super(XOSComponentVolume, self).save(*args, **kwds)
+
diff --git a/xos/core/models/attic/xoscomponentvolumecontainer_model.py b/xos/core/models/attic/xoscomponentvolumecontainer_model.py
new file mode 100644
index 0000000..fda0b03
--- /dev/null
+++ b/xos/core/models/attic/xoscomponentvolumecontainer_model.py
@@ -0,0 +1,8 @@
+def save(self, *args, **kwds):
+ # If this is a new object, then check to make sure it doesn't already exist
+ if not self.pk:
+ existing = XOSComponentVolumeContainer.objects.filter(name=self.name)
+ if len(existing) > 0:
+ raise XOSValidationError('XOSComponentVolumeContainer for %s:%s already defined' % (self.container_path, self.host_path))
+ super(XOSComponentVolumeContainer, self).save(*args, **kwds)
+
diff --git a/xos/core/models/attic/xosguiextension_model.py b/xos/core/models/attic/xosguiextension_model.py
new file mode 100644
index 0000000..dbbad60
--- /dev/null
+++ b/xos/core/models/attic/xosguiextension_model.py
@@ -0,0 +1,4 @@
+"""Persist GUI Extension"""
+class Meta:
+ app_label = "core"
+
diff --git a/xos/core/models/attic/xosvolume_model.py b/xos/core/models/attic/xosvolume_model.py
new file mode 100644
index 0000000..47c0c1b
--- /dev/null
+++ b/xos/core/models/attic/xosvolume_model.py
@@ -0,0 +1,11 @@
+def __unicode__(self): return u'%s' % (self.container_path)
+
+def save(self, *args, **kwargs):
+ super(XOSVolume, self).save(*args, **kwargs)
+
+ # This is necessary, as the XOS syncstep handles rerunning the docker-
+ # compose.
+ # TODO: Update onboarding synchronizer and replace this with watcher functionality
+ if self.xos:
+ # force XOS to rebuild
+ self.xos.save(update_fields=["updated"])
diff --git a/xos/core/models/billing.py b/xos/core/models/billing.py
deleted file mode 100644
index 083149a..0000000
--- a/xos/core/models/billing.py
+++ /dev/null
@@ -1,84 +0,0 @@
-import datetime
-import os
-import socket
-from django.db import models
-from core.models import PlCoreBase, Site, Slice, Instance, Deployment, ModelLink
-from core.models.plcorebase import StrippedCharField
-from django.contrib.contenttypes.models import ContentType
-from django.db.models import Sum
-from django.utils import timezone
-
-class Account(PlCoreBase):
- site = models.ForeignKey(Site, related_name="accounts", help_text="Site for this account")
-
- xos_links = [ModelLink(Site,via='site')]
-
- @property
- def total_invoices(self):
- # Since the amount of an invoice is the sum of it's charges, we can
- # compute the sum of the invoices by summing all charges where
- # charge.invoice != Null.
- x=self.charges.filter(invoice__isnull=False).aggregate(Sum('amount'))["amount__sum"]
- if (x==None):
- return 0.0
- return x
-
- @property
- def total_payments(self):
- x=self.payments.all().aggregate(Sum('amount'))["amount__sum"]
- if (x==None):
- return 0.0
- return x
-
- @property
- def balance_due(self):
- return self.total_invoices - self.total_payments
-
- def __unicode__(self): return u'%s' % (self.site.name)
-
-class Invoice(PlCoreBase):
- date = models.DateTimeField()
- account = models.ForeignKey(Account, related_name="invoices")
-
- xos_links = [ModelLink(Account,via='account')]
-
- @property
- def amount(self):
- return str(self.charges.all().aggregate(Sum('amount'))["amount__sum"])
-
- def __unicode__(self): return u'%s-%s' % (self.account.site.name, str(self.date))
-
-class UsableObject(PlCoreBase):
- name = StrippedCharField(max_length=1024)
-
- def __unicode__(self): return u'%s' % (self.name)
-
-class Payment(PlCoreBase):
- account = models.ForeignKey(Account, related_name="payments")
- amount = models.FloatField(default=0.0)
- date = models.DateTimeField(default=timezone.now)
-
- xos_links = [ModelLink(Account, via='account')]
-
- def __unicode__(self): return u'%s-%0.2f-%s' % (self.account.site.name, self.amount, str(self.date))
-
-class Charge(PlCoreBase):
- KIND_CHOICES = (('besteffort', 'besteffort'), ('reservation', 'reservation'), ('monthlyfee', 'monthlyfee'))
- STATE_CHOICES = (('pending', 'pending'), ('invoiced', 'invoiced'))
-
- account = models.ForeignKey(Account, related_name="charges")
- slice = models.ForeignKey(Slice, related_name="charges", null=True, blank=True)
- kind = StrippedCharField(max_length=30, choices=KIND_CHOICES, default="besteffort")
- state = StrippedCharField(max_length=30, choices=STATE_CHOICES, default="pending")
- date = models.DateTimeField()
- object = models.ForeignKey(UsableObject)
- amount = models.FloatField(default=0.0)
- coreHours = models.FloatField(default=0.0)
- invoice = models.ForeignKey(Invoice, blank=True, null=True, related_name="charges")
- xos_links = [ModelLink(Account,via='account'),ModelLink(Slice,via='slice'),ModelLink(Invoice,via='invoice')]
-
- def __unicode__(self): return u'%s-%0.2f-%s' % (self.account.site.name, self.amount, str(self.date))
-
-
-
-
diff --git a/xos/core/models/charge.xproto b/xos/core/models/charge.xproto
new file mode 100644
index 0000000..df45134
--- /dev/null
+++ b/xos/core/models/charge.xproto
@@ -0,0 +1,13 @@
+
+
+message Charge (PlCoreBase){
+ required manytoone account->Account:charges = 1 [db_index = True, null = False, blank = False];
+ optional manytoone slice->Slice:charges = 2 [db_index = True, null = True, blank = True];
+ required string kind = 3 [default = "besteffort", choices = "(('besteffort', 'besteffort'), ('reservation', 'reservation'), ('monthlyfee', 'monthlyfee'))", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+ required string state = 4 [default = "pending", choices = "(('pending', 'pending'), ('invoiced', 'invoiced'))", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+ required string date = 5 [db_index = False, null = False, content_type = "date", blank = False];
+ required manytoone object->UsableObject:charge = 6 [db_index = True, null = False, blank = False];
+ required float amount = 7 [default = 0.0, null = False, db_index = False, blank = False];
+ required float coreHours = 8 [default = 0.0, null = False, db_index = False, blank = False];
+ optional manytoone invoice->Invoice:charges = 9 [db_index = True, null = True, blank = True];
+}
diff --git a/xos/core/models/contenttype.py b/xos/core/models/contenttype.py
new file mode 100644
index 0000000..62e77ea
--- /dev/null
+++ b/xos/core/models/contenttype.py
@@ -0,0 +1 @@
+from django.contrib.contenttypes.models import ContentType
diff --git a/xos/core/models/controller.xproto b/xos/core/models/controller.xproto
new file mode 100644
index 0000000..da2d1e3
--- /dev/null
+++ b/xos/core/models/controller.xproto
@@ -0,0 +1,16 @@
+
+
+message Controller (PlCoreBase){
+ required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Name of the Controller", null = False, db_index = False];
+ required string backend_type = 2 [max_length = 200, content_type = "stripped", blank = False, help_text = "Type of compute controller, e.g. EC2, OpenStack, or OpenStack version", null = False, db_index = False];
+ required string version = 3 [max_length = 200, content_type = "stripped", blank = False, help_text = "Controller version", null = False, db_index = False];
+ optional string auth_url = 4 [max_length = 200, content_type = "stripped", blank = True, help_text = "Auth url for the compute controller", null = True, db_index = False];
+ optional string admin_user = 5 [max_length = 200, content_type = "stripped", blank = True, help_text = "Username of an admin user at this controller", null = True, db_index = False];
+ optional string admin_password = 6 [max_length = 200, content_type = "stripped", blank = True, help_text = "Password of theadmin user at this controller", null = True, db_index = False];
+ optional string admin_tenant = 7 [max_length = 200, content_type = "stripped", blank = True, help_text = "Name of the tenant the admin user belongs to", null = True, db_index = False];
+ optional string domain = 8 [max_length = 200, content_type = "stripped", blank = True, help_text = "Name of the domain this controller belongs to", null = True, db_index = False];
+ optional string rabbit_host = 9 [max_length = 200, content_type = "stripped", blank = True, help_text = "IP address of rabbitmq server at this controller", null = True, db_index = False];
+ optional string rabbit_user = 10 [max_length = 200, content_type = "stripped", blank = True, help_text = "Username of rabbitmq server at this controller", null = True, db_index = False];
+ optional string rabbit_password = 11 [max_length = 200, content_type = "stripped", blank = True, help_text = "Password of rabbitmq server at this controller", null = True, db_index = False];
+ required manytoone deployment->Deployment:controllerdeployments = 12 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/controllerdashboardview.xproto b/xos/core/models/controllerdashboardview.xproto
new file mode 100644
index 0000000..ed4229c
--- /dev/null
+++ b/xos/core/models/controllerdashboardview.xproto
@@ -0,0 +1,8 @@
+
+
+message ControllerDashboardView (PlCoreBase){
+ required manytoone controller->Controller:controllerdashboardviews = 1 [db_index = True, null = False, blank = False];
+ required manytoone dashboardView->DashboardView:controllerdashboardviews = 2 [db_index = True, null = False, blank = False];
+ required bool enabled = 3 [default = True, null = False, db_index = False, blank = True];
+ required string url = 4 [max_length = 1024, content_type = "stripped", blank = False, help_text = "URL of Dashboard", null = False, db_index = False];
+}
diff --git a/xos/core/models/controllerimages.xproto b/xos/core/models/controllerimages.xproto
new file mode 100644
index 0000000..38d6237
--- /dev/null
+++ b/xos/core/models/controllerimages.xproto
@@ -0,0 +1,7 @@
+
+
+message ControllerImages (PlCoreBase){
+ required manytoone image->Image:controllerimages = 1 [db_index = True, null = False, blank = False];
+ required manytoone controller->Controller:controllerimages = 2 [db_index = True, null = False, blank = False];
+ optional string glance_image_id = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "Glance image id", null = True, db_index = False];
+}
diff --git a/xos/core/models/controllernetwork.xproto b/xos/core/models/controllernetwork.xproto
new file mode 100644
index 0000000..ba6acec
--- /dev/null
+++ b/xos/core/models/controllernetwork.xproto
@@ -0,0 +1,14 @@
+
+
+message ControllerNetwork (PlCoreBase){
+ required manytoone network->Network:controllernetworks = 1 [db_index = True, null = False, blank = False];
+ required manytoone controller->Controller:controllernetworks = 2 [db_index = True, null = False, blank = False];
+ required string subnet = 3 [db_index = False, max_length = 32, null = False, blank = True];
+ required string start_ip = 4 [db_index = False, max_length = 32, null = False, blank = True];
+ required string stop_ip = 5 [db_index = False, max_length = 32, null = False, blank = True];
+ optional string net_id = 6 [help_text = "Neutron network", max_length = 256, null = True, db_index = False, blank = True];
+ optional string router_id = 7 [help_text = "Neutron router id", max_length = 256, null = True, db_index = False, blank = True];
+ optional string subnet_id = 8 [help_text = "Neutron subnet id", max_length = 256, null = True, db_index = False, blank = True];
+ optional string gateway = 9 [db_index = False, max_length = 32, null = True, blank = True];
+ optional string segmentation_id = 10 [db_index = False, max_length = 32, null = True, blank = True];
+}
diff --git a/xos/core/models/controllerrole.xproto b/xos/core/models/controllerrole.xproto
new file mode 100644
index 0000000..4ae4bb2
--- /dev/null
+++ b/xos/core/models/controllerrole.xproto
@@ -0,0 +1,5 @@
+
+
+message ControllerRole (PlCoreBase){
+ required string role = 1 [choices = "(('admin', 'Admin'),)", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+}
diff --git a/xos/core/models/controllersite.xproto b/xos/core/models/controllersite.xproto
new file mode 100644
index 0000000..6fb4be8
--- /dev/null
+++ b/xos/core/models/controllersite.xproto
@@ -0,0 +1,7 @@
+
+
+message ControllerSite (PlCoreBase){
+ required manytoone site->Site:controllersite = 1 [db_index = True, null = False, blank = False];
+ optional manytoone controller->Controller:controllersite = 2 [db_index = True, null = True, blank = True];
+ optional string tenant_id = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "Keystone tenant id", null = True, db_index = True];
+}
diff --git a/xos/core/models/controllersiteprivilege.xproto b/xos/core/models/controllersiteprivilege.xproto
new file mode 100644
index 0000000..ca5ca75
--- /dev/null
+++ b/xos/core/models/controllersiteprivilege.xproto
@@ -0,0 +1,7 @@
+
+
+message ControllerSitePrivilege (PlCoreBase){
+ required manytoone controller->Controller:controllersiteprivileges = 1 [db_index = True, null = False, blank = False];
+ required manytoone site_privilege->SitePrivilege:controllersiteprivileges = 2 [db_index = True, null = False, blank = False];
+ optional string role_id = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "Keystone id", null = True, db_index = True];
+}
diff --git a/xos/core/models/controllerslice.xproto b/xos/core/models/controllerslice.xproto
new file mode 100644
index 0000000..46e15ae
--- /dev/null
+++ b/xos/core/models/controllerslice.xproto
@@ -0,0 +1,7 @@
+
+
+message ControllerSlice (PlCoreBase){
+ required manytoone controller->Controller:controllerslices = 1 [db_index = True, null = False, blank = False];
+ required manytoone slice->Slice:controllerslices = 2 [db_index = True, null = False, blank = False];
+ optional string tenant_id = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "Keystone tenant id", null = True, db_index = False];
+}
diff --git a/xos/core/models/controllersliceprivilege.xproto b/xos/core/models/controllersliceprivilege.xproto
new file mode 100644
index 0000000..c1308dc
--- /dev/null
+++ b/xos/core/models/controllersliceprivilege.xproto
@@ -0,0 +1,7 @@
+
+
+message ControllerSlicePrivilege (PlCoreBase){
+ required manytoone controller->Controller:controllersliceprivileges = 1 [db_index = True, null = False, blank = False];
+ required manytoone slice_privilege->SlicePrivilege:controllersliceprivileges = 2 [db_index = True, null = False, blank = False];
+ optional string role_id = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "Keystone id", null = True, db_index = True];
+}
diff --git a/xos/core/models/controlleruser.py b/xos/core/models/controlleruser.py
deleted file mode 100644
index 0e05cfa..0000000
--- a/xos/core/models/controlleruser.py
+++ /dev/null
@@ -1,110 +0,0 @@
-import os
-import datetime
-from collections import defaultdict
-from django.db import models
-from django.db.models import F, Q
-from core.models import PlCoreBase,User,Controller,ModelLink
-from core.models.site import SitePrivilege
-from core.models.slice import SlicePrivilege
-from core.models.plcorebase import StrippedCharField
-from core.models import Controller,ControllerLinkManager,ControllerLinkDeletionManager
-
-class ControllerUser(PlCoreBase):
- objects = ControllerLinkManager()
- deleted_objects = ControllerLinkDeletionManager()
-
- user = models.ForeignKey(User,related_name='controllerusers')
- controller = models.ForeignKey(Controller,related_name='controllersusers')
- kuser_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Keystone user id")
-
- xos_links = [ModelLink(Controller,via='controller'), ModelLink(User,via='user')]
-
-
- class Meta:
- unique_together = ('user', 'controller')
-
- def __unicode__(self): return u'%s %s' % (self.controller, self.user)
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = ControllerUser.objects.all()
- else:
- users = User.select_by_user(user)
- qs = ControllerUser.objects.filter(user__in=users)
- return qs
-
- def can_update(self, user):
- return user.can_update_root()
-
-
-class ControllerSitePrivilege(PlCoreBase):
- objects = ControllerLinkManager()
- deleted_objects = ControllerLinkDeletionManager()
-
- controller = models.ForeignKey('Controller', related_name='controllersiteprivileges')
- 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")
- xos_links = [ModelLink(Controller,via='controller'), ModelLink(SitePrivilege,via='site_privilege')]
-
- class Meta:
- unique_together = ('controller', 'site_privilege', 'role_id')
-
- def __unicode__(self): return u'%s %s' % (self.controller, self.site_privilege)
-
- def can_update(self, user):
- if user.is_readonly:
- return False
- if user.is_admin:
- return True
- cprivs = ControllerSitePrivilege.objects.filter(site_privilege__user=user)
- for cpriv in dprivs:
- if cpriv.site_privilege.role.role == ['admin', 'Admin']:
- return True
- return False
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = ControllerSitePrivilege.objects.all()
- else:
- cpriv_ids = [cp.id for cp in ControllerSitePrivilege.objects.filter(site_privilege__user=user)]
- qs = ControllerSitePrivilege.objects.filter(id__in=cpriv_ids)
- return qs
-
-
-class ControllerSlicePrivilege(PlCoreBase):
- objects = ControllerLinkManager()
- deleted_objects = ControllerLinkDeletionManager()
-
- controller = models.ForeignKey('Controller', related_name='controllersliceprivileges')
- 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")
- xos_links = [ModelLink(Controller,via='controller'), ModelLink(SlicePrivilege,via='slice_privilege')]
-
-
- class Meta:
- unique_together = ('controller', 'slice_privilege')
-
- def __unicode__(self): return u'%s %s' % (self.controller, self.slice_privilege)
-
- def can_update(self, user):
- if user.is_readonly:
- return False
- if user.is_admin:
- return True
- cprivs = ControllerSlicePrivilege.objects.filter(slice_privilege__user=user)
- for cpriv in dprivs:
- if cpriv.role.role == ['admin', 'Admin']:
- return True
- return False
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = ControllerSlicePrivilege.objects.all()
- else:
- cpriv_ids = [cp.id for cp in ControllerSlicePrivilege.objects.filter(slice_privilege__user=user)]
- qs = ControllerSlicePrivilege.objects.filter(id__in=cpriv_ids)
- return qs
-
diff --git a/xos/core/models/controlleruser.xproto b/xos/core/models/controlleruser.xproto
new file mode 100644
index 0000000..5560d6d
--- /dev/null
+++ b/xos/core/models/controlleruser.xproto
@@ -0,0 +1,7 @@
+
+
+message ControllerUser (PlCoreBase){
+ required manytoone user->User:controllerusers = 1 [db_index = True, null = False, blank = False];
+ required manytoone controller->Controller:controllersusers = 2 [db_index = True, null = False, blank = False];
+ optional string kuser_id = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "Keystone user id", null = True, db_index = False];
+}
diff --git a/xos/core/models/credential.py b/xos/core/models/credential.py
deleted file mode 100644
index 166b546..0000000
--- a/xos/core/models/credential.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase,ModelLink
-from core.models import User,Site,Slice,Controller
-from core.models.plcorebase import StrippedCharField
-from encrypted_fields import EncryptedCharField
-from core.models import Controller,ControllerLinkManager,ControllerLinkDeletionManager
-
-class UserCredential(PlCoreBase):
- user = models.ForeignKey(User, related_name='usercredentials', help_text="The User this credential is associated with")
-
- name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
- key_id = StrippedCharField(help_text="The backend id of this credential", max_length=1024)
- enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
-
- xos_links = [ModelLink(User,via='user')]
-
-
- def __unicode__(self):
- return self.name
-
-class SiteCredential(PlCoreBase):
- site = models.ForeignKey(Site, related_name='sitecredentials', help_text="The User this credential is associated with")
-
- name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
- key_id = StrippedCharField(help_text="The backend id of this credential", max_length=1024)
- enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
-
- xos_links = [ModelLink(Site,via='site')]
-
- def __unicode__(self):
- return self.name
-
-class SliceCredential(PlCoreBase):
- slice = models.ForeignKey(Slice, related_name='slicecredentials', help_text="The User this credential is associated with")
-
- name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
- key_id = StrippedCharField(help_text="The backend id of this credential", max_length=1024)
- enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
-
-
- xos_links = [ModelLink(Slice,via='slice')]
-
-
- def __unicode__(self):
- return self.name
-
-class ControllerCredential(PlCoreBase):
- objects = ControllerLinkManager()
- deleted_objects = ControllerLinkDeletionManager()
- controller = models.ForeignKey(Controller, related_name='controllercredentials', help_text="The User this credential is associated with")
-
- name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
- key_id = models.CharField(help_text="The backend id of this credential", max_length=1024)
- enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
-
-
- xos_links = [ModelLink(Controller,via='controller')]
-
-
- def __unicode__(self):
- return self.name
diff --git a/xos/core/models/dashboard.py b/xos/core/models/dashboard.py
deleted file mode 100644
index d57c8ba..0000000
--- a/xos/core/models/dashboard.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase, Controller, Deployment
-from core.models.plcorebase import StrippedCharField, ModelLink
-from core.models.site import ControllerLinkManager, ControllerLinkDeletionManager
-
-
-class DashboardView(PlCoreBase):
- name = StrippedCharField(max_length=200, unique=True, help_text="Name of the View")
- url = StrippedCharField(max_length=1024, help_text="URL of Dashboard")
- controllers = models.ManyToManyField(Controller, blank=True, related_name="dashboardviews", through='ControllerDashboardView')
- enabled = models.BooleanField(default=True)
- icon = models.CharField(max_length=200, default="default-icon.png", help_text="Icon for Dashboard")
- icon_active = models.CharField(max_length=200, default="default-icon-active.png", help_text="Icon for active Dashboard")
- deployments = models.ManyToManyField(Deployment, blank=True, related_name="dashboardviews", help_text="Deployments that should be included in this view")
-
- def __unicode__(self): return u'%s' % (self.name)
-
-
-class ControllerDashboardView(PlCoreBase):
- objects = ControllerLinkManager()
- deleted_objects = ControllerLinkDeletionManager()
- controller = models.ForeignKey(Controller, related_name='controllerdashboardviews')
- dashboardView = models.ForeignKey(DashboardView, related_name='controllerdashboardviews')
- enabled = models.BooleanField(default=True)
- url = StrippedCharField(max_length=1024, help_text="URL of Dashboard")
- xos_links = [ModelLink(Controller, via='controller'), ModelLink(DashboardView, via='dashboardview')]
-
-
-class XOSGuiExtension(PlCoreBase):
- """Persist GUI Extension"""
- class Meta:
- app_label = "core"
-
- name = StrippedCharField(max_length=200, unique=True, help_text="Name of the GUI Extensions")
- files = StrippedCharField(max_length=1024, help_text="List of comma separated file composing the view")
diff --git a/xos/core/models/dashboardview.xproto b/xos/core/models/dashboardview.xproto
new file mode 100644
index 0000000..76e4f30
--- /dev/null
+++ b/xos/core/models/dashboardview.xproto
@@ -0,0 +1,11 @@
+
+
+message DashboardView (PlCoreBase){
+ required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Name of the View", null = False, db_index = False];
+ required string url = 2 [max_length = 1024, content_type = "stripped", blank = False, help_text = "URL of Dashboard", null = False, db_index = False];
+ required bool enabled = 3 [default = True, null = False, db_index = False, blank = True];
+ required string icon = 4 [default = "default-icon.png", max_length = 200, blank = False, help_text = "Icon for Dashboard", null = False, db_index = False];
+ required string icon_active = 5 [default = "default-icon-active.png", max_length = 200, blank = False, help_text = "Icon for active Dashboard", null = False, db_index = False];
+ required manytomany controllers->Controller/ControllerDashboardView:dashboardviews = 6 [db_index = False, null = False, blank = True];
+ required manytomany deployments->Deployment/DashboardView_deployments:dashboardviews = 7 [help_text = "Deployments that should be included in this view", null = False, db_index = False, blank = True];
+}
diff --git a/xos/core/models/deployment.xproto b/xos/core/models/deployment.xproto
new file mode 100644
index 0000000..779f74d
--- /dev/null
+++ b/xos/core/models/deployment.xproto
@@ -0,0 +1,6 @@
+
+
+message Deployment (PlCoreBase){
+ required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Name of the Deployment", null = False, db_index = False];
+ required string accessControl = 2 [default = "allow all", max_length = 200, blank = False, help_text = "Access control list that specifies which sites/users may use nodes in this deployment", null = False, db_index = False];
+}
diff --git a/xos/core/models/deploymentprivilege.xproto b/xos/core/models/deploymentprivilege.xproto
new file mode 100644
index 0000000..33efc2a
--- /dev/null
+++ b/xos/core/models/deploymentprivilege.xproto
@@ -0,0 +1,7 @@
+
+
+message DeploymentPrivilege (PlCoreBase){
+ required manytoone user->User:deploymentprivileges = 1 [db_index = True, null = False, blank = False];
+ required manytoone deployment->Deployment:deploymentprivileges = 2 [db_index = True, null = False, blank = False];
+ required manytoone role->DeploymentRole:deploymentprivileges = 3 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/deploymentrole.xproto b/xos/core/models/deploymentrole.xproto
new file mode 100644
index 0000000..61adab5
--- /dev/null
+++ b/xos/core/models/deploymentrole.xproto
@@ -0,0 +1,5 @@
+
+
+message DeploymentRole (PlCoreBase){
+ required string role = 1 [choices = "(('admin', 'Admin'),)", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+}
diff --git a/xos/core/models/diag.xproto b/xos/core/models/diag.xproto
new file mode 100644
index 0000000..7869f50
--- /dev/null
+++ b/xos/core/models/diag.xproto
@@ -0,0 +1,5 @@
+
+
+message Diag (PlCoreBase){
+ required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Name of the synchronizer", null = False, db_index = False];
+}
diff --git a/xos/core/models/flavor.py b/xos/core/models/flavor.py
deleted file mode 100644
index 693a5f8..0000000
--- a/xos/core/models/flavor.py
+++ /dev/null
@@ -1,45 +0,0 @@
-import os
-import socket
-from django.db import models
-from core.models import PlCoreBase, Deployment
-from core.models.plcorebase import StrippedCharField
-from django.contrib.contenttypes.models import ContentType
-
-class Flavor(PlCoreBase):
- name = StrippedCharField(max_length=32, help_text="name of this flavor, as displayed to users")
- description = StrippedCharField(max_length=1024, blank=True, null=True)
- flavor = StrippedCharField(max_length=32, help_text="flavor string used to configure deployments")
- deployments = models.ManyToManyField(Deployment, blank=True, related_name="flavors")
- order = models.IntegerField(default=0, help_text="used to order flavors when displayed in a list")
- default = models.BooleanField(default=False, help_text="make this a default flavor to use when creating new instances")
-
- class Meta:
- app_label = "core"
- ordering = ('order', 'name')
-
- def __init__(self, *args, **kwargs):
- super(Flavor, self).__init__(*args, **kwargs)
- self.no_sync=True
-
- def __unicode__(self): return u'%s' % (self.name)
-
-""" FlavorParameterType and FlavorParameter are below for completeness sake,
- waiting for the day we might want to add parameters to flavors.
-
-class FlavorParameterType(PlCoreBase):
- name = models.SlugField(help_text="The name of this parameter", max_length=128)
- description = StrippedCharField(max_length=1024)
-
- def __unicode__(self): return u'%s' % (self.name)
-
-class FlavorParameter(PlCoreBase):
- parameter = models.ForeignKey(FlavorParameterType, related_name="flavorparameters", help_text="The type of the parameter")
- value = StrippedCharField(help_text="The value of this parameter", max_length=1024)
-
- flavor = models.ForeignKey(Flavor,related_name='flavorparameter')
-
- def __unicode__(self):
- return self.parameter.name
-
-"""
-
diff --git a/xos/core/models/flavor.xproto b/xos/core/models/flavor.xproto
new file mode 100644
index 0000000..d30a7c2
--- /dev/null
+++ b/xos/core/models/flavor.xproto
@@ -0,0 +1,10 @@
+
+
+message Flavor (PlCoreBase){
+ required string name = 1 [max_length = 32, content_type = "stripped", blank = False, help_text = "name of this flavor, as displayed to users", null = False, db_index = False];
+ optional string description = 2 [db_index = False, max_length = 1024, null = True, content_type = "stripped", blank = True];
+ required string flavor = 3 [max_length = 32, content_type = "stripped", blank = False, help_text = "flavor string used to configure deployments", null = False, db_index = False];
+ required int32 order = 4 [help_text = "used to order flavors when displayed in a list", default = 0, null = False, db_index = False, blank = False];
+ required bool default = 5 [help_text = "make this a default flavor to use when creating new instances", default = False, null = False, db_index = False, blank = True];
+ required manytomany deployments->Deployment/DashboardView_deployments:flavors = 6 [db_index = False, null = False, blank = True];
+}
diff --git a/xos/core/models/header.py b/xos/core/models/header.py
new file mode 120000
index 0000000..721b5c0
--- /dev/null
+++ b/xos/core/models/header.py
@@ -0,0 +1 @@
+attic/header.py
\ No newline at end of file
diff --git a/xos/core/models/image.py b/xos/core/models/image.py
deleted file mode 100644
index 8f48458..0000000
--- a/xos/core/models/image.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase
-from core.models.plcorebase import StrippedCharField,ModelLink
-from core.models import Deployment, DeploymentPrivilege, Controller,ControllerLinkManager,ControllerLinkDeletionManager
-
-# Create your models here.
-
-class Image(PlCoreBase):
- KIND_CHOICES = (('vm', 'Virtual Machine'), ('container', 'Container'), )
-
- name = StrippedCharField(max_length=256, unique=True)
- kind = models.CharField(null=False, blank=False, max_length=30, choices=KIND_CHOICES, default="vm")
- disk_format = StrippedCharField(max_length=256)
- container_format = StrippedCharField(max_length=256)
- path = StrippedCharField(max_length=256, null=True, blank=True, help_text="Path to image on local disk")
- deployments = models.ManyToManyField('Deployment', through='ImageDeployments', blank=True, help_text="Select which images should be instantiated on this deployment", related_name='images')
-
- tag = StrippedCharField(max_length=256, null=True, blank=True, help_text="For Docker Images, tag of image")
-
- def __unicode__(self): return u'%s' % (self.name)
-
-class ImageDeployments(PlCoreBase):
- image = models.ForeignKey(Image,related_name='imagedeployments')
- deployment = models.ForeignKey(Deployment,related_name='imagedeployments')
- xos_links = [ModelLink(Image,'image'),ModelLink(Deployment,'deployment')]
-
- class Meta:
- unique_together = ('image', 'deployment')
-
- def __unicode__(self): return u'%s %s' % (self.image, self.deployment)
-
- def can_update(self, user):
- return user.can_update_deployment(self.deployment)
-
-class ControllerImages(PlCoreBase):
- objects = ControllerLinkManager()
- deleted_objects = ControllerLinkDeletionManager()
- 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")
- xos_links = [ModelLink(Image,'image'),ModelLink(Controller,'controller')]
-
- class Meta:
- unique_together = ('image', 'controller')
-
- def __unicode__(self): return u'%s %s' % (self.image, self.controller)
diff --git a/xos/core/models/image.xproto b/xos/core/models/image.xproto
new file mode 100644
index 0000000..f810e0d
--- /dev/null
+++ b/xos/core/models/image.xproto
@@ -0,0 +1,11 @@
+
+
+message Image (PlCoreBase){
+ required string name = 1 [db_index = False, max_length = 256, null = False, content_type = "stripped", blank = False];
+ required string kind = 2 [default = "vm", choices = "(('vm', 'Virtual Machine'), ('container', 'Container'))", max_length = 30, blank = False, null = False, db_index = False];
+ required string disk_format = 3 [db_index = False, max_length = 256, null = False, content_type = "stripped", blank = False];
+ required string container_format = 4 [db_index = False, max_length = 256, null = False, content_type = "stripped", blank = False];
+ optional string path = 5 [max_length = 256, content_type = "stripped", blank = True, help_text = "Path to image on local disk", null = True, db_index = False];
+ optional string tag = 6 [max_length = 256, content_type = "stripped", blank = True, help_text = "For Docker Images, tag of image", null = True, db_index = False];
+ required manytomany deployments->Deployment/ImageDeployments:images = 7 [help_text = "Select which images should be instantiated on this deployment", null = False, db_index = False, blank = True];
+}
diff --git a/xos/core/models/imagedeployments.xproto b/xos/core/models/imagedeployments.xproto
new file mode 100644
index 0000000..e11fedb
--- /dev/null
+++ b/xos/core/models/imagedeployments.xproto
@@ -0,0 +1,6 @@
+
+
+message ImageDeployments (PlCoreBase){
+ required manytoone image->Image:imagedeployments = 1 [db_index = True, null = False, blank = False];
+ required manytoone deployment->Deployment:imagedeployments = 2 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/instance.py b/xos/core/models/instance.py
deleted file mode 100644
index 043df7c..0000000
--- a/xos/core/models/instance.py
+++ /dev/null
@@ -1,261 +0,0 @@
-import os
-from django.db import models
-from django.db.models import Q
-from django.core import exceptions
-from core.models import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager,ModelLink
-from core.models.plcorebase import StrippedCharField
-from core.models import Image
-from core.models import Slice, SlicePrivilege
-from core.models import Node
-from core.models import Site
-from core.models import Deployment
-from core.models import Controller
-from core.models import User
-from core.models import Tag
-from core.models import Flavor
-from django.contrib.contenttypes.fields import GenericRelation
-from xos.config import Config
-from django.core.exceptions import PermissionDenied, ValidationError
-
-config = Config()
-
-def get_default_flavor(controller = None):
- # Find a default flavor that can be used for a instance. This is particularly
- # useful in evolution. It's also intended this helper function can be used
- # for admin.py when users
-
- if controller:
- flavors = controller.flavors.all()
- else:
- flavors = Flavor.objects.all()
-
- if not flavors:
- return None
-
- for flavor in flavors:
- if flavor.default:
- return flavor
-
- return flavors[0]
-
-class InstanceDeletionManager(PlCoreBaseDeletionManager):
- def get_queryset(self):
- parent=super(InstanceDeletionManager, self)
- try:
- backend_type = config.observer_backend_type
- except AttributeError:
- backend_type = None
-
- parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
- if (backend_type):
- return parent_queryset.filter(Q(node__controller__backend_type=backend_type))
- else:
- return parent_queryset
-
- # deprecated in django 1.7 in favor of get_queryset().
- def get_query_set(self):
- return self.get_queryset()
-
-
-class InstanceManager(PlCoreBaseManager):
- def get_queryset(self):
- parent=super(InstanceManager, self)
-
- try:
- backend_type = config.observer_backend_type
- except AttributeError:
- backend_type = None
-
- parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
-
- if backend_type:
- return parent_queryset.filter(Q(node__controller__backend_type=backend_type))
- else:
- return parent_queryset
-
- # deprecated in django 1.7 in favor of get_queryset().
- def get_query_set(self):
- return self.get_queryset()
-
-# Create your models here.
-class Instance(PlCoreBase):
- ISOLATION_CHOICES = (('vm', 'Virtual Machine'), ('container', 'Container'), ('container_vm', 'Container In VM'))
-
- objects = InstanceManager()
- deleted_objects = InstanceDeletionManager()
- instance_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Nova instance id")
- instance_uuid = StrippedCharField(null=True, blank=True, max_length=200, help_text="Nova instance uuid")
- name = StrippedCharField(max_length=200, help_text="Instance name")
- instance_name = StrippedCharField(blank=True, null=True, max_length=200, help_text="OpenStack generated name")
- ip = models.GenericIPAddressField(help_text="Instance ip address", blank=True, null=True)
- image = models.ForeignKey(Image, related_name='instances')
- creator = models.ForeignKey(User, related_name='instances', blank=True, null=True)
- slice = models.ForeignKey(Slice, related_name='instances')
- deployment = models.ForeignKey(Deployment, verbose_name='deployment', related_name='instance_deployment')
- node = models.ForeignKey(Node, related_name='instances')
- numberCores = models.IntegerField(verbose_name="Number of Cores", help_text="Number of cores for instance", default=0)
- flavor = models.ForeignKey(Flavor, help_text="Flavor of this instance", default=get_default_flavor)
- tags = GenericRelation(Tag)
- userData = models.TextField(blank=True, null=True, help_text="user_data passed to instance during creation")
- isolation = models.CharField(null=False, blank=False, max_length=30, choices=ISOLATION_CHOICES, default="vm")
- volumes = models.TextField(null=True, blank=True, help_text="Comma-separated list of directories to expose to parent context")
- parent = models.ForeignKey("Instance", null=True, blank=True, help_text="Parent Instance for containers nested inside of VMs")
-
- xos_links = [ModelLink(dest=Slice,via='slice'),ModelLink(dest=Image,via='image')]
-
- def get_controller (self):
- return self.node.site_deployment.controller
-
- def tologdict(self):
- d=super(Instance,self).tologdict()
- try:
- d['slice_name']=self.slice.name
- d['controller_name']=self.get_controller().name
- except:
- pass
- return d
-
- def __unicode__(self):
- if self.name and Slice.objects.filter(id=self.slice_id) and (self.name != self.slice.name):
- # NOTE: The weird check on self.slice_id was due to a problem when
- # deleting the slice before the instance.
- return u'%s' % self.name
- elif self.instance_name:
- return u'%s' % (self.instance_name)
- elif self.id:
- return u'uninstantiated-%s' % str(self.id)
- elif self.slice:
- return u'unsaved-instance on %s' % self.slice.name
- else:
- return u'unsaved-instance'
-
- def save(self, *args, **kwds):
- if not self.name:
- self.name = self.slice.name
- if not self.creator and hasattr(self, 'caller'):
- self.creator = self.caller
- if not self.creator:
- raise ValidationError('instance has no creator')
-
- if (self.isolation == "container") or (self.isolation == "container_vm"):
- if (self.image.kind != "container"):
- raise ValidationError("Container instance must use container image")
- elif (self.isolation == "vm"):
- if (self.image.kind != "vm"):
- raise ValidationError("VM instance must use VM image")
-
- if (self.isolation == "container_vm") and (not self.parent):
- raise ValidationError("Container-vm instance must have a parent")
-
- if (self.parent) and (self.isolation != "container_vm"):
- raise ValidationError("Parent field can only be set on Container-vm instances")
-
- if (self.slice.creator != self.creator):
- # Check to make sure there's a slice_privilege for the user. If there
- # isn't, then keystone will throw an exception inside the observer.
- slice_privs = SlicePrivilege.objects.filter(slice=self.slice, user=self.creator)
- if not slice_privs:
- raise ValidationError('instance creator has no privileges on slice')
-
-# XXX smbaker - disabled for now, was causing fault in tenant view create slice
-# if not self.controllerNetwork.test_acl(slice=self.slice):
-# raise exceptions.ValidationError("Deployment %s's ACL does not allow any of this slice %s's users" % (self.controllerNetwork.name, self.slice.name))
-
- super(Instance, self).save(*args, **kwds)
-
- def can_update(self, user):
- return user.can_update_slice(self.slice)
-
- def all_ips(self):
- ips={}
- for ns in self.ports.all():
- if ns.ip:
- ips[ns.network.name] = ns.ip
- return ips
-
- def all_ips_string(self):
- result = []
- ips = self.all_ips()
- for key in sorted(ips.keys()):
- #result.append("%s = %s" % (key, ips[key]))
- result.append(ips[key])
- return ", ".join(result)
- all_ips_string.short_description = "addresses"
-
- def get_public_ip(self):
- for ns in self.ports.all():
- if (ns.ip) and (ns.network.template.visibility=="public") and (ns.network.template.translation=="none"):
- return ns.ip
- return None
-
- # return an address on nat-net
- def get_network_ip(self, pattern):
- for ns in self.ports.all():
- if pattern in ns.network.name.lower():
- return ns.ip
- return None
-
- # return an address that the synchronizer can use to SSH to the instance
- def get_ssh_ip(self):
- # first look specifically for a management_local network
- for ns in self.ports.all():
- if ns.network.template and ns.network.template.vtn_kind=="MANAGEMENT_LOCAL":
- return ns.ip
-
- # for compatibility, now look for any management network
- management=self.get_network_ip("management")
- if management:
- return management
-
- # if all else fails, look for nat-net (for OpenCloud?)
- return self.get_network_ip("nat")
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = Instance.objects.all()
- else:
- slices = Slice.select_by_user(user)
- qs = Instance.objects.filter(slice__in=slices)
- return qs
-
- def get_cpu_stats(self):
- filter = 'instance_id=%s'%self.instance_id
- return monitor.get_meter('cpu',filter,None)
-
- def get_bw_stats(self):
- filter = 'instance_id=%s'%self.instance_id
- return monitor.get_meter('network.outgoing.bytes',filter,None)
-
- def get_node_stats(self):
- # Note sure what should go back here
- return 1
-
- def get_ssh_command(self):
- if (not self.instance_id) or (not self.node) or (not self.instance_name):
- return None
- else:
- return 'ssh -o "ProxyCommand ssh -q %s@%s" ubuntu@%s' % (self.instance_id, self.node.name, self.instance_name)
-
- def get_public_keys(self):
- slice_memberships = SlicePrivilege.objects.filter(slice=self.slice)
- pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
-
- if self.creator.public_key:
- pubkeys.add(self.creator.public_key)
-
- if self.slice.creator.public_key:
- pubkeys.add(self.slice.creator.public_key)
-
- if self.slice.service and self.slice.service.public_key:
- pubkeys.add(self.slice.service.public_key)
-
- return pubkeys
-
-def controller_setter(instance, **kwargs):
- try:
- instance.controller = instance.node.site_deployment.controller
- except:
- instance.controller = None
-
-models.signals.post_init.connect(controller_setter, Instance)
diff --git a/xos/core/models/instance.xproto b/xos/core/models/instance.xproto
new file mode 100644
index 0000000..b411bd4
--- /dev/null
+++ b/xos/core/models/instance.xproto
@@ -0,0 +1,21 @@
+
+
+message Instance (PlCoreBase){
+ optional string instance_id = 1 [max_length = 200, content_type = "stripped", blank = True, help_text = "Nova instance id", null = True, db_index = False];
+ optional string instance_uuid = 2 [max_length = 200, content_type = "stripped", blank = True, help_text = "Nova instance uuid", null = True, db_index = False];
+ required string name = 3 [max_length = 200, content_type = "stripped", blank = False, help_text = "Instance name", null = False, db_index = False];
+ optional string instance_name = 4 [max_length = 200, content_type = "stripped", blank = True, help_text = "OpenStack generated name", null = True, db_index = False];
+ optional string ip = 5 [max_length = 39, content_type = "ip", blank = True, help_text = "Instance ip address", null = True, db_index = False];
+ required manytoone image->Image:instances = 6 [db_index = True, null = False, blank = False];
+ optional manytoone creator->User:instances = 7 [db_index = True, null = True, blank = True];
+ required manytoone slice->Slice:instances = 8 [db_index = True, null = False, blank = False];
+ required manytoone deployment->Deployment:instance_deployment = 9 [db_index = True, null = False, blank = False];
+ required manytoone node->Node:instances = 10 [db_index = True, null = False, blank = False];
+ required int32 numberCores = 11 [help_text = "Number of cores for instance", default = 0, null = False, db_index = False, blank = False];
+ required manytoone flavor->Flavor:instance = 12 [help_text = "Flavor of this instance", default = "get_default_flavor()", null = False, db_index = True, blank = False];
+ optional string userData = 13 [help_text = "user_data passed to instance during creation", null = True, db_index = False, blank = True];
+ required string isolation = 14 [default = "vm", choices = "(('vm', 'Virtual Machine'), ('container', 'Container'), ('container_vm', 'Container In VM'))", max_length = 30, blank = False, null = False, db_index = False];
+ optional string volumes = 15 [help_text = "Comma-separated list of directories to expose to parent context", null = True, db_index = False, blank = True];
+ optional manytoone parent->Instance:instance = 16 [help_text = "Parent Instance for containers nested inside of VMs", null = True, db_index = True, blank = True];
+ required manytomany tags->Tag = 17 [db_index = False, null = False, blank = True];
+}
diff --git a/xos/core/models/invoice.xproto b/xos/core/models/invoice.xproto
new file mode 100644
index 0000000..7c05a58
--- /dev/null
+++ b/xos/core/models/invoice.xproto
@@ -0,0 +1,6 @@
+
+
+message Invoice (PlCoreBase){
+ required string date = 1 [db_index = False, null = False, content_type = "date", blank = False];
+ required manytoone account->Account:invoices = 2 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/journal.py b/xos/core/models/journal.py
index 6c25033..9d60f2a 100644
--- a/xos/core/models/journal.py
+++ b/xos/core/models/journal.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
from django.db import models
from django.utils import timezone
diff --git a/xos/core/models/library.xproto b/xos/core/models/library.xproto
new file mode 100644
index 0000000..8505547
--- /dev/null
+++ b/xos/core/models/library.xproto
@@ -0,0 +1,4 @@
+
+
+message Library (LoadableModule){
+}
diff --git a/xos/core/models/loadablemodule.xproto b/xos/core/models/loadablemodule.xproto
new file mode 100644
index 0000000..9f953d4
--- /dev/null
+++ b/xos/core/models/loadablemodule.xproto
@@ -0,0 +1,10 @@
+
+
+message LoadableModule (PlCoreBase){
+ required manytoone xos->XOS:loadable_modules = 1 [help_text = "Pointer to XOS", default = "get_xos()", null = False, db_index = True, blank = False];
+ required string name = 2 [max_length = 30, content_type = "stripped", blank = False, help_text = "Service Name", null = False, db_index = False];
+ optional string base_url = 3 [max_length = 1024, content_type = "stripped", blank = True, help_text = "Base URL, allows use of relative URLs for resources", null = True, db_index = False];
+ optional string version = 4 [default = "1.0.0", max_length = 30, content_type = "stripped", blank = True, help_text = "Version of Service Controller", null = True, db_index = False];
+ optional string provides = 5 [max_length = 254, content_type = "stripped", blank = True, help_text = "Comma-separated list of things provided", null = True, db_index = False];
+ optional string requires = 6 [max_length = 254, content_type = "stripped", blank = True, help_text = "Comma-separated list of required Service Controllers", null = True, db_index = False];
+}
diff --git a/xos/core/models/loadablemoduleresource.xproto b/xos/core/models/loadablemoduleresource.xproto
new file mode 100644
index 0000000..f91729f
--- /dev/null
+++ b/xos/core/models/loadablemoduleresource.xproto
@@ -0,0 +1,10 @@
+
+
+message LoadableModuleResource (PlCoreBase){
+ required manytoone loadable_module->LoadableModule:loadable_module_resources = 1 [help_text = "The Loadable Module this resource is associated with", null = False, db_index = True, blank = False];
+ required string name = 2 [max_length = 30, content_type = "stripped", blank = False, help_text = "Object Name", null = False, db_index = False];
+ optional string subdirectory = 3 [max_length = 1024, content_type = "stripped", blank = True, help_text = "optional subdirectory", null = True, db_index = False];
+ required string kind = 4 [choices = "(('models', 'Models'), ('admin', 'Admin'), ('admin_template', 'Admin Template'), ('django_library', 'Django Library'), ('synchronizer', 'Synchronizer'), ('rest_service', 'REST API (service)'), ('rest_tenant', 'REST API (tenant)'), ('tosca_custom_types', 'Tosca Custom Types'), ('tosca_resource', 'Tosca Resource'), ('private_key', 'Private Key'), ('public_key', 'Public Key'), ('vendor_js', 'Vendor Javascript'))", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+ required string format = 5 [choices = "(('python', 'Python'), ('manifest', 'Manifest'), ('docker', 'Docker Container'), ('yaml', 'YAML'), ('raw', 'raw'), ('javascript', 'Javascript'))", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+ optional string url = 6 [max_length = 1024, content_type = "stripped", blank = True, help_text = "URL of resource", null = True, db_index = False];
+}
diff --git a/xos/core/models/network.py b/xos/core/models/network.py
deleted file mode 100644
index a2b61c2..0000000
--- a/xos/core/models/network.py
+++ /dev/null
@@ -1,426 +0,0 @@
-import os
-import socket
-import sys
-from django.db import models, transaction
-from core.models import PlCoreBase, Site, Slice, Instance, Controller, Service, ModelLink
-from core.models import ControllerLinkManager,ControllerLinkDeletionManager
-from django.contrib.contenttypes.models import ContentType
-from django.contrib.contenttypes.fields import GenericForeignKey
-from django.core.exceptions import ValidationError
-from django.db.models import Q
-
-# If true, then IP addresses will be allocated by the model. If false, then
-# we will assume the observer handles it.
-NO_OBSERVER=False
-
-def ParseNatList(ports):
- """ Support a list of ports in the format "protocol:port, protocol:port, ..."
- examples:
- tcp 123
- tcp 123:133
- tcp 123, tcp 124, tcp 125, udp 201, udp 202
-
- User can put either a "/" or a " " between protocol and ports
- Port ranges can be specified with "-" or ":"
- """
- nats = []
- if ports:
- parts = ports.split(",")
- for part in parts:
- part = part.strip()
- if "/" in part:
- (protocol, ports) = part.split("/",1)
- elif " " in part:
- (protocol, ports) = part.split(None,1)
- else:
- raise TypeError('malformed port specifier %s, format example: "tcp 123, tcp 201:206, udp 333"' % part)
-
- protocol = protocol.strip()
- ports = ports.strip()
-
- if not (protocol in ["udp", "tcp"]):
- raise ValueError('unknown protocol %s' % protocol)
-
- if "-" in ports:
- (first, last) = ports.split("-")
- first = int(first.strip())
- last = int(last.strip())
- portStr = "%d:%d" % (first, last)
- elif ":" in ports:
- (first, last) = ports.split(":")
- first = int(first.strip())
- last = int(last.strip())
- portStr = "%d:%d" % (first, last)
- else:
- portStr = "%d" % int(ports)
-
- nats.append( {"l4_protocol": protocol, "l4_port": portStr} )
-
- return nats
-
-def ValidateNatList(ports):
- try:
- ParseNatList(ports)
- except Exception,e:
- raise ValidationError(str(e))
-
-class ParameterMixin(object):
- # helper classes for dealing with NetworkParameter
-
- def get_parameters(self):
- parameter_dict = {}
-
- instance_type = ContentType.objects.get_for_model(self)
- for param in NetworkParameter.objects.filter(content_type__pk=instance_type.id, object_id=self.id):
- parameter_dict[param.parameter.name] = param.value
-
- return parameter_dict
-
- def set_parameter(self, name, value):
- instance_type = ContentType.objects.get_for_model(self)
- existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
- if existing_params:
- p=existing_params[0]
- p.value = value
- p.save()
- else:
- pt = NetworkParameterType.objects.get(name=name)
- p = NetworkParameter(parameter=pt, content_type=instance_type, object_id=self.id, value=value)
- p.save()
-
- def unset_parameter(self, name):
- instance_type = ContentType.objects.get_for_model(self)
- existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
- for p in existing_params:
- p.delete()
-
-
-class NetworkTemplate(PlCoreBase, ParameterMixin):
- VISIBILITY_CHOICES = (('public', 'public'), ('private', 'private'))
- TRANSLATION_CHOICES = (('none', 'none'), ('NAT', 'NAT'))
- TOPOLOGY_CHOICES = (('bigswitch', 'BigSwitch'), ('physical', 'Physical'), ('custom', 'Custom'))
- CONTROLLER_CHOICES = ((None, 'None'), ('onos', 'ONOS'), ('custom', 'Custom'))
- ACCESS_CHOICES = ((None, 'None'), ('indirect', 'Indirect'), ('direct', 'Direct'))
-
- VTN_KIND_CHOICES = (("PRIVATE", "Private"), ("PUBLIC", "Public"), ("MANAGEMENT_LOCAL", "Management Local"),
- ("MANAGEMENT_HOST", "Management Host"), ("VSG", "VSG"), ("ACCESS_AGENT", "Access Agent"))
-
- name = models.CharField(max_length=32)
- description = models.CharField(max_length=1024, blank=True, null=True)
- guaranteed_bandwidth = 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")
- access = models.CharField(max_length=30, null=True, blank=True, choices=ACCESS_CHOICES, help_text="Advertise this network as a means for other slices to contact this slice")
- shared_network_name = models.CharField(max_length=30, blank=True, null=True)
- shared_network_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network")
- topology_kind = models.CharField(null=False, blank=False, max_length=30, choices=TOPOLOGY_CHOICES, default="bigswitch")
- controller_kind = models.CharField(null=True, blank=True, max_length=30, choices=CONTROLLER_CHOICES, default=None)
- vtn_kind = models.CharField(null=True, blank=True, max_length=30, choices=VTN_KIND_CHOICES, default="PRIVATE")
-
- def __init__(self, *args, **kwargs):
- super(NetworkTemplate, self).__init__(*args, **kwargs)
-
- # somehow these got set wrong inside of the live database. Remove this
- # code after all is well...
- if (self.topology_kind=="BigSwitch"):
- print >> sys.stderr, "XXX warning: topology_kind invalid case"
- self.topology_kind="bigswitch"
- elif (self.topology_kind=="Physical"):
- print >> sys.stderr, "XXX warning: topology_kind invalid case"
- self.topology_kind="physical"
- elif (self.topology_kind=="Custom"):
- print >> sys.stderr, "XXX warning: topology_kind invalid case"
- self.toplogy_kind="custom"
-
- def save(self, *args, **kwargs):
- self.enforce_choices(self.access, self.ACCESS_CHOICES)
- super(NetworkTemplate, self).save(*args, **kwargs)
-
- def __unicode__(self): return u'%s' % (self.name)
-
-class Network(PlCoreBase, ParameterMixin):
- name = models.CharField(max_length=32)
- template = models.ForeignKey(NetworkTemplate)
- subnet = models.CharField(max_length=32, blank=True)
- start_ip = models.CharField(max_length=32, blank=True)
- end_ip = models.CharField(max_length=32, blank=True)
- ports = models.CharField(max_length=1024, blank=True, null=True, validators=[ValidateNatList])
- labels = models.CharField(max_length=1024, blank=True, null=True)
- owner = models.ForeignKey(Slice, related_name="ownedNetworks", help_text="Slice that owns control of this Network")
-
- guaranteed_bandwidth = models.IntegerField(default=0)
- permit_all_slices = models.BooleanField(default=False)
- permitted_slices = models.ManyToManyField(Slice, blank=True, related_name="availableNetworks")
- slices = models.ManyToManyField(Slice, blank=True, related_name="networks", through="NetworkSlice")
- instances = models.ManyToManyField(Instance, blank=True, related_name="networks", through="Port")
-
- topology_parameters = models.TextField(null=True, blank=True)
- controller_url = models.CharField(null=True, blank=True, max_length=1024)
- controller_parameters = models.TextField(null=True, blank=True)
-
- # 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")
-
- autoconnect = models.BooleanField(default=True, help_text="This network can be autoconnected to the slice that owns it")
-
- 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()])
- print "DEF_MOD_NET_IP", self.start_ip
- super(Network, self).save(*args, **kwds)
-
- def can_update(self, user):
- return user.can_update_slice(self.owner)
-
- @property
- def nat_list(self):
- return ParseNatList(self.ports)
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = Network.objects.all()
- else:
- slices = Slice.select_by_user(user)
- #slice_ids = [s.id for s in Slice.select_by_user(user)]
- qs = Network.objects.filter(owner__in=slices)
- return qs
-
- def get_parameters(self):
- # returns parameters from the template, updated by self.
- p={}
- if self.template:
- p = self.template.get_parameters()
- p.update(ParameterMixin.get_parameters(self))
- return p
-
-class ControllerNetwork(PlCoreBase):
- objects = ControllerLinkManager()
- deleted_objects = ControllerLinkDeletionManager()
-
- # Stores the openstack ids at various controllers
- network = models.ForeignKey(Network, related_name='controllernetworks')
- controller = models.ForeignKey(Controller, related_name='controllernetworks')
- subnet = models.CharField(max_length=32, blank=True)
- start_ip = models.CharField(max_length=32, blank=True)
- stop_ip = models.CharField(max_length=32, blank=True)
- net_id = models.CharField(null=True, blank=True, max_length=256, help_text="Neutron network") # feedback state
- router_id = models.CharField(null=True, blank=True, max_length=256, help_text="Neutron router id") # feedback state
- subnet_id = models.CharField(null=True, blank=True, max_length=256, help_text="Neutron subnet id") # feedback state
- gateway = models.CharField(max_length=32, blank=True, null=True) # feedback state
- segmentation_id = models.CharField(max_length=32, blank=True, null=True) # feedback state
- xos_links = [ModelLink(Controller,via='controller'),ModelLink(Network,via='network')]
-
- class Meta:
- unique_together = ('network', 'controller')
-
- def tologdict(self):
- d=super(ControllerNetwork,self).tologdict()
- try:
- d['network_name']=self.network.name
- d['controller_name']=self.controller.name
- except:
- pass
- return d
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = ControllerNetwork.objects.all()
- else:
- slices = Slice.select_by_user(user)
- networks = Network.objects.filter(owner__in=slices)
- qs = ControllerNetwork.objects.filter(network__in=networks)
- return qs
-
-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,related_name='networkslices')
- slice = models.ForeignKey(Slice,related_name='networkslices')
-
- xos_links = [ModelLink(Network,via='network'),ModelLink(Slice,via='slice')]
-
- class Meta:
- unique_together = ('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.permit_all_slices):
- # to add a instance to the network, then one of the following must be true:
- # 1) instance's slice is in network's permittedSlices list,
- # 2) instance'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)
-
- def can_update(self, user):
- return user.can_update_slice(self.slice)
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = NetworkSlice.objects.all()
- else:
- slice_ids = [s.id for s in Slice.select_by_user(user)]
- network_ids = [network.id for network in Network.select_by_user(user)]
- qs = NetworkSlice.objects.filter(Q(slice__in=slice_ids) | Q(network__in=network_ids))
- return qs
-
-class Port(PlCoreBase, ParameterMixin):
- network = models.ForeignKey(Network,related_name='links')
- instance = models.ForeignKey(Instance, null=True, blank=True, related_name='ports')
- ip = models.GenericIPAddressField(help_text="Instance ip address", blank=True, null=True)
- port_id = models.CharField(null=True, blank=True, max_length=256, help_text="Neutron port id")
- mac = models.CharField(null=True, blank=True, max_length=256, help_text="MAC address associated with this port")
- xos_created = models.BooleanField(default=False) # True if XOS created this port in Neutron, False if port created by Neutron and observed by XOS
-
- xos_links = [ModelLink(Network,via='network'), ModelLink('Instance',via='instance')]
-
- class Meta:
- unique_together = ('network', 'instance')
-
- def save(self, *args, **kwds):
- if self.instance:
- slice = self.instance.slice
- if (slice not in self.network.permitted_slices.all()) and (slice != self.network.owner) and (not self.network.permit_all_slices):
- # to add a instance to the network, then one of the following must be true:
- # 1) instance's slice is in network's permittedSlices list,
- # 2) instance'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(Port, self).save(*args, **kwds)
-
- def __unicode__(self):
- if self.instance:
- return u'%s-%s' % (self.network.name, self.instance.instance_name)
- else:
- return u'%s-unboundport-%s' % (self.network.name, self.id)
-
- def can_update(self, user):
- if self.instance:
- return user.can_update_slice(self.instance.slice)
- if self.network:
- return user.can_update_slice(self.network.owner)
- return False
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = Port.objects.all()
- else:
- instances = Instance.select_by_user(user)
- instance_ids = [instance.id for instance in instances]
- networks = Network.select_by_user(user)
- network_ids = [network.id for network in networks]
- qs = Port.objects.filter(Q(instance__in=instance_ids) | Q(network__in=network_ids))
- return qs
-
- def get_parameters(self):
- # returns parameters from the network, updated by self.
- p={}
- if self.network:
- p = self.network.get_parameters()
- p.update(ParameterMixin.get_parameters(self))
- return p
-
-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)
-
- def can_update(self, user):
- return user.can_update_slice(self.owner)
-
-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="networkparameters", 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 = GenericForeignKey('content_type', 'object_id')
-
- def __unicode__(self):
- return self.parameter.name
-
-class AddressPool(PlCoreBase):
- name = models.CharField(max_length=32)
- addresses = models.TextField(blank=True, null=True)
- gateway_ip = models.CharField(max_length=32, null=True)
- gateway_mac = models.CharField(max_length=32, null=True)
- cidr = models.CharField(max_length=32, null=True)
- inuse = models.TextField(blank=True, null=True)
- service = models.ForeignKey(Service, related_name="addresspools", null=True, blank=True)
-
- def __unicode__(self): return u'%s' % (self.name)
-
- def get_address(self):
- with transaction.atomic():
- ap = AddressPool.objects.get(pk=self.pk)
- if ap.addresses:
- avail_ips = ap.addresses.split()
- else:
- avail_ips = []
-
- if ap.inuse:
- inuse_ips = ap.inuse.split()
- else:
- inuse_ips = []
-
- while avail_ips:
- addr = avail_ips.pop(0)
-
- if addr in inuse_ips:
- # This may have happened if someone re-ran the tosca
- # recipe and 'refilled' the AddressPool while some addresses
- # were still in use.
- continue
-
- inuse_ips.insert(0,addr)
-
- ap.inuse = " ".join(inuse_ips)
- ap.addresses = " ".join(avail_ips)
- ap.save()
- return addr
-
- addr = None
- return addr
-
- def put_address(self, addr):
- with transaction.atomic():
- ap = AddressPool.objects.get(pk=self.pk)
- addresses = ap.addresses or ""
- parts = addresses.split()
- if addr not in parts:
- parts.insert(0,addr)
- ap.addresses = " ".join(parts)
-
- inuse = ap.inuse or ""
- parts = inuse.split()
- if addr in parts:
- parts.remove(addr)
- ap.inuse = " ".join(parts)
-
- ap.save()
-
-
diff --git a/xos/core/models/network.xproto b/xos/core/models/network.xproto
new file mode 100644
index 0000000..4e66a1f
--- /dev/null
+++ b/xos/core/models/network.xproto
@@ -0,0 +1,24 @@
+
+
+message Network (PlCoreBase,ParameterMixin){
+ required string name = 1 [db_index = False, max_length = 32, null = False, blank = False];
+ required manytoone template->NetworkTemplate:network = 2 [db_index = True, null = False, blank = False];
+ required string subnet = 3 [db_index = False, max_length = 32, null = False, blank = True];
+ required string start_ip = 4 [db_index = False, max_length = 32, null = False, blank = True];
+ required string end_ip = 5 [db_index = False, max_length = 32, null = False, blank = True];
+ optional string ports = 6 [db_index = False, max_length = 1024, null = True, blank = True];
+ optional string labels = 7 [db_index = False, max_length = 1024, null = True, blank = True];
+ required manytoone owner->Slice:ownedNetworks = 8 [help_text = "Slice that owns control of this Network", null = False, db_index = True, blank = False];
+ required int32 guaranteed_bandwidth = 9 [default = 0, null = False, db_index = False, blank = False];
+ required bool permit_all_slices = 10 [default = False, null = False, db_index = False, blank = True];
+ optional string topology_parameters = 11 [db_index = False, null = True, blank = True];
+ optional string controller_url = 12 [db_index = False, max_length = 1024, null = True, blank = True];
+ optional string controller_parameters = 13 [db_index = False, null = True, blank = True];
+ optional string network_id = 14 [help_text = "Quantum network", max_length = 256, null = True, db_index = False, blank = True];
+ optional string router_id = 15 [help_text = "Quantum router id", max_length = 256, null = True, db_index = False, blank = True];
+ optional string subnet_id = 16 [help_text = "Quantum subnet id", max_length = 256, null = True, db_index = False, blank = True];
+ required bool autoconnect = 17 [help_text = "This network can be autoconnected to the slice that owns it", default = True, null = False, db_index = False, blank = True];
+ required manytomany permitted_slices->Slice/Network_permitted_slices:availableNetworks = 18 [db_index = False, null = False, blank = True];
+ required manytomany slices->Slice/NetworkSlice:networks = 19 [db_index = False, null = False, blank = True];
+ required manytomany instances->Instance/Port:networks = 20 [db_index = False, null = False, blank = True];
+}
diff --git a/xos/core/models/network_header.py b/xos/core/models/network_header.py
new file mode 120000
index 0000000..1573aea
--- /dev/null
+++ b/xos/core/models/network_header.py
@@ -0,0 +1 @@
+attic/network_header.py
\ No newline at end of file
diff --git a/xos/core/models/networkparameter.xproto b/xos/core/models/networkparameter.xproto
new file mode 100644
index 0000000..81585ee
--- /dev/null
+++ b/xos/core/models/networkparameter.xproto
@@ -0,0 +1,8 @@
+
+
+message NetworkParameter (PlCoreBase){
+ required manytoone parameter->NetworkParameterType:networkparameters = 1 [help_text = "The type of the parameter", null = False, db_index = True, blank = False];
+ required string value = 2 [help_text = "The value of this parameter", max_length = 1024, null = False, db_index = False, blank = False];
+ required manytoone content_type->ContentType:networkparameter = 3 [db_index = True, null = False, blank = False];
+ required uint32 object_id = 4 [db_index = False, null = False, blank = False];
+}
diff --git a/xos/core/models/networkparametertype.xproto b/xos/core/models/networkparametertype.xproto
new file mode 100644
index 0000000..6eb7804
--- /dev/null
+++ b/xos/core/models/networkparametertype.xproto
@@ -0,0 +1,6 @@
+
+
+message NetworkParameterType (PlCoreBase){
+ required string name = 1 [help_text = "The name of this parameter", max_length = 128, null = False, db_index = True, blank = False];
+ required string description = 2 [db_index = False, max_length = 1024, null = False, blank = False];
+}
diff --git a/xos/core/models/networkslice.xproto b/xos/core/models/networkslice.xproto
new file mode 100644
index 0000000..7ae04a2
--- /dev/null
+++ b/xos/core/models/networkslice.xproto
@@ -0,0 +1,6 @@
+
+
+message NetworkSlice (PlCoreBase){
+ required manytoone network->Network:networkslices = 1 [db_index = True, null = False, blank = False];
+ required manytoone slice->Slice:networkslices = 2 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/networktemplate.xproto b/xos/core/models/networktemplate.xproto
new file mode 100644
index 0000000..3d17277
--- /dev/null
+++ b/xos/core/models/networktemplate.xproto
@@ -0,0 +1,15 @@
+
+
+message NetworkTemplate (PlCoreBase,ParameterMixin){
+ required string name = 1 [db_index = False, max_length = 32, null = False, blank = False];
+ optional string description = 2 [db_index = False, max_length = 1024, null = True, blank = True];
+ required int32 guaranteed_bandwidth = 3 [default = 0, null = False, db_index = False, blank = False];
+ required string visibility = 4 [default = "private", choices = "(('public', 'public'), ('private', 'private'))", max_length = 30, blank = False, null = False, db_index = False];
+ required string translation = 5 [default = "none", choices = "(('none', 'none'), ('NAT', 'NAT'))", max_length = 30, blank = False, null = False, db_index = False];
+ optional string access = 6 [choices = "((None, 'None'), ('indirect', 'Indirect'), ('direct', 'Direct'))", max_length = 30, blank = True, help_text = "Advertise this network as a means for other slices to contact this slice", null = True, db_index = False];
+ optional string shared_network_name = 7 [db_index = False, max_length = 30, null = True, blank = True];
+ optional string shared_network_id = 8 [help_text = "Quantum network", max_length = 256, null = True, db_index = False, blank = True];
+ required string topology_kind = 9 [default = "bigswitch", choices = "(('bigswitch', 'BigSwitch'), ('physical', 'Physical'), ('custom', 'Custom'))", max_length = 30, blank = False, null = False, db_index = False];
+ optional string controller_kind = 10 [blank = True, max_length = 30, null = True, db_index = False, choices = "((None, 'None'), ('onos', 'ONOS'), ('custom', 'Custom'))"];
+ optional string vtn_kind = 11 [default = "PRIVATE", choices = "(('PRIVATE', 'Private'), ('PUBLIC', 'Public'), ('MANAGEMENT_LOCAL', 'Management Local'), ('MANAGEMENT_HOST', 'Management Host'), ('VSG', 'VSG'), ('ACCESS_AGENT', 'Access Agent'))", max_length = 30, blank = True, null = True, db_index = False];
+}
diff --git a/xos/core/models/node.py b/xos/core/models/node.py
deleted file mode 100644
index 5cfc9b8..0000000
--- a/xos/core/models/node.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase,ModelLink
-from core.models.plcorebase import StrippedCharField
-from core.models.site import Site, SiteDeployment, SitePrivilege
-from core.models import Tag
-from django.contrib.contenttypes.fields import GenericRelation
-
-# Create your models here.
-
-class Node(PlCoreBase):
- name = StrippedCharField(max_length=200, unique=True, help_text="Name of the Node")
- site_deployment = models.ForeignKey(SiteDeployment, related_name='nodes')
- site = models.ForeignKey(Site, null=True, blank=True, related_name='nodes')
- tags = GenericRelation(Tag)
- xos_links = [ModelLink(Site,'site')]
-
-
- def __unicode__(self): return u'%s' % (self.name)
-
- def __init__(self, *args, **kwargs):
- super(Node, self).__init__(*args, **kwargs)
- self.no_sync=True
-
- def save(self, *args, **kwds):
- if self.site is None and self.site_deployment is not None:
- self.site = self.site_deployment.site
-
- super(Node, self).save(*args, **kwds)
-
- def can_update(self, user):
- return user.can_update_site(self.site, allow=['tech'])
-
-class NodeLabel(PlCoreBase):
- name = StrippedCharField(max_length=200, help_text="label name", unique=True)
- node = models.ManyToManyField(Node, related_name="nodelabels", blank=True)
-
- def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/node.xproto b/xos/core/models/node.xproto
new file mode 100644
index 0000000..3a88b6a
--- /dev/null
+++ b/xos/core/models/node.xproto
@@ -0,0 +1,8 @@
+
+
+message Node (PlCoreBase){
+ required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Name of the Node", null = False, db_index = False];
+ required manytoone site_deployment->SiteDeployment:nodes = 2 [db_index = True, null = False, blank = False];
+ optional manytoone site->Site:nodes = 3 [db_index = True, null = True, blank = True];
+ required manytomany tags->Tag = 4 [db_index = False, null = False, blank = True];
+}
diff --git a/xos/core/models/nodelabel.xproto b/xos/core/models/nodelabel.xproto
new file mode 100644
index 0000000..fc89a46
--- /dev/null
+++ b/xos/core/models/nodelabel.xproto
@@ -0,0 +1,6 @@
+
+
+message NodeLabel (PlCoreBase){
+ required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "label name", null = False, db_index = False];
+ required manytomany node->Node/NodeLabel_node:nodelabels = 2 [db_index = False, null = False, blank = True];
+}
diff --git a/xos/core/models/payment.xproto b/xos/core/models/payment.xproto
new file mode 100644
index 0000000..f9723ad
--- /dev/null
+++ b/xos/core/models/payment.xproto
@@ -0,0 +1,7 @@
+
+
+message Payment (PlCoreBase){
+ required manytoone account->Account:payments = 1 [db_index = True, null = False, blank = False];
+ required float amount = 2 [default = 0.0, null = False, db_index = False, blank = False];
+ required string date = 3 [default = "now()", null = False, db_index = False, content_type = "date", blank = False];
+}
diff --git a/xos/core/models/port.xproto b/xos/core/models/port.xproto
new file mode 100644
index 0000000..a3a9cdc
--- /dev/null
+++ b/xos/core/models/port.xproto
@@ -0,0 +1,10 @@
+
+
+message Port (PlCoreBase,ParameterMixin){
+ required manytoone network->Network:links = 1 [db_index = True, null = False, blank = False];
+ optional manytoone instance->Instance:ports = 2 [db_index = True, null = True, blank = True];
+ optional string ip = 3 [max_length = 39, content_type = "ip", blank = True, help_text = "Instance ip address", null = True, db_index = False];
+ optional string port_id = 4 [help_text = "Neutron port id", max_length = 256, null = True, db_index = False, blank = True];
+ optional string mac = 5 [help_text = "MAC address associated with this port", max_length = 256, null = True, db_index = False, blank = True];
+ required bool xos_created = 6 [default = False, null = False, db_index = False, blank = True];
+}
diff --git a/xos/core/models/program.py b/xos/core/models/program.py
deleted file mode 100644
index 01e17fa..0000000
--- a/xos/core/models/program.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from django.db import models
-from core.models import PlCoreBase,SingletonModel,PlCoreBaseManager,User
-from core.models.plcorebase import StrippedCharField
-from xos.exceptions import *
-from operator import attrgetter
-import json
-
-class Program(PlCoreBase):
- KIND_CHOICES = (('tosca', 'Tosca'), )
- COMMAND_CHOICES = (('run', 'Run'), ('destroy', 'Destroy'), )
-
- name = StrippedCharField(max_length=30, help_text="Service Name")
- description = models.TextField(max_length=254,null=True, blank=True,help_text="Description of Service")
- kind = StrippedCharField(max_length=30, help_text="Kind of service", choices=KIND_CHOICES)
- command = StrippedCharField(blank=True, null=True, max_length=30, help_text="Command to run", choices=COMMAND_CHOICES)
-
- owner = models.ForeignKey(User, null=True, related_name="programs")
-
- contents = models.TextField(blank=True, null=True, help_text="Contents of Program")
- output = models.TextField(blank=True, null=True, help_text="Output of Program")
- messages = models.TextField(blank=True, null=True, help_text="Debug messages")
- status = models.TextField(blank=True, null=True, max_length=30, help_text="Status of program")
-
- @classmethod
- def select_by_user(cls, user):
- return cls.objects.all()
-
- def __unicode__(self): return u'%s' % (self.name)
-
- def can_update(self, user):
- return True
-
- def save(self, *args, **kwargs):
- # set creator on first save
- if not self.owner and hasattr(self, 'caller'):
- self.owner = self.caller
-
- if (self.command in ["run", "destroy"]) and (self.status in ["complete", "exception"]):
- self.status = "queued"
-
- super(Program, self).save(*args, **kwargs)
-
diff --git a/xos/core/models/program.xproto b/xos/core/models/program.xproto
new file mode 100644
index 0000000..38b083e
--- /dev/null
+++ b/xos/core/models/program.xproto
@@ -0,0 +1,13 @@
+
+
+message Program (PlCoreBase){
+ required string name = 1 [max_length = 30, content_type = "stripped", blank = False, help_text = "Service Name", null = False, db_index = False];
+ optional string description = 2 [help_text = "Description of Service", max_length = 254, null = True, db_index = False, blank = True];
+ required string kind = 3 [choices = "(('tosca', 'Tosca'),)", max_length = 30, content_type = "stripped", blank = False, help_text = "Kind of service", null = False, db_index = False];
+ optional string command = 4 [choices = "(('run', 'Run'), ('destroy', 'Destroy'))", max_length = 30, content_type = "stripped", blank = True, help_text = "Command to run", null = True, db_index = False];
+ optional manytoone owner->User:programs = 5 [db_index = True, null = True, blank = False];
+ optional string contents = 6 [help_text = "Contents of Program", null = True, db_index = False, blank = True];
+ optional string output = 7 [help_text = "Output of Program", null = True, db_index = False, blank = True];
+ optional string messages = 8 [help_text = "Debug messages", null = True, db_index = False, blank = True];
+ optional string status = 9 [help_text = "Status of program", max_length = 30, null = True, db_index = False, blank = True];
+}
diff --git a/xos/core/models/project.py b/xos/core/models/project.py
deleted file mode 100644
index 9cc2927..0000000
--- a/xos/core/models/project.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase
-from core.models.plcorebase import StrippedCharField
-
-# Create your models here.
-
-class Project(PlCoreBase):
- name = StrippedCharField(max_length=200, unique=True, help_text="Name of Project")
-
- def __unicode__(self): return u'%s' % (self.name)
-
diff --git a/xos/core/models/project.xproto b/xos/core/models/project.xproto
new file mode 100644
index 0000000..d857de9
--- /dev/null
+++ b/xos/core/models/project.xproto
@@ -0,0 +1,5 @@
+
+
+message Project (PlCoreBase){
+ required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Name of Project", null = False, db_index = False];
+}
diff --git a/xos/core/models/reservation.py b/xos/core/models/reservation.py
deleted file mode 100644
index 6b6e7a1..0000000
--- a/xos/core/models/reservation.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import os
-import datetime
-from django.db import models
-from core.models import PlCoreBase, ModelLink
-from core.models import Instance
-from core.models import Slice
-from core.models import ServiceResource
-
-# Create your models here.
-
-class Reservation(PlCoreBase):
- startTime = models.DateTimeField()
- slice = models.ForeignKey(Slice, related_name="reservations")
- duration = models.IntegerField(default=1)
-
- xos_links = [ModelLink(Slice,via='slice')]
-
- def __unicode__(self): return u'%s to %s' % (self.startTime, self.endTime)
-
- @property
- def endTime(self):
- return self.startTime + datetime.timedelta(hours=self.duration)
-
- def can_update(self, user):
- return user.can_update_slice(self.slice)
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = Reservation.objects.all()
- else:
- slice_ids = [s.id for s in Slice.select_by_user(user)]
- qs = Reservation.objects.filter(id__in=slice_ids)
- return qs
-
-class ReservedResource(PlCoreBase):
- instance = models.ForeignKey(Instance, related_name="reservedresources")
- resource = models.ForeignKey(ServiceResource, related_name="reservedresources")
- quantity = models.IntegerField(default=1)
- reservationSet = models.ForeignKey(Reservation, related_name="reservedresources")
-
- xos_links = [ModelLink(Instance,'instance'),ModelLink(ServiceResource,'resource')]
-
- class Meta(PlCoreBase.Meta):
- verbose_name_plural = "Reserved Resources"
-
- def __unicode__(self): return u'%d %s on %s' % (self.quantity, self.resource, self.instance)
-
- def can_update(self, user):
- return user.can_update(self.instance.slice)
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = ReservedResource.objects.all()
- else:
- instance_ids = [s.id for s in Instance.select_by_user(user)]
- qs = ReservedResource.objects.filter(id__in=instance_ids)
- return qs
-
-
diff --git a/xos/core/models/reservation.xproto b/xos/core/models/reservation.xproto
new file mode 100644
index 0000000..be00e7f
--- /dev/null
+++ b/xos/core/models/reservation.xproto
@@ -0,0 +1,7 @@
+
+
+message Reservation (PlCoreBase){
+ required string startTime = 1 [db_index = False, null = False, content_type = "date", blank = False];
+ required manytoone slice->Slice:reservations = 2 [db_index = True, null = False, blank = False];
+ required int32 duration = 3 [default = 1, null = False, db_index = False, blank = False];
+}
diff --git a/xos/core/models/reservedresource.xproto b/xos/core/models/reservedresource.xproto
new file mode 100644
index 0000000..d3baae7
--- /dev/null
+++ b/xos/core/models/reservedresource.xproto
@@ -0,0 +1,8 @@
+
+
+message ReservedResource (PlCoreBase){
+ required manytoone instance->Instance:reservedresources = 1 [db_index = True, null = False, blank = False];
+ required manytoone resource->ServiceResource:reservedresources = 2 [db_index = True, null = False, blank = False];
+ required int32 quantity = 3 [default = 1, null = False, db_index = False, blank = False];
+ required manytoone reservationSet->Reservation:reservedresources = 4 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/role.py b/xos/core/models/role.py
deleted file mode 100644
index b259410..0000000
--- a/xos/core/models/role.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import os
-import datetime
-from django.db import models
-from django.contrib.contenttypes.models import ContentType
-from core.models import PlCoreBase
-from core.models.plcorebase import StrippedCharField
-
-class Role(PlCoreBase):
-
- role_type = StrippedCharField(max_length=80, verbose_name="Name")
- role = StrippedCharField(max_length=80, verbose_name="Keystone role id", null=True, blank=True)
- description = StrippedCharField(max_length=120, verbose_name="Description")
- content_type = models.ForeignKey(ContentType, verbose_name="Role Scope")
-
- def __unicode__(self): return u'%s:%s' % (self.content_type,self.role_type)
-
-
- def save(self, *args, **kwds):
- super(Role, self).save(*args, **kwds)
-
- def delete(self, *args, **kwds):
- super(Role, self).delete(*args, **kwds)
-
diff --git a/xos/core/models/role.xproto b/xos/core/models/role.xproto
new file mode 100644
index 0000000..2ebde68
--- /dev/null
+++ b/xos/core/models/role.xproto
@@ -0,0 +1,8 @@
+
+
+message Role (PlCoreBase){
+ required string role_type = 1 [db_index = False, max_length = 80, null = False, content_type = "stripped", blank = False];
+ optional string role = 2 [db_index = False, max_length = 80, null = True, content_type = "stripped", blank = True];
+ required string description = 3 [db_index = False, max_length = 120, null = False, content_type = "stripped", blank = False];
+ required manytoone content_type->ContentType:role = 4 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/router.xproto b/xos/core/models/router.xproto
new file mode 100644
index 0000000..0e17b20
--- /dev/null
+++ b/xos/core/models/router.xproto
@@ -0,0 +1,8 @@
+
+
+message Router (PlCoreBase){
+ required string name = 1 [db_index = False, max_length = 32, null = False, blank = False];
+ required manytoone owner->Slice:routers = 2 [db_index = True, null = False, blank = False];
+ required manytomany permittedNetworks->Network/Router_permittedNetworks:availableRouters = 3 [db_index = False, null = False, blank = True];
+ required manytomany networks->Network/Router_networks:routers = 4 [db_index = False, null = False, blank = True];
+}
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
deleted file mode 100644
index d3cfc04..0000000
--- a/xos/core/models/service.py
+++ /dev/null
@@ -1,1112 +0,0 @@
-import json
-import operator
-
-from operator import attrgetter
-from distutils.version import LooseVersion
-
-from core.models import PlCoreBase, PlCoreBaseManager, SingletonModel, XOS
-from core.models.plcorebase import StrippedCharField
-from django.db import models
-from django.core.validators import URLValidator
-from xos.exceptions import *
-import urlparse
-
-COARSE_KIND = "coarse"
-
-def get_xos():
- xos = XOS.objects.all()
-
- if xos:
- return xos[0]
- else:
- return None
-
-class AttributeMixin(object):
- # helper for extracting things from a json-encoded
- # service_specific_attribute
-
- def get_attribute(self, name, default=None):
- if self.service_specific_attribute:
- attributes = json.loads(self.service_specific_attribute)
- else:
- attributes = {}
- return attributes.get(name, default)
-
- def set_attribute(self, name, value):
- if self.service_specific_attribute:
- attributes = json.loads(self.service_specific_attribute)
- else:
- attributes = {}
- attributes[name] = value
- self.service_specific_attribute = json.dumps(attributes)
-
- def get_initial_attribute(self, name, default=None):
- if self._initial["service_specific_attribute"]:
- attributes = json.loads(
- self._initial["service_specific_attribute"])
- else:
- attributes = {}
- return attributes.get(name, default)
-
- @classmethod
- def get_default_attribute(cls, name):
- for (attrname, default) in cls.simple_attributes:
- if attrname == name:
- return default
- if hasattr(cls, "default_attributes"):
- if name in cls.default_attributes:
- return cls.default_attributes[name]
-
- return None
-
- @classmethod
- def setup_simple_attributes(cls):
- for (attrname, default) in cls.simple_attributes:
- setattr(cls, attrname, property(lambda self, attrname=attrname, default=default: self.get_attribute(attrname, default),
- lambda self, value, attrname=attrname: self.set_attribute(
- attrname, value),
- None,
- attrname))
-
-class LoadableModule(PlCoreBase):
- xos = models.ForeignKey(XOS, related_name='loadable_modules', help_text="Pointer to XOS", default=get_xos)
- name = StrippedCharField(max_length=30, help_text="Service Name")
- base_url = StrippedCharField(max_length=1024, help_text="Base URL, allows use of relative URLs for resources", null=True, blank=True)
-
- version = StrippedCharField(blank=True, null=True,
- max_length=30, help_text="Version of Service Controller", default = "1.0.0")
- provides = StrippedCharField(blank=True, null=True,
- max_length=254, help_text="Comma-separated list of things provided")
- requires = StrippedCharField(blank=True, null=True,
- max_length=254, help_text="Comma-separated list of required Service Controllers")
-
- def __unicode__(self): return u'%s' % (self.name)
-
- def save(self, *args, **kwargs):
- super(LoadableModule, self).save(*args, **kwargs)
-
- # This is necessary, as the XOS syncstep handles rerunning the docker-
- # compose.
- # TODO: Update synchronizer and replace with watcher functionality
- if self.xos:
- # force XOS to rebuild
- self.xos.save(update_fields=["updated"])
-
- def get_provides_list(self):
- prov_list = []
- if self.provides and self.provides.strip():
- for prov in self.provides.split(","):
- prov=prov.strip()
- if "=" in prov:
- (name, version) = prov.split("=",1)
- name = name.strip()
- version = version.strip()
- else:
- name = prov
- version = "1.0.0"
- prov_list.append( {"name": name, "version": version} )
-
- # every controller provides itself
- prov_list.append( {"name": self.name, "version": self.version} )
-
- return prov_list
-
-
- @classmethod
- def dependency_check(cls, dep_list):
- missing = []
- satisfied = []
- operators = {">=": operator.ge,
- "<=": operator.le,
- ">": operator.gt,
- "<": operator.lt,
- "!=": operator.ne,
- "=": operator.eq}
- for dep in dep_list:
- dep = dep.strip()
- name = dep
- version = None
- this_op = None
- for op in operators.keys():
- if op in dep:
- (name, version) = dep.split(op,1)
- name = name.strip()
- version = version.strip()
- this_op = operators[op]
- break
- found=False
- scs = ServiceController.objects.all()
- for sc in scs:
- for provide in sc.get_provides_list():
- if (provide["name"] != name):
- continue
- if not this_op:
- satisfied.append(sc)
- found=True
- break
- elif this_op(LooseVersion(provide["version"]), LooseVersion(version)):
- satisfied.append(sc)
- found=True
- break
- if not found:
- missing.append(dep)
-
- return (satisfied, missing)
-
-class LoadableModuleResource(PlCoreBase):
- KIND_CHOICES = (('xproto', 'XProto'),
- ('models', 'Models'),
- ('admin', 'Admin'),
- ('admin_template', 'Admin Template'),
- ('django_library', 'Django Library'),
- ('synchronizer', 'Synchronizer'),
- ('rest_service', 'REST API (service)'),
- ('rest_tenant', 'REST API (tenant)'),
- ('tosca_custom_types', 'Tosca Custom Types'),
- ('tosca_resource', 'Tosca Resource'),
- ('private_key', 'Private Key'),
- ('public_key', 'Public Key'),
- ('vendor_js', 'Vendor Javascript'))
-
- FORMAT_CHOICES = (('xproto', 'XProto'),
- ('python', 'Python'),
- ('manifest', 'Manifest'),
- ('docker', 'Docker Container'),
- ('yaml', 'YAML'),
- ('raw', 'raw'),
- ('javascript', 'Javascript'))
-
- loadable_module = models.ForeignKey(LoadableModule, related_name='loadable_module_resources',
- help_text="The Loadable Module this resource is associated with")
-
- name = StrippedCharField(max_length=30, help_text="Object Name")
- subdirectory = StrippedCharField(max_length=1024, help_text="optional subdirectory", null=True, blank=True)
- kind = StrippedCharField(choices=KIND_CHOICES, max_length=30)
- format = StrippedCharField(choices=FORMAT_CHOICES, max_length=30)
- url = StrippedCharField(max_length=1024, help_text="URL of resource", null=True, blank=True)
-
- def __unicode__(self): return u'%s' % (self.name)
-
- @property
- def full_url(self):
- if self.loadable_module and self.loadable_module.base_url:
- return urlparse.urljoin(self.loadable_module.base_url, self.url)
- else:
- return self.url
-
-class Library(LoadableModule):
- # for now, it's exactly like a LoadableModule
- pass
-
-
-class XOSComponent(LoadableModule):
- # this will define loadable XOS component in the form of containers
- image = StrippedCharField(max_length=200, help_text="docker image name")
- command = StrippedCharField(max_length=1024, help_text="docker run command", null=True, blank=True)
- ports = StrippedCharField(max_length=200, help_text="port binding", null=True, blank=True)
- extra = StrippedCharField(max_length=200, help_text="extra information needed by containers", null=True, blank=True)
-
- no_start = models.BooleanField(help_text="Do not start the Component", default=False)
-
-
-class XOSComponentLink(PlCoreBase):
-
- LINK_KIND = (
- ('internal', 'Internal'),
- ('external', 'External')
- )
-
- component = models.ForeignKey(XOSComponent, related_name='links', help_text="The Component object for this Link")
- container = StrippedCharField(max_length=200, help_text="container to link")
- alias = StrippedCharField(max_length=200, help_text="alias for the link")
- kind = models.CharField(max_length=20, choices=LINK_KIND, default='internal')
-
- def save(self, *args, **kwds):
- # If this is a new object, then check to make sure it doesn't already exist
- if not self.pk:
- existing = XOSComponentLink.objects.filter(container=self.container, alias=self.alias)
- if len(existing) > 0:
- raise XOSValidationError('XOSComponentLink for %s:%s already defined' % (self.container, self.alias))
- super(XOSComponentLink, self).save(*args, **kwds)
-
-
-# NOTE can this be the same of XOSVolume??
-class XOSComponentVolume(PlCoreBase):
- component = models.ForeignKey(XOSComponent, related_name='volumes', help_text="The Component object for this Volume")
- name = StrippedCharField(max_length=300, help_text="Volume Name")
- container_path = StrippedCharField(max_length=1024, unique=True, help_text="Path of Volume in Container")
- host_path = StrippedCharField(max_length=1024, help_text="Path of Volume in Host")
- read_only = models.BooleanField(default=False, help_text="True if mount read-only")
-
- def save(self, *args, **kwds):
- # If this is a new object, then check to make sure it doesn't already exist
- if not self.pk:
- existing = XOSComponentVolume.objects.filter(container_path=self.container_path, host_path=self.host_path)
- if len(existing) > 0:
- raise XOSValidationError('XOSComponentVolume for %s:%s already defined' % (self.container_path, self.host_path))
- super(XOSComponentVolume, self).save(*args, **kwds)
-
-
-class XOSComponentVolumeContainer(PlCoreBase):
- component = models.ForeignKey(XOSComponent, related_name='volumecontainers', help_text="The Component object for this VolumeContainer")
- name = StrippedCharField(max_length=300, help_text="Volume Name")
- container = StrippedCharField(max_length=300, help_text="Volume Name")
-
- def save(self, *args, **kwds):
- # If this is a new object, then check to make sure it doesn't already exist
- if not self.pk:
- existing = XOSComponentVolumeContainer.objects.filter(name=self.name)
- if len(existing) > 0:
- raise XOSValidationError('XOSComponentVolumeContainer for %s:%s already defined' % (self.container_path, self.host_path))
- super(XOSComponentVolumeContainer, self).save(*args, **kwds)
-
-
-class ServiceController(LoadableModule):
- synchronizer_run = StrippedCharField(max_length=1024, help_text="synchronizer run command", null=True, blank=True)
- synchronizer_config = StrippedCharField(max_length=1024, help_text="synchronizer config file", null=True, blank=True)
-
- image = StrippedCharField(max_length=200, help_text="docker image name", null=True, blank=True)
-
- no_start = models.BooleanField(help_text="Do not start the Synchronizer", default=False)
- no_build = models.BooleanField(help_text="Do not build the Synchronizer container", default=False)
- no_deploy = models.BooleanField(help_text="Do not add synchronizer container to onboarding-docker-compose", default=False)
-
-class Service(PlCoreBase, AttributeMixin):
- # when subclassing a service, redefine KIND to describe the new service
- KIND = "generic"
-
- description = models.TextField(
- max_length=254, null=True, blank=True, help_text="Description of Service")
- enabled = models.BooleanField(default=True)
- kind = StrippedCharField(
- max_length=30, help_text="Kind of service", default=KIND)
- name = StrippedCharField(max_length=30, help_text="Service Name")
- versionNumber = StrippedCharField(blank=True, null=True,
- max_length=30, help_text="Version of Service Definition") # deprecated
- published = models.BooleanField(default=True)
- view_url = StrippedCharField(blank=True, null=True, max_length=1024)
- icon_url = StrippedCharField(blank=True, null=True, max_length=1024)
- public_key = models.TextField(
- null=True, blank=True, max_length=1024, help_text="Public key string")
- private_key_fn = StrippedCharField(blank=True, null=True, max_length=1024)
-
- # Service_specific_attribute and service_specific_id are opaque to XOS
- service_specific_id = StrippedCharField(
- max_length=30, blank=True, null=True)
- service_specific_attribute = models.TextField(blank=True, null=True)
-
- controller = models.ForeignKey(ServiceController, related_name='services',
- help_text="The Service Controller this Service uses",
- null=True, blank=True)
-
- def __init__(self, *args, **kwargs):
- # for subclasses, set the default kind appropriately
- self._meta.get_field("kind").default = self.KIND
- super(Service, self).__init__(*args, **kwargs)
-
- @classmethod
- def get_service_objects(cls):
- return cls.objects.filter(kind=cls.KIND)
-
- @classmethod
- def get_deleted_service_objects(cls):
- return cls.deleted_objects.filter(kind=cls.KIND)
-
- @classmethod
- def get_service_objects_by_user(cls, user):
- return cls.select_by_user(user).filter(kind=cls.KIND)
-
- @classmethod
- def select_by_user(cls, user):
- if user.is_admin:
- return cls.objects.all()
- else:
- service_ids = [
- sp.slice.id for sp in ServicePrivilege.objects.filter(user=user)]
- return cls.objects.filter(id__in=service_ids)
-
- @property
- def serviceattribute_dict(self):
- attrs = {}
- for attr in self.serviceattributes.all():
- attrs[attr.name] = attr.value
- return attrs
-
- def __unicode__(self): return u'%s' % (self.name)
-
- def can_update(self, user):
- return user.can_update_service(self, allow=['admin'])
-
- def get_scalable_nodes(self, slice, max_per_node=None, exclusive_slices=[]):
- """
- Get a list of nodes that can be used to scale up a slice.
-
- slice - slice to scale up
- max_per_node - maximum numbers of instances that 'slice' can have on a single node
- exclusive_slices - list of slices that must have no nodes in common with 'slice'.
- """
-
- # late import to get around order-of-imports constraint in __init__.py
- from core.models import Node, Instance
-
- nodes = list(Node.objects.all())
-
- conflicting_instances = Instance.objects.filter(
- slice__in=exclusive_slices)
- conflicting_nodes = Node.objects.filter(
- instances__in=conflicting_instances)
-
- nodes = [x for x in nodes if x not in conflicting_nodes]
-
- # If max_per_node is set, then limit the number of instances this slice
- # can have on a single node.
- if max_per_node:
- acceptable_nodes = []
- for node in nodes:
- existing_count = node.instances.filter(slice=slice).count()
- if existing_count < max_per_node:
- acceptable_nodes.append(node)
- nodes = acceptable_nodes
-
- return nodes
-
- def pick_node(self, slice, max_per_node=None, exclusive_slices=[]):
- # Pick the best node to scale up a slice.
-
- nodes = self.get_scalable_nodes(slice, max_per_node, exclusive_slices)
- nodes = sorted(nodes, key=lambda node: node.instances.all().count())
- if not nodes:
- return None
- return nodes[0]
-
- def adjust_scale(self, slice_hint, scale, max_per_node=None, exclusive_slices=[]):
- # late import to get around order-of-imports constraint in __init__.py
- from core.models import Instance
-
- slices = [x for x in self.slices.all() if slice_hint in x.name]
- for slice in slices:
- while slice.instances.all().count() > scale:
- s = slice.instances.all()[0]
- # print "drop instance", s
- s.delete()
-
- while slice.instances.all().count() < scale:
- node = self.pick_node(slice, max_per_node, exclusive_slices)
- if not node:
- # no more available nodes
- break
-
- image = slice.default_image
- if not image:
- raise XOSConfigurationError(
- "No default_image for slice %s" % slice.name)
-
- flavor = slice.default_flavor
- if not flavor:
- raise XOSConfigurationError(
- "No default_flavor for slice %s" % slice.name)
-
- s = Instance(slice=slice,
- node=node,
- creator=slice.creator,
- image=image,
- flavor=flavor,
- deployment=node.site_deployment.deployment)
- s.save()
-
- # print "add instance", s
-
- def get_vtn_src_nets(self):
- nets = []
- for slice in self.slices.all():
- for ns in slice.networkslices.all():
- if not ns.network:
- continue
-# if ns.network.template.access in ["direct", "indirect"]:
-# # skip access networks; we want to use the private network
-# continue
- if "management" in ns.network.name:
- # don't try to connect the management network to anything
- continue
- if ns.network.name in ["wan_network", "lan_network"]:
- # we don't want to attach to the vCPE's lan or wan network
- # we only want to attach to its private network
- # TODO: fix hard-coding of network name
- continue
- for cn in ns.network.controllernetworks.all():
- if cn.net_id:
- net = {"name": ns.network.name, "net_id": cn.net_id}
- nets.append(net)
- return nets
-
- def get_vtn_nets(self):
- nets = []
- for slice in self.slices.all():
- for ns in slice.networkslices.all():
- if not ns.network:
- continue
- if ns.network.template.access not in ["direct", "indirect"]:
- # skip anything that's not an access network
- continue
- for cn in ns.network.controllernetworks.all():
- if cn.net_id:
- net = {"name": ns.network.name, "net_id": cn.net_id}
- nets.append(net)
- return nets
-
- def get_vtn_dependencies_nets(self):
- provider_nets = []
- for tenant in self.subscribed_tenants.all():
- if tenant.provider_service:
- for net in tenant.provider_service.get_vtn_nets():
- if not net in provider_nets:
- net["bidirectional"] = tenant.connect_method!="private-unidirectional"
- provider_nets.append(net)
- return provider_nets
-
- def get_vtn_dependencies_ids(self):
- return [x["net_id"] for x in self.get_vtn_dependencies_nets()]
-
- def get_vtn_dependencies_names(self):
- return [x["name"] + "_" + x["net_id"] for x in self.get_vtn_dependencies_nets()]
-
- def get_vtn_src_ids(self):
- return [x["net_id"] for x in self.get_vtn_src_nets()]
-
- def get_vtn_src_names(self):
- return [x["name"] + "_" + x["net_id"] for x in self.get_vtn_src_nets()]
-
- def get_composable_networks(self):
- SUPPORTED_VTN_SERVCOMP_KINDS = ['VSG','PRIVATE']
-
- nets = []
- for slice in self.slices.all():
- for net in slice.networks.all():
- if (net.template.vtn_kind not in SUPPORTED_VTN_SERVCOMP_KINDS) or (net.owner != slice):
- continue
-
- if not net.controllernetworks.exists():
- continue
- nets.append(net)
- return nets
-
-
-class ServiceAttribute(PlCoreBase):
- name = models.CharField(help_text="Attribute Name", max_length=128)
- value = models.TextField(help_text="Attribute Value")
- service = models.ForeignKey(Service, related_name='serviceattributes',
- help_text="The Service this attribute is associated with")
-
-
-class ServiceRole(PlCoreBase):
- ROLE_CHOICES = (('admin', 'Admin'),)
- role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
-
- def __unicode__(self): return u'%s' % (self.role)
-
-
-class ServicePrivilege(PlCoreBase):
- user = models.ForeignKey('User', related_name='serviceprivileges')
- service = models.ForeignKey('Service', related_name='serviceprivileges')
- role = models.ForeignKey('ServiceRole', related_name='serviceprivileges')
-
- class Meta:
- unique_together = ('user', 'service', 'role')
-
- def __unicode__(self): return u'%s %s %s' % (
- self.service, self.user, self.role)
-
- def can_update(self, user):
- if not self.service.enabled:
- raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
- return self.service.can_update(user)
-
- def save(self, *args, **kwds):
- if not self.service.enabled:
- raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
- super(ServicePrivilege, self).save(*args, **kwds)
-
- def delete(self, *args, **kwds):
- if not self.service.enabled:
- raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
- super(ServicePrivilege, self).delete(*args, **kwds)
-
- @classmethod
- def select_by_user(cls, user):
- if user.is_admin:
- qs = cls.objects.all()
- else:
- qs = cls.objects.filter(user=user)
- return qs
-
-#Model that defines the information needed to enable monitoring agents of a service
-class ServiceMonitoringAgentInfo(PlCoreBase):
- name = models.CharField(help_text="Monitoring Agent Name", max_length=128)
- service = models.ForeignKey(Service, related_name='servicemonitoringagents', blank=True, null=True,
- help_text="The Service this attribute is associated with")
- target_uri = models.TextField(validators=[URLValidator()], help_text="Monitoring collector URI to be used by agents to publish the data")
-
-
-class TenantRoot(PlCoreBase, AttributeMixin):
- """ A tenantRoot is one of the things that can sit at the root of a chain
- of tenancy. This object represents a node.
- """
-
- KIND = "generic"
- kind = StrippedCharField(max_length=30, default=KIND)
- name = StrippedCharField(
- max_length=255, help_text="name", blank=True, null=True)
-
- service_specific_attribute = models.TextField(blank=True, null=True)
- service_specific_id = StrippedCharField(
- max_length=30, blank=True, null=True)
-
- def __init__(self, *args, **kwargs):
- # for subclasses, set the default kind appropriately
- self._meta.get_field("kind").default = self.KIND
- super(TenantRoot, self).__init__(*args, **kwargs)
-
- def __unicode__(self):
- if not self.name:
- return u"%s-tenant_root-#%s" % (str(self.kind), str(self.id))
- else:
- return self.name
-
- def can_update(self, user):
- return user.can_update_tenant_root(self, allow=['admin'])
-
- def get_subscribed_tenants(self, tenant_class):
- ids = self.subscribed_tenants.filter(kind=tenant_class.KIND)
- return tenant_class.objects.filter(id__in=ids)
-
- def get_newest_subscribed_tenant(self, kind):
- st = list(self.get_subscribed_tenants(kind))
- if not st:
- return None
- return sorted(st, key=attrgetter('id'))[0]
-
- @classmethod
- def get_tenant_objects(cls):
- return cls.objects.filter(kind=cls.KIND)
-
- @classmethod
- def get_tenant_objects_by_user(cls, user):
- return cls.select_by_user(user).filter(kind=cls.KIND)
-
- @classmethod
- def select_by_user(cls, user):
- if user.is_admin:
- return cls.objects.all()
- else:
- tr_ids = [
- trp.tenant_root.id for trp in TenantRootPrivilege.objects.filter(user=user)]
- return cls.objects.filter(id__in=tr_ids)
-
- # helper function to be used in subclasses that want to ensure
- # service_specific_id is unique
- def validate_unique_service_specific_id(self, none_okay=False):
- if not none_okay and (self.service_specific_id is None):
- raise XOSMissingField("subscriber_specific_id is None, and it's a required field", fields={
- "service_specific_id": "cannot be none"})
-
- if self.service_specific_id:
- conflicts = self.get_tenant_objects().filter(
- service_specific_id=self.service_specific_id)
- if self.pk:
- conflicts = conflicts.exclude(pk=self.pk)
- if conflicts:
- raise XOSDuplicateKey("service_specific_id %s already exists" % self.service_specific_id, fields={
- "service_specific_id": "duplicate key"})
-
-
-class Tenant(PlCoreBase, AttributeMixin):
- """ A tenant is a relationship between two entities, a subscriber and a
- provider. This object represents an edge.
-
- The subscriber can be a User, a Service, or a Tenant.
-
- The provider is always a Service.
-
- TODO: rename "Tenant" to "Tenancy"
- """
-
- CONNECTIVITY_CHOICES = (('public', 'Public'),
- ('private', 'Private'),
- ('private-unidirectional', 'Private Unidirectional'),
- ('na', 'Not Applicable'))
-
- # when subclassing a service, redefine KIND to describe the new service
- KIND = "generic"
-
- name = StrippedCharField(max_length=200, blank=True, null=True)
- kind = StrippedCharField(max_length=30, default=KIND)
- provider_service = models.ForeignKey(
- Service, related_name='provided_tenants')
-
- # The next four things are the various type of objects that can be subscribers of this Tenancy
- # relationship. One and only one can be used at a time.
- # XXX these should really be changed to GenericForeignKey
- subscriber_service = models.ForeignKey(
- Service, related_name='subscribed_tenants', blank=True, null=True)
- subscriber_tenant = models.ForeignKey(
- "Tenant", related_name='subscribed_tenants', blank=True, null=True)
- subscriber_user = models.ForeignKey(
- "User", related_name='subscribed_tenants', blank=True, null=True)
- subscriber_root = models.ForeignKey(
- "TenantRoot", related_name="subscribed_tenants", blank=True, null=True)
- subscriber_network = models.ForeignKey(
- "Network", related_name="subscribed_tenants", blank=True, null=True)
-
- # Service_specific_attribute and service_specific_id are opaque to XOS
- service_specific_id = StrippedCharField(
- max_length=30, blank=True, null=True)
- service_specific_attribute = models.TextField(blank=True, null=True)
-
- # Connect_method is only used by Coarse tenants
- connect_method = models.CharField(
- null=False, blank=False, max_length=30, choices=CONNECTIVITY_CHOICES, default="na")
-
- def __init__(self, *args, **kwargs):
- # for subclasses, set the default kind appropriately
- self._meta.get_field("kind").default = self.KIND
- super(Tenant, self).__init__(*args, **kwargs)
-
- def __unicode__(self):
- return u"%s-tenant-%s" % (str(self.kind), str(self.id))
-
- @classmethod
- def get_tenant_objects(cls):
- return cls.objects.filter(kind=cls.KIND)
-
- @classmethod
- def get_tenant_objects_by_user(cls, user):
- return cls.select_by_user(user).filter(kind=cls.KIND)
-
- @classmethod
- def get_deleted_tenant_objects(cls):
- return cls.deleted_objects.filter(kind=cls.KIND)
-
- @property
- def tenantattribute_dict(self):
- attrs = {}
- for attr in self.tenantattributes.all():
- attrs[attr.name] = attr.value
- return attrs
-
- # helper function to be used in subclasses that want to ensure
- # service_specific_id is unique
- def validate_unique_service_specific_id(self):
- if self.pk is None:
- if self.service_specific_id is None:
- raise XOSMissingField("subscriber_specific_id is None, and it's a required field", fields={
- "service_specific_id": "cannot be none"})
-
- conflicts = self.get_tenant_objects().filter(
- service_specific_id=self.service_specific_id)
- if conflicts:
- raise XOSDuplicateKey("service_specific_id %s already exists" % self.service_specific_id, fields={
- "service_specific_id": "duplicate key"})
-
- def save(self, *args, **kwargs):
- subCount = sum([1 for e in [self.subscriber_service, self.subscriber_tenant,
- self.subscriber_user, self.subscriber_root] if e is not None])
- if (subCount > 1):
- raise XOSConflictingField(
- "Only one of subscriber_service, subscriber_tenant, subscriber_user, subscriber_root should be set")
-
- super(Tenant, self).save(*args, **kwargs)
-
- def get_subscribed_tenants(self, tenant_class):
- ids = self.subscribed_tenants.filter(kind=tenant_class.KIND)
- return tenant_class.objects.filter(id__in=ids)
-
- def get_newest_subscribed_tenant(self, kind):
- st = list(self.get_subscribed_tenants(kind))
- if not st:
- return None
- return sorted(st, key=attrgetter('id'))[0]
-
-
-class Scheduler(object):
- # XOS Scheduler Abstract Base Class
- # Used to implement schedulers that pick which node to put instances on
-
- def __init__(self, slice):
- self.slice = slice
-
- def pick(self):
- # this method should return a tuple (node, parent)
- # node is the node to instantiate on
- # parent is for container_vm instances only, and is the VM that will
- # hold the container
-
- raise Exception("Abstract Base")
-
-
-class LeastLoadedNodeScheduler(Scheduler):
- # This scheduler always return the node with the fewest number of
- # instances.
-
- def __init__(self, slice, label=None):
- super(LeastLoadedNodeScheduler, self).__init__(slice)
- self.label = label
-
- def pick(self):
- from core.models import Node
-
- # start with all nodes
- nodes = Node.objects.all()
-
- # if a label is set, then filter by label
- if self.label:
- nodes = nodes.filter(nodelabels__name=self.label)
-
- # if slice.default_node is set, then filter by default_node
- if self.slice.default_node:
- nodes = nodes.filter(name = self.slice.default_node)
-
- # convert to list
- nodes = list(nodes)
-
- # sort so that we pick the least-loaded node
- nodes = sorted(nodes, key=lambda node: node.instances.all().count())
-
- if not nodes:
- raise Exception(
- "LeastLoadedNodeScheduler: No suitable nodes to pick from")
-
- # TODO: logic to filter nodes by which nodes are up, and which
- # nodes the slice can instantiate on.
-# nodes = sorted(nodes, key=lambda node: node.instances.all().count())
- return [nodes[0], None]
-
-
-class ContainerVmScheduler(Scheduler):
- # This scheduler picks a VM in the slice with the fewest containers inside
- # of it. If no VMs are suitable, then it creates a VM.
-
- MAX_VM_PER_CONTAINER = 10
-
- def __init__(self, slice):
- super(ContainerVmScheduler, self).__init__(slice)
-
- @property
- def image(self):
- from core.models import Image
-
- # If slice has default_image set then use it
- if self.slice.default_image:
- return self.slice.default_image
-
- raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
-
- def make_new_instance(self):
- from core.models import Instance, Flavor
-
- flavors = Flavor.objects.filter(name="m1.small")
- if not flavors:
- raise XOSConfigurationError("No m1.small flavor")
-
- (node, parent) = LeastLoadedNodeScheduler(self.slice).pick()
-
- instance = Instance(slice=self.slice,
- node=node,
- image=self.image,
- creator=self.slice.creator,
- deployment=node.site_deployment.deployment,
- flavor=flavors[0],
- isolation="vm",
- parent=parent)
- instance.save()
- # We rely on a special naming convention to identify the VMs that will
- # hole containers.
- instance.name = "%s-outer-%s" % (instance.slice.name, instance.id)
- instance.save()
- return instance
-
- def pick(self):
- from core.models import Instance, Flavor
-
- for vm in self.slice.instances.filter(isolation="vm"):
- avail_vms = []
- if (vm.name.startswith("%s-outer-" % self.slice.name)):
- container_count = Instance.objects.filter(parent=vm).count()
- if (container_count < self.MAX_VM_PER_CONTAINER):
- avail_vms.append((vm, container_count))
- # sort by least containers-per-vm
- avail_vms = sorted(avail_vms, key=lambda x: x[1])
- print "XXX", avail_vms
- if avail_vms:
- instance = avail_vms[0][0]
- return (instance.node, instance)
-
- instance = self.make_new_instance()
- return (instance.node, instance)
-
-
-class TenantWithContainer(Tenant):
- """ A tenant that manages an Instance
- Note: Should probably be called TenantWithInstance instead of TenantWithContainer
- """
-
- instance = models.ForeignKey("Instance", related_name='+', help_text="Instance used by this Tenant", null=True, blank=True)
- creator = models.ForeignKey("User", related_name='+', help_text="Creator of this Tenant", null=True, blank=True)
- external_hostname = StrippedCharField(max_length=30, help_text="External host name", null=True, blank=True) # is this still used?
- external_container = StrippedCharField(max_length=30, help_text="External host name", null=True, blank=True) # is this still used?
-
- def __init__(self, *args, **kwargs):
- super(TenantWithContainer, self).__init__(*args, **kwargs)
-
- # vSG service relies on knowing when instance id has changed
- self.orig_instance_id = self.get_attribute("instance_id")
-
- # vSG service relies on instance_id attribute
- def get_attribute(self, name, default=None):
- if name=="instance_id":
- if self.instance:
- return self.instance.id
- else:
- return None
- else:
- return super(TenantWithContainer, self).get_attribute(name, default)
-
- # Services may wish to override the image() function to return different
- # images based on criteria in the tenant object. For example,
- # if (self.has_feature_A):
- # return Instance.object.get(name="image_with_feature_a")
- # elif (self.has_feature_B):
- # return Instance.object.get(name="image_with_feature_b")
- # else:
- # return super(MyTenantClass,self).image()
-
- @property
- def image(self):
- from core.models import Image
- # Implement the logic here to pick the image that should be used when
- # instantiating the VM that will hold the container.
-
- slice = self.provider_service.slices.all()
- if not slice:
- raise XOSProgrammingError("provider service has no slice")
- slice = slice[0]
-
- # If slice has default_image set then use it
- if slice.default_image:
- return slice.default_image
-
- raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
-
- def save_instance(self, instance):
- # Override this function to do custom pre-save or post-save processing,
- # such as creating ports for containers.
- instance.save()
-
- def pick_least_loaded_instance_in_slice(self, slices, image):
- for slice in slices:
- if slice.instances.all().count() > 0:
- for instance in slice.instances.all():
- if instance.image != image:
- continue
- # Pick the first instance that has lesser than 5 tenants
- if self.count_of_tenants_of_an_instance(instance) < 5:
- return instance
- return None
-
- # TODO: Ideally the tenant count for an instance should be maintained using a
- # many-to-one relationship attribute, however this model being proxy, it does
- # not permit any new attributes to be defined. Find if any better solutions
- def count_of_tenants_of_an_instance(self, instance):
- tenant_count = 0
- for tenant in self.get_tenant_objects().all():
- if tenant.get_attribute("instance_id", None) == instance.id:
- tenant_count += 1
- return tenant_count
-
- def manage_container(self):
- from core.models import Instance, Flavor
-
- if self.deleted:
- return
-
- if (self.instance is not None) and (self.instance.image != self.image):
- self.instance.delete()
- self.instance = None
-
- if self.instance is None:
- if not self.provider_service.slices.count():
- raise XOSConfigurationError("The service has no slices")
-
- new_instance_created = False
- instance = None
- if self.get_attribute("use_same_instance_for_multiple_tenants", default=False):
- # Find if any existing instances can be used for this tenant
- slices = self.provider_service.slices.all()
- instance = self.pick_least_loaded_instance_in_slice(slices, self.image)
-
- if not instance:
- slice = self.provider_service.slices.all()[0]
-
- flavor = slice.default_flavor
- if not flavor:
- flavors = Flavor.objects.filter(name="m1.small")
- if not flavors:
- raise XOSConfigurationError("No m1.small flavor")
- flavor = flavors[0]
-
- if slice.default_isolation == "container_vm":
- (node, parent) = ContainerVmScheduler(slice).pick()
- else:
- (node, parent) = LeastLoadedNodeScheduler(slice).pick()
-
- instance = Instance(slice=slice,
- node=node,
- image=self.image,
- creator=self.creator,
- deployment=node.site_deployment.deployment,
- flavor=flavor,
- isolation=slice.default_isolation,
- parent=parent)
- self.save_instance(instance)
- new_instance_created = True
-
- try:
- self.instance = instance
- super(TenantWithContainer, self).save()
- except:
- if new_instance_created:
- instance.delete()
- raise
-
- def cleanup_container(self):
- if self.instance:
- if self.get_attribute("use_same_instance_for_multiple_tenants", default=False):
- # Delete the instance only if this is last tenant in that
- # instance
- tenant_count = self.count_of_tenants_of_an_instance(
- self.instance)
- if tenant_count == 0:
- self.instance.delete()
- else:
- self.instance.delete()
- self.instance = None
-
- def save(self, *args, **kwargs):
- if (not self.creator) and (hasattr(self, "caller")) and (self.caller):
- self.creator = self.caller
- super(TenantWithContainer, self).save(*args, **kwargs)
-
-
-class ServiceDependency(Tenant):
- KIND = COARSE_KIND
-
- def save(self, *args, **kwargs):
- if (not self.subscriber_service):
- raise XOSValidationError("subscriber_service cannot be null")
- if (self.subscriber_tenant or self.subscriber_user):
- raise XOSValidationError(
- "subscriber_tenant and subscriber_user must be null")
-
- super(ServiceDependency, self).save()
-
-
-class TenantAttribute(PlCoreBase):
- name = models.CharField(help_text="Attribute Name", max_length=128)
- value = models.TextField(help_text="Attribute Value")
- tenant = models.ForeignKey(Tenant, related_name='tenantattributes',
- help_text="The Tenant this attribute is associated with")
-
- def __unicode__(self): return u'%s-%s' % (self.name, self.id)
-
-
-class TenantRootRole(PlCoreBase):
- ROLE_CHOICES = (('admin', 'Admin'), ('access', 'Access'))
-
- role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
-
- def __unicode__(self): return u'%s' % (self.role)
-
-
-class TenantRootPrivilege(PlCoreBase):
- user = models.ForeignKey('User', related_name="tenant_root_privileges")
- tenant_root = models.ForeignKey(
- 'TenantRoot', related_name="tenant_root_privileges")
- role = models.ForeignKey(
- 'TenantRootRole', related_name="tenant_root_privileges")
-
- class Meta:
- unique_together = ('user', 'tenant_root', 'role')
-
- def __unicode__(self): return u'%s %s %s' % (
- self.tenant_root, self.user, self.role)
-
- def save(self, *args, **kwds):
- if not self.user.is_active:
- raise PermissionDenied, "Cannot modify role(s) of a disabled user"
- super(TenantRootPrivilege, self).save(*args, **kwds)
-
- def can_update(self, user):
- return user.can_update_tenant_root_privilege(self)
-
- @classmethod
- def select_by_user(cls, user):
- if user.is_admin:
- return cls.objects.all()
- else:
- # User can see his own privilege
- trp_ids = [trp.id for trp in cls.objects.filter(user=user)]
-
- # A slice admin can see the SlicePrivileges for his Slice
- for priv in cls.objects.filter(user=user, role__role="admin"):
- trp_ids.extend(
- [trp.id for trp in cls.objects.filter(tenant_root=priv.tenant_root)])
-
- return cls.objects.filter(id__in=trp_ids)
-
-
-class TenantRole(PlCoreBase):
- """A TenantRole option."""
- ROLE_CHOICES = (('admin', 'Admin'), ('access', 'Access'))
- role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
-
- def __unicode__(self): return u'%s' % (self.role)
-
-
-class TenantPrivilege(PlCoreBase):
- """"A TenantPrivilege which defines how users can access a particular Tenant.
-
- Attributes:
- id (models.AutoField): The ID of the privilege.
- user (models.ForeignKey): A Foreign Key to the a User.
- tenant (models.ForeignKey): A ForeignKey to the Tenant.
- role (models.ForeignKey): A ForeignKey to the TenantRole.
- """
- id = models.AutoField(primary_key=True)
- user = models.ForeignKey('User', related_name="tenantprivileges")
- tenant = models.ForeignKey('Tenant', related_name="tenantprivileges")
- role = models.ForeignKey('TenantRole', related_name="tenantprivileges")
-
- def __unicode__(self): return u'%s %s %s' % (
- self.tenant, self.user, self.role)
-
- def save(self, *args, **kwds):
- if not self.user.is_active:
- raise PermissionDenied, "Cannot modify role(s) of a disabled user"
- super(TenantPrivilege, self).save(*args, **kwds)
-
- def can_update(self, user):
- return user.can_update_tenant_privilege(self)
-
- @classmethod
- def select_by_user(cls, user):
- if user.is_admin:
- return cls.objects.all()
- else:
- # User can see his own privilege
- trp_ids = [trp.id for trp in cls.objects.filter(user=user)]
-
- # A tenant admin can see the TenantPrivileges for their Tenants
- for priv in cls.objects.filter(user=user, role__role="admin"):
- trp_ids.extend(
- [trp.id for trp in cls.objects.filter(tenant=priv.tenant)])
-
- return cls.objects.filter(id__in=trp_ids)
diff --git a/xos/core/models/service.xproto b/xos/core/models/service.xproto
new file mode 100644
index 0000000..e3ba5bb
--- /dev/null
+++ b/xos/core/models/service.xproto
@@ -0,0 +1,17 @@
+
+
+message Service (PlCoreBase,AttributeMixin){
+ optional string description = 1 [help_text = "Description of Service", max_length = 254, null = True, db_index = False, blank = True];
+ required bool enabled = 2 [default = True, null = False, db_index = False, blank = True];
+ required string kind = 3 [default = "generic", max_length = 30, content_type = "stripped", blank = False, help_text = "Kind of service", null = False, db_index = False];
+ required string name = 4 [max_length = 30, content_type = "stripped", blank = False, help_text = "Service Name", null = False, db_index = False];
+ optional string versionNumber = 5 [max_length = 30, content_type = "stripped", blank = True, help_text = "Version of Service Definition", null = True, db_index = False];
+ required bool published = 6 [default = True, null = False, db_index = False, blank = True];
+ optional string view_url = 7 [db_index = False, max_length = 1024, null = True, content_type = "stripped", blank = True];
+ optional string icon_url = 8 [db_index = False, max_length = 1024, null = True, content_type = "stripped", blank = True];
+ optional string public_key = 9 [help_text = "Public key string", max_length = 1024, null = True, db_index = False, blank = True];
+ optional string private_key_fn = 10 [db_index = False, max_length = 1024, null = True, content_type = "stripped", blank = True];
+ optional string service_specific_id = 11 [db_index = False, max_length = 30, null = True, content_type = "stripped", blank = True];
+ optional string service_specific_attribute = 12 [db_index = False, null = True, blank = True];
+ optional manytoone controller->ServiceController:services = 13 [help_text = "The Service Controller this Service uses", null = True, db_index = True, blank = True];
+}
diff --git a/xos/core/models/service_header.py b/xos/core/models/service_header.py
new file mode 120000
index 0000000..a90002d
--- /dev/null
+++ b/xos/core/models/service_header.py
@@ -0,0 +1 @@
+attic/service_header.py
\ No newline at end of file
diff --git a/xos/core/models/serviceattribute.xproto b/xos/core/models/serviceattribute.xproto
new file mode 100644
index 0000000..d333aa2
--- /dev/null
+++ b/xos/core/models/serviceattribute.xproto
@@ -0,0 +1,7 @@
+
+
+message ServiceAttribute (PlCoreBase){
+ required string name = 1 [help_text = "Attribute Name", max_length = 128, null = False, db_index = False, blank = False];
+ required string value = 2 [help_text = "Attribute Value", null = False, db_index = False, blank = False];
+ required manytoone service->Service:serviceattributes = 3 [help_text = "The Service this attribute is associated with", null = False, db_index = True, blank = False];
+}
diff --git a/xos/core/models/serviceclass.py b/xos/core/models/serviceclass.py
deleted file mode 100644
index a51b476..0000000
--- a/xos/core/models/serviceclass.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase
-from core.models.plcorebase import StrippedCharField
-
-def get_default_serviceclass():
- try:
- return ServiceClass.objects.get(name="Best Effort")
- except ServiceClass.DoesNotExist:
- return None
-
-class ServiceClass(PlCoreBase):
- name = StrippedCharField(max_length=32)
- description = StrippedCharField(max_length=255)
- commitment = models.IntegerField(default=365)
- membershipFee = models.IntegerField(default=0)
- membershipFeeMonths = models.IntegerField(default=12)
- upgradeRequiresApproval = models.BooleanField(default=False)
- upgradeFrom = models.ManyToManyField('self', blank=True)
-
- class Meta(PlCoreBase.Meta):
- verbose_name_plural = "Service classes"
-
- def __unicode__(self): return u'%s' % (self.name)
-
- def save_by_user(self, user, *args, **kwds):
- if self.can_update(user):
- super(ServiceClass, self).save(*args, **kwds)
diff --git a/xos/core/models/serviceclass.xproto b/xos/core/models/serviceclass.xproto
new file mode 100644
index 0000000..9f1e4cf
--- /dev/null
+++ b/xos/core/models/serviceclass.xproto
@@ -0,0 +1,11 @@
+
+
+message ServiceClass (PlCoreBase){
+ required string name = 1 [db_index = False, max_length = 32, null = False, content_type = "stripped", blank = False];
+ required string description = 2 [db_index = False, max_length = 255, null = False, content_type = "stripped", blank = False];
+ required int32 commitment = 3 [default = 365, null = False, db_index = False, blank = False];
+ required int32 membershipFee = 4 [default = 0, null = False, db_index = False, blank = False];
+ required int32 membershipFeeMonths = 5 [default = 12, null = False, db_index = False, blank = False];
+ required bool upgradeRequiresApproval = 6 [default = False, null = False, db_index = False, blank = True];
+ required manytomany upgradeFrom->ServiceClass/ServiceClass_upgradeFrom:upgradeFrom_rel_+ = 7 [db_index = False, null = False, blank = True];
+}
diff --git a/xos/core/models/servicecontroller.xproto b/xos/core/models/servicecontroller.xproto
new file mode 100644
index 0000000..aa4baaa
--- /dev/null
+++ b/xos/core/models/servicecontroller.xproto
@@ -0,0 +1,10 @@
+
+
+message ServiceController (LoadableModule){
+ optional string synchronizer_run = 1 [max_length = 1024, content_type = "stripped", blank = True, help_text = "synchronizer run command", null = True, db_index = False];
+ optional string synchronizer_config = 2 [max_length = 1024, content_type = "stripped", blank = True, help_text = "synchronizer config file", null = True, db_index = False];
+ optional string image = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "docker image name", null = True, db_index = False];
+ required bool no_start = 4 [help_text = "Do not start the Synchronizer", default = False, null = False, db_index = False, blank = True];
+ required bool no_build = 5 [help_text = "Do not build the Synchronizer container", default = False, null = False, db_index = False, blank = True];
+ required bool no_deploy = 6 [help_text = "Do not add synchronizer container to onboarding-docker-compose", default = False, null = False, db_index = False, blank = True];
+}
diff --git a/xos/core/models/servicedependency.xproto b/xos/core/models/servicedependency.xproto
new file mode 100644
index 0000000..09248fe
--- /dev/null
+++ b/xos/core/models/servicedependency.xproto
@@ -0,0 +1,4 @@
+
+
+message ServiceDependency (Tenant){
+}
diff --git a/xos/core/models/servicemonitoringagentinfo.xproto b/xos/core/models/servicemonitoringagentinfo.xproto
new file mode 100644
index 0000000..4a4e466
--- /dev/null
+++ b/xos/core/models/servicemonitoringagentinfo.xproto
@@ -0,0 +1,7 @@
+
+
+message ServiceMonitoringAgentInfo (PlCoreBase){
+ required string name = 1 [help_text = "Monitoring Agent Name", max_length = 128, null = False, db_index = False, blank = False];
+ optional manytoone service->Service:servicemonitoringagents = 2 [help_text = "The Service this attribute is associated with", null = True, db_index = True, blank = True];
+ required string target_uri = 3 [help_text = "Monitoring collector URI to be used by agents to publish the data", null = False, db_index = False, blank = False];
+}
diff --git a/xos/core/models/serviceprivilege.xproto b/xos/core/models/serviceprivilege.xproto
new file mode 100644
index 0000000..f88acef
--- /dev/null
+++ b/xos/core/models/serviceprivilege.xproto
@@ -0,0 +1,7 @@
+
+
+message ServicePrivilege (PlCoreBase){
+ required manytoone user->User:serviceprivileges = 1 [db_index = True, null = False, blank = False];
+ required manytoone service->Service:serviceprivileges = 2 [db_index = True, null = False, blank = False];
+ required manytoone role->ServiceRole:serviceprivileges = 3 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/serviceresource.py b/xos/core/models/serviceresource.py
deleted file mode 100644
index 416627a..0000000
--- a/xos/core/models/serviceresource.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase
-from core.models import ServiceClass
-from core.models.plcorebase import StrippedCharField
-
-# Create your models here.
-
-class ServiceResource(PlCoreBase):
- serviceClass = models.ForeignKey(ServiceClass, related_name = "serviceresources")
- name = StrippedCharField(max_length=32)
- maxUnitsDeployment = models.IntegerField(default=1)
- maxUnitsNode = models.IntegerField(default=1)
- maxDuration = models.IntegerField(default=1)
- bucketInRate = models.IntegerField(default=0)
- bucketMaxSize = models.IntegerField(default=0)
- cost = models.IntegerField(default=0)
- calendarReservable = models.BooleanField(default=True)
-
- def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/serviceresource.xproto b/xos/core/models/serviceresource.xproto
new file mode 100644
index 0000000..46cb5c4
--- /dev/null
+++ b/xos/core/models/serviceresource.xproto
@@ -0,0 +1,13 @@
+
+
+message ServiceResource (PlCoreBase){
+ required manytoone serviceClass->ServiceClass:serviceresources = 1 [db_index = True, null = False, blank = False];
+ required string name = 2 [db_index = False, max_length = 32, null = False, content_type = "stripped", blank = False];
+ required int32 maxUnitsDeployment = 3 [default = 1, null = False, db_index = False, blank = False];
+ required int32 maxUnitsNode = 4 [default = 1, null = False, db_index = False, blank = False];
+ required int32 maxDuration = 5 [default = 1, null = False, db_index = False, blank = False];
+ required int32 bucketInRate = 6 [default = 0, null = False, db_index = False, blank = False];
+ required int32 bucketMaxSize = 7 [default = 0, null = False, db_index = False, blank = False];
+ required int32 cost = 8 [default = 0, null = False, db_index = False, blank = False];
+ required bool calendarReservable = 9 [default = True, null = False, db_index = False, blank = True];
+}
diff --git a/xos/core/models/servicerole.xproto b/xos/core/models/servicerole.xproto
new file mode 100644
index 0000000..3661df4
--- /dev/null
+++ b/xos/core/models/servicerole.xproto
@@ -0,0 +1,5 @@
+
+
+message ServiceRole (PlCoreBase){
+ required string role = 1 [choices = "(('admin', 'Admin'),)", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+}
diff --git a/xos/core/models/site.py b/xos/core/models/site.py
deleted file mode 100644
index 069fec9..0000000
--- a/xos/core/models/site.py
+++ /dev/null
@@ -1,342 +0,0 @@
-import os
-from django.db import models
-from django.db.models import Q
-from django.contrib.contenttypes.fields import GenericRelation
-from django.core.exceptions import PermissionDenied
-# from geoposition.fields import GeopositionField
-from core.models import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager,ModelLink
-from core.models import Tag
-from core.models.plcorebase import StrippedCharField
-from core.acl import AccessControlList
-from xos.config import Config
-
-config = Config()
-
-class ControllerLinkDeletionManager(PlCoreBaseDeletionManager):
- def get_queryset(self):
- parent=super(ControllerLinkDeletionManager, self)
- try:
- backend_type = config.observer_backend_type
- except AttributeError:
- backend_type = None
-
- parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
- if (backend_type):
- return parent_queryset.filter(Q(controller__backend_type=backend_type))
- else:
- return parent_queryset
-
- # deprecated in django 1.7 in favor of get_queryset().
- def get_query_set(self):
- return self.get_queryset()
-
-
-class ControllerDeletionManager(PlCoreBaseDeletionManager):
- def get_queryset(self):
- parent=super(ControllerDeletionManager, self)
-
- try:
- backend_type = config.observer_backend_type
- except AttributeError:
- backend_type = None
-
- parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
-
- if backend_type:
- return parent_queryset.filter(Q(backend_type=backend_type))
- else:
- return parent_queryset
-
- # deprecated in django 1.7 in favor of get_queryset().
- def get_query_set(self):
- return self.get_queryset()
-
-class ControllerLinkManager(PlCoreBaseManager):
- def get_queryset(self):
- parent=super(ControllerLinkManager, self)
-
- try:
- backend_type = config.observer_backend_type
- except AttributeError:
- backend_type = None
-
- parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
-
- if backend_type:
- return parent_queryset.filter(Q(controller__backend_type=backend_type))
- else:
- return parent_queryset
-
- # deprecated in django 1.7 in favor of get_queryset().
- def get_query_set(self):
- return self.get_queryset()
-
-
-class ControllerManager(PlCoreBaseManager):
- def get_queryset(self):
- parent=super(ControllerManager, self)
-
- try:
- backend_type = config.observer_backend_type
- except AttributeError:
- backend_type = None
-
- parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
-
- if backend_type:
- return parent_queryset.filter(Q(backend_type=backend_type))
- else:
- return parent_queryset
-
- # deprecated in django 1.7 in favor of get_queryset().
- def get_query_set(self):
- return self.get_queryset()
-
-class Site(PlCoreBase):
- """
- A logical grouping of Nodes that are co-located at the same geographic location, which also typically corresponds to the Nodes' location in the physical network.
- """
- name = StrippedCharField(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")
- hosts_nodes = models.BooleanField(default=True, help_text="Indicates whether or not the site host nodes")
- hosts_users = models.BooleanField(default=True, help_text="Indicates whether or not the site manages user accounts")
- # location = GeopositionField()
- longitude = models.FloatField(null=True, blank=True)
- latitude = models.FloatField(null=True, blank=True)
- login_base = StrippedCharField(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 = StrippedCharField(max_length=80)
-
- #deployments = models.ManyToManyField('Deployment', blank=True, related_name='sites')
- deployments = models.ManyToManyField('Deployment', through='SiteDeployment', blank=True, help_text="Select which sites are allowed to host nodes in this deployment", related_name='sites')
- tags = GenericRelation(Tag)
-
-
- def __unicode__(self): return u'%s' % (self.name)
-
- def can_update(self, user):
- return user.can_update_site(self, allow=['pi'])
-
-class SiteRole(PlCoreBase):
-
- ROLE_CHOICES = (('admin','Admin'),('pi','PI'),('tech','Tech'),('billing','Billing'))
- role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
-
- def __unicode__(self): return u'%s' % (self.role)
-
-class SitePrivilege(PlCoreBase):
-
- user = models.ForeignKey('User', related_name='siteprivileges')
- site = models.ForeignKey('Site', related_name='siteprivileges')
- role = models.ForeignKey('SiteRole',related_name='siteprivileges')
-
- xos_links = [ModelLink(Site,'site'),ModelLink('User','user'),ModelLink('Role','role')]
-
- def __unicode__(self): return u'%s %s %s' % (self.site, self.user, self.role)
-
- def save(self, *args, **kwds):
- if not self.user.is_active:
- raise PermissionDenied, "Cannot modify role(s) of a disabled user"
- super(SitePrivilege, self).save(*args, **kwds)
-
- def delete(self, *args, **kwds):
- super(SitePrivilege, self).delete(*args, **kwds)
-
- def can_update(self, user):
- return user.can_update_site(self, allow=['pi'])
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = SitePrivilege.objects.all()
- else:
- sp_ids = [sp.id for sp in SitePrivilege.objects.filter(user=user)]
- qs = SitePrivilege.objects.filter(id__in=sp_ids)
- return qs
-
-class Deployment(PlCoreBase):
- #objects = Controllermanager()
- #deleted_objects = DeploymentDeletionManager()
- name = StrippedCharField(max_length=200, unique=True, help_text="Name of the Deployment")
- #admin_user = StrippedCharField(max_length=200, null=True, blank=True, help_text="Username of an admin user at this deployment")
- #admin_password = StrippedCharField(max_length=200, null=True, blank=True, help_text="Password of theadmin user at this deployment")
- #admin_tenant = StrippedCharField(max_length=200, null=True, blank=True, help_text="Name of the tenant the admin user belongs to")
- #auth_url = StrippedCharField(max_length=200, null=True, blank=True, help_text="Auth url for the deployment")
- #backend_type = StrippedCharField(max_length=200, null=True, blank=True, help_text="Type of deployment, e.g. EC2, OpenStack, or OpenStack version")
- #availability_zone = StrippedCharField(max_length=200, null=True, blank=True, help_text="OpenStack availability zone")
-
- # smbaker: the default of 'allow all' is intended for evolutions of existing
- # deployments. When new deployments are created via the GUI, they are
- # given a default of 'allow site <site_of_creator>'
- accessControl = models.TextField(max_length=200, blank=False, null=False, default="allow all",
- help_text="Access control list that specifies which sites/users may use nodes in this deployment")
- def __init__(self, *args, **kwargs):
- super(Deployment, self).__init__(*args, **kwargs)
- self.no_sync=True
-
- def get_acl(self):
- return AccessControlList(self.accessControl)
-
- def test_acl(self, slice=None, user=None):
- potential_users=[]
-
- if user:
- potential_users.append(user)
-
- if slice:
- potential_users.append(slice.creator)
- for priv in slice.sliceprivileges.all():
- if priv.user not in potential_users:
- potential_users.append(priv.user)
-
- acl = self.get_acl()
- for user in potential_users:
- if acl.test(user) == "allow":
- return True
-
- return False
-
- @staticmethod
- def select_by_acl(user):
- ids = []
- for deployment in Deployment.objects.all():
- acl = deployment.get_acl()
- if acl.test(user) == "allow":
- ids.append(deployment.id)
-
- return Deployment.objects.filter(id__in=ids)
-
- def can_update(self, user):
- return user.can_update_deployment(self)
-
- def __unicode__(self): return u'%s' % (self.name)
-
-class DeploymentRole(PlCoreBase):
- #objects = DeploymentLinkManager()
- #deleted_objects = DeploymentLinkDeletionManager()
- ROLE_CHOICES = (('admin','Admin'),)
- role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
-
- def __unicode__(self): return u'%s' % (self.role)
-
-class DeploymentPrivilege(PlCoreBase):
- #objects = DeploymentLinkManager()
- #deleted_objects = DeploymentLinkDeletionManager()
-
- user = models.ForeignKey('User', related_name='deploymentprivileges')
- deployment = models.ForeignKey('Deployment', related_name='deploymentprivileges')
- role = models.ForeignKey('DeploymentRole',related_name='deploymentprivileges')
-
- xos_links = [ModelLink(Deployment,'deployment'),ModelLink('User','user'),ModelLink('Role','role')]
-
- class Meta:
- unique_together = ('user', 'deployment', 'role')
-
- def __unicode__(self): return u'%s %s %s' % (self.deployment, self.user, self.role)
-
- def can_update(self, user):
- return user.can_update_deployment(self)
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = DeploymentPrivilege.objects.all()
- else:
- dpriv_ids = [dp.id for dp in DeploymentPrivilege.objects.filter(user=user)]
- qs = DeploymentPrivilege.objects.filter(id__in=dpriv_ids)
- return qs
-
-class ControllerRole(PlCoreBase):
- #objects = ControllerLinkManager()
- #deleted_objects = ControllerLinkDeletionManager()
-
- ROLE_CHOICES = (('admin','Admin'),)
- role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
-
- def __unicode__(self): return u'%s' % (self.role)
-
-class Controller(PlCoreBase):
-
- objects = ControllerManager()
- deleted_objects = ControllerDeletionManager()
-
- name = StrippedCharField(max_length=200, unique=True, help_text="Name of the Controller")
- backend_type = StrippedCharField(max_length=200, help_text="Type of compute controller, e.g. EC2, OpenStack, or OpenStack version")
- version = StrippedCharField(max_length=200, help_text="Controller version")
- auth_url = StrippedCharField(max_length=200, null=True, blank=True, help_text="Auth url for the compute controller")
- admin_user = StrippedCharField(max_length=200, null=True, blank=True, help_text="Username of an admin user at this controller")
- admin_password = StrippedCharField(max_length=200, null=True, blank=True, help_text="Password of theadmin user at this controller")
- admin_tenant = StrippedCharField(max_length=200, null=True, blank=True, help_text="Name of the tenant the admin user belongs to")
- domain = StrippedCharField(max_length=200, null=True, blank=True, help_text="Name of the domain this controller belongs to")
- rabbit_host = StrippedCharField(max_length=200, null=True, blank=True, help_text="IP address of rabbitmq server at this controller")
- rabbit_user = StrippedCharField(max_length=200, null=True, blank=True, help_text="Username of rabbitmq server at this controller")
- rabbit_password = StrippedCharField(max_length=200, null=True, blank=True, help_text="Password of rabbitmq server at this controller")
- deployment = models.ForeignKey(Deployment,related_name='controllerdeployments')
-
- xos_links = [ModelLink(Deployment, via='deployment')]
-
- def __init__(self, *args, **kwargs):
- super(Controller, self).__init__(*args, **kwargs)
- self.no_sync=True
-
- def __unicode__(self): return u'%s %s %s' % (self.name, self.backend_type, self.version)
-
- @property
- def auth_url_v3(self):
- if self.auth_url and self.auth_url[-1] == '/':
- return '{}/v3/'.format('/'.join(self.auth_url.split('/')[:-2]))
- else:
- return '{}/v3/'.format('/'.join(self.auth_url.split('/')[:-1]))
-
- @staticmethod
- def select_by_user(user):
-
- if user.is_admin:
- qs = Controller.objects.all()
- else:
- deployments = [dp.deployment for dp in DeploymentPrivilege.objects.filter(user=user, role__role__in=['Admin', 'admin'])]
- qs = Controller.objects.filter(deployment__in=deployments)
- return qs
-
-class SiteDeployment(PlCoreBase):
- objects = ControllerLinkManager()
- deleted_objects = ControllerLinkDeletionManager()
-
- site = models.ForeignKey(Site,related_name='sitedeployments')
- deployment = models.ForeignKey(Deployment,related_name='sitedeployments')
- 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")
-
- xos_links = [ModelLink(Site,'site'),ModelLink(Deployment,'deployment'),ModelLink(Controller,'controller')]
-
- class Meta:
- unique_together = ('site', 'deployment', 'controller')
-
- def __unicode__(self): return u'%s %s' % (self.deployment, self.site)
-
-class ControllerSite(PlCoreBase):
-
- 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")
-
- xos_links = [ModelLink(Controller,via='controller'),ModelLink(Site,via='site')]
-
- def delete(self, *args, **kwds):
- super(ControllerSite, self).delete(*args, **kwds)
-
-
- class Meta:
- unique_together = ('site', 'controller')
-
-class Diag(PlCoreBase):
- name = StrippedCharField(max_length=200, help_text="Name of the synchronizer")
-
- @property
- def enacted(self):
- return None
-
- @enacted.setter
- def enacted(self, value):
- pass # Ignore sets, Diag objects are always pending.
diff --git a/xos/core/models/site.xproto b/xos/core/models/site.xproto
new file mode 100644
index 0000000..fe3f9f5
--- /dev/null
+++ b/xos/core/models/site.xproto
@@ -0,0 +1,16 @@
+
+
+message Site (PlCoreBase){
+ required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Name for this Site", null = False, db_index = False];
+ optional string site_url = 2 [max_length = 512, content_type = "url", blank = True, help_text = "Site's Home URL Page", null = True, db_index = False];
+ required bool enabled = 3 [help_text = "Status for this Site", default = True, null = False, db_index = False, blank = True];
+ required bool hosts_nodes = 4 [help_text = "Indicates whether or not the site host nodes", default = True, null = False, db_index = False, blank = True];
+ required bool hosts_users = 5 [help_text = "Indicates whether or not the site manages user accounts", default = True, null = False, db_index = False, blank = True];
+ optional float longitude = 6 [db_index = False, null = True, blank = True];
+ optional float latitude = 7 [db_index = False, null = True, blank = True];
+ required string login_base = 8 [max_length = 50, content_type = "stripped", blank = False, help_text = "Prefix for Slices associated with this Site", null = False, db_index = False];
+ required bool is_public = 9 [help_text = "Indicates the visibility of this site to other members", default = True, null = False, db_index = False, blank = True];
+ required string abbreviated_name = 10 [db_index = False, max_length = 80, null = False, content_type = "stripped", blank = False];
+ required manytomany deployments->Deployment/SiteDeployment:sites = 11 [help_text = "Select which sites are allowed to host nodes in this deployment", null = False, db_index = False, blank = True];
+ required manytomany tags->Tag = 12 [db_index = False, null = False, blank = True];
+}
diff --git a/xos/core/models/sitecredential.xproto b/xos/core/models/sitecredential.xproto
new file mode 100644
index 0000000..f6a3fec
--- /dev/null
+++ b/xos/core/models/sitecredential.xproto
@@ -0,0 +1,8 @@
+
+
+message SiteCredential (PlCoreBase){
+ required manytoone site->Site:sitecredentials = 1 [help_text = "The User this credential is associated with", null = False, db_index = True, blank = False];
+ required string name = 2 [help_text = "The credential type, e.g. ec2", max_length = 128, null = False, db_index = True, blank = False];
+ required string key_id = 3 [max_length = 1024, content_type = "stripped", blank = False, help_text = "The backend id of this credential", null = False, db_index = False];
+ required string enc_value = 4 [help_text = "The key value of this credential", max_length = 1024, null = False, db_index = False, blank = False];
+}
diff --git a/xos/core/models/sitedeployment.xproto b/xos/core/models/sitedeployment.xproto
new file mode 100644
index 0000000..ae12aa1
--- /dev/null
+++ b/xos/core/models/sitedeployment.xproto
@@ -0,0 +1,8 @@
+
+
+message SiteDeployment (PlCoreBase){
+ required manytoone site->Site:sitedeployments = 1 [db_index = True, null = False, blank = False];
+ required manytoone deployment->Deployment:sitedeployments = 2 [db_index = True, null = False, blank = False];
+ optional manytoone controller->Controller:sitedeployments = 3 [db_index = True, null = True, blank = True];
+ optional string availability_zone = 4 [max_length = 200, content_type = "stripped", blank = True, help_text = "OpenStack availability zone", null = True, db_index = False];
+}
diff --git a/xos/core/models/siteprivilege.xproto b/xos/core/models/siteprivilege.xproto
new file mode 100644
index 0000000..c63677a
--- /dev/null
+++ b/xos/core/models/siteprivilege.xproto
@@ -0,0 +1,7 @@
+
+
+message SitePrivilege (PlCoreBase){
+ required manytoone user->User:siteprivileges = 1 [db_index = True, null = False, blank = False];
+ required manytoone site->Site:siteprivileges = 2 [db_index = True, null = False, blank = False];
+ required manytoone role->SiteRole:siteprivileges = 3 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/siterole.xproto b/xos/core/models/siterole.xproto
new file mode 100644
index 0000000..a42ef5c
--- /dev/null
+++ b/xos/core/models/siterole.xproto
@@ -0,0 +1,5 @@
+
+
+message SiteRole (PlCoreBase){
+ required string role = 1 [choices = "(('admin', 'Admin'), ('pi', 'PI'), ('tech', 'Tech'), ('billing', 'Billing'))", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+}
diff --git a/xos/core/models/slice.py b/xos/core/models/slice.py
deleted file mode 100644
index 183241f..0000000
--- a/xos/core/models/slice.py
+++ /dev/null
@@ -1,217 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase,ModelLink
-from core.models import Site
-from core.models.site import SitePrivilege
-from core.models import User
-from core.models import Role
-from core.models import Controller,ControllerLinkManager,ControllerLinkDeletionManager
-from core.models import ServiceClass
-#from core.models.serviceclass import get_default_serviceclass
-from core.models import Tag
-from django.contrib.contenttypes.fields import GenericRelation
-from core.models import Service
-from core.models import Controller
-from core.models.node import Node
-from core.models import Flavor, Image
-from core.models.plcorebase import StrippedCharField
-from django.core.exceptions import PermissionDenied, ValidationError
-from xos.exceptions import *
-
-# Create your models here.
-
-class Slice(PlCoreBase):
- ISOLATION_CHOICES = (('vm', 'Virtual Machine'), ('container', 'Container'), ('container_vm', 'Container In VM'))
- NETWORK_CHOICES = ((None, 'Default'), ('host', 'Host'), ('bridged', 'Bridged'), ('noauto', 'No Automatic Networks'))
-
- name = StrippedCharField(unique=True, help_text="The Name of the Slice", max_length=80)
- enabled = models.BooleanField(default=True, help_text="Status for this Slice")
- omf_friendly = models.BooleanField(default=False)
- 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 Slice belongs to")
- max_instances = models.IntegerField(default=10)
- service = models.ForeignKey(Service, related_name='slices', null=True, blank=True)
- network = models.CharField(null=True, blank=True, max_length=256, choices=NETWORK_CHOICES)
- exposed_ports = models.CharField(null=True, blank=True, max_length=256)
- tags = GenericRelation(Tag)
- serviceClass = models.ForeignKey(ServiceClass, related_name = "slices", null=True, blank=True) # DEPRECATED
- creator = models.ForeignKey(User, related_name='slices', blank=True, null=True)
-
- # for tenant view
- default_flavor = models.ForeignKey(Flavor, related_name = "slices", null=True, blank=True)
- default_image = models.ForeignKey(Image, related_name = "slices", null=True, blank=True);
- default_node = models.ForeignKey(Node, related_name = "slices", null=True, blank=True)
- mount_data_sets = StrippedCharField(default="GenBank",null=True, blank=True, max_length=256)
-
- default_isolation = models.CharField(null=False, blank=False, max_length=30, choices=ISOLATION_CHOICES, default="vm")
- xos_links = [ModelLink(Site,'site'),ModelLink(User,'user')]
-
- def __unicode__(self): return u'%s' % (self.name)
-
- @property
- def slicename(self):
- return "%s_%s" % (self.site.login_base, self.name)
-
- def save(self, *args, **kwds):
- site = Site.objects.get(id=self.site.id)
- # allow preexisting slices to keep their original name for now
- if not self.id and not self.name.startswith(site.login_base):
- raise XOSValidationError('slice name must begin with %s' % site.login_base)
-
- if self.name == site.login_base+"_":
- raise XOSValidationError('slice name is too short')
-
- if " " in self.name:
- raise XOSValidationError('slice name must not contain spaces')
-
- # set creator on first save
- if not self.creator and hasattr(self, 'caller'):
- self.creator = self.caller
-
- # only admins change a slice's creator
- if 'creator' in self.changed_fields and \
- (not hasattr(self, 'caller') or not self.caller.is_admin):
-
- if (self._initial["creator"]==None) and (self.creator==getattr(self,"caller",None)):
- # it's okay if the creator is being set by the caller to
- # himeself on a new slice object.
- pass
- else:
- raise PermissionDenied("Insufficient privileges to change slice creator")
-
- if not self.creator:
- raise XOSValidationError('slice has no creator')
-
- if self.network=="Private Only":
- # "Private Only" was the default from the old Tenant View
- self.network=None
- self.enforce_choices(self.network, self.NETWORK_CHOICES)
-
- super(Slice, self).save(*args, **kwds)
-
- def can_update(self, user):
- return user.can_update_slice(self)
-
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = Slice.objects.all()
- else:
- # users can see slices they belong to
- slice_ids = [sp.slice.id for sp in SlicePrivilege.objects.filter(user=user)]
- # pis and admins can see slices at their sites
- sites = [sp.site for sp in SitePrivilege.objects.filter(user=user)\
- if (sp.role.role == 'pi') or (sp.role.role == 'admin')]
- slice_ids.extend([s.id for s in Slice.objects.filter(site__in=sites)])
- qs = Slice.objects.filter(id__in=slice_ids)
- return qs
-
- """
- def delete(self, *args, **kwds):
- # delete networks associated with this slice
- from core.models.network import Network
- nets = Network.objects.filter(slices=self)
- nets.delete()
- # delete slice controllers
- slice_controllers = ControllerSlice.objects.filter(slice=self)
- slice_controllers.delete()
- # delete slice privilege
- slice_privileges = SlicePrivilege.objects.filter(slice=self)
- slice_privileges.delete()
- # continue with normal delete
- super(Slice, self).delete(*args, **kwds)
- """
-
-
-class SliceRole(PlCoreBase):
- ROLE_CHOICES = (('admin','Admin'),('default','Default'))
-
- role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
-
- def __unicode__(self): return u'%s' % (self.role)
-
-class SlicePrivilege(PlCoreBase):
- user = models.ForeignKey('User', related_name='sliceprivileges')
- slice = models.ForeignKey('Slice', related_name='sliceprivileges')
- role = models.ForeignKey('SliceRole',related_name='sliceprivileges')
-
- xos_links=[ModelLink(User,via='user'),ModelLink(Slice,via='slice'),ModelLink(Role,via='role')]
-
- class Meta:
- unique_together = ('user', 'slice', 'role')
-
- def __unicode__(self): return u'%s %s %s' % (self.slice, self.user, self.role)
-
- def save(self, *args, **kwds):
- if not self.user.is_active:
- raise PermissionDenied, "Cannot modify role(s) of a disabled user"
- super(SlicePrivilege, self).save(*args, **kwds)
-
- def can_update(self, user):
- return user.can_update_slice(self.slice)
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = SlicePrivilege.objects.all()
- else:
- # You can see your own SlicePrivileges
- sp_ids = [sp.id for sp in SlicePrivilege.objects.filter(user=user)]
-
- # A site pi or site admin can see the SlicePrivileges for all slices in his Site
- for priv in SitePrivilege.objects.filter(user=user):
- if priv.role.role in ['pi', 'admin']:
- sp_ids.extend( [sp.id for sp in SlicePrivilege.objects.filter(slice__site = priv.site)] )
-
- # A slice admin can see the SlicePrivileges for his Slice
- for priv in SlicePrivilege.objects.filter(user=user, role__role="admin"):
- sp_ids.extend( [sp.id for sp in SlicePrivilege.objects.filter(slice=priv.slice)] )
-
- qs = SlicePrivilege.objects.filter(id__in=sp_ids)
- return qs
-
-class ControllerSlice(PlCoreBase):
- objects = ControllerLinkManager()
- deleted_objects = ControllerLinkDeletionManager()
-
- controller = models.ForeignKey(Controller, related_name='controllerslices')
- slice = models.ForeignKey(Slice, related_name='controllerslices')
- tenant_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")
-
- xos_links = [ModelLink(Controller,via='controller'),ModelLink(Slice,via='slice')]
-
- class Meta:
- unique_together = ('controller', 'slice')
-
- def tologdict(self):
- d=super(ControllerSlice,self).tologdict()
- try:
- d['slice_name']=self.slice.name
- d['controller_name']=self.controller.name
- except:
- pass
- return d
-
- def __unicode__(self): return u'%s %s' % (self.slice, self.controller)
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = ControllerSlice.objects.all()
- else:
- slices = Slice.select_by_user(user)
- qs = ControllerSlice.objects.filter(slice__in=slices)
- return qs
-
- def get_cpu_stats(self):
- filter = 'project_id=%s'%self.tenant_id
- return monitor.get_meter('cpu',filter,None)
-
- def get_bw_stats(self):
- filter = 'project_id=%s'%self.tenant_id
- return monitor.get_meter('network.outgoing.bytes',filter,None)
-
- def get_node_stats(self):
- return len(self.slice.instances)
diff --git a/xos/core/models/slice.xproto b/xos/core/models/slice.xproto
new file mode 100644
index 0000000..5b1acaa
--- /dev/null
+++ b/xos/core/models/slice.xproto
@@ -0,0 +1,20 @@
+message Slice (PlCoreBase){
+ required string name = 1 [max_length = 80, content_type = "stripped", blank = False, help_text = "The Name of the Slice", null = False, db_index = False];
+ required bool enabled = 2 [help_text = "Status for this Slice", default = True, null = False, db_index = False, blank = True];
+ required bool omf_friendly = 3 [default = False, null = False, db_index = False, blank = True];
+ required string description = 4 [help_text = "High level description of the slice and expected activities", max_length = 1024, null = False, db_index = False, blank = True];
+ required string slice_url = 5 [db_index = False, max_length = 512, null = False, content_type = "url", blank = True];
+ required manytoone site->Site:slices = 6 [help_text = "The Site this Slice belongs to", null = False, db_index = True, blank = False];
+ required int32 max_instances = 7 [default = 10, null = False, db_index = False, blank = False];
+ optional manytoone service->Service:slices = 8 [db_index = True, null = True, blank = True];
+ optional string network = 9 [blank = True, max_length = 256, null = True, db_index = False, choices = "((None, 'Default'), ('host', 'Host'), ('bridged', 'Bridged'), ('noauto', 'No Automatic Networks'))"];
+ optional string exposed_ports = 10 [db_index = False, max_length = 256, null = True, blank = True];
+ optional manytoone serviceClass->ServiceClass:slices = 11 [db_index = True, null = True, blank = True];
+ optional manytoone creator->User:slices = 12 [db_index = True, null = True, blank = True];
+ optional manytoone default_flavor->Flavor:slices = 13 [db_index = True, null = True, blank = True];
+ optional manytoone default_image->Image:slices = 14 [db_index = True, null = True, blank = True];
+ optional manytoone default_node->Node:slices = 15 [db_index = True, null = True, blank = True];
+ optional string mount_data_sets = 16 [default = "GenBank", max_length = 256, content_type = "stripped", blank = True, null = True, db_index = False];
+ required string default_isolation = 17 [default = "vm", choices = "(('vm', 'Virtual Machine'), ('container', 'Container'), ('container_vm', 'Container In VM'))", max_length = 30, blank = False, null = False, db_index = False];
+ required manytomany tags->Tag = 18 [db_index = False, null = False, blank = True];
+}
diff --git a/xos/core/models/slicecredential.xproto b/xos/core/models/slicecredential.xproto
new file mode 100644
index 0000000..3ae9ed9
--- /dev/null
+++ b/xos/core/models/slicecredential.xproto
@@ -0,0 +1,8 @@
+
+
+message SliceCredential (PlCoreBase){
+ required manytoone slice->Slice:slicecredentials = 1 [help_text = "The User this credential is associated with", null = False, db_index = True, blank = False];
+ required string name = 2 [help_text = "The credential type, e.g. ec2", max_length = 128, null = False, db_index = True, blank = False];
+ required string key_id = 3 [max_length = 1024, content_type = "stripped", blank = False, help_text = "The backend id of this credential", null = False, db_index = False];
+ required string enc_value = 4 [help_text = "The key value of this credential", max_length = 1024, null = False, db_index = False, blank = False];
+}
diff --git a/xos/core/models/sliceprivilege.xproto b/xos/core/models/sliceprivilege.xproto
new file mode 100644
index 0000000..587f423
--- /dev/null
+++ b/xos/core/models/sliceprivilege.xproto
@@ -0,0 +1,7 @@
+
+
+message SlicePrivilege (PlCoreBase){
+ required manytoone user->User:sliceprivileges = 1 [db_index = True, null = False, blank = False];
+ required manytoone slice->Slice:sliceprivileges = 2 [db_index = True, null = False, blank = False];
+ required manytoone role->SliceRole:sliceprivileges = 3 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/slicerole.xproto b/xos/core/models/slicerole.xproto
new file mode 100644
index 0000000..6396518
--- /dev/null
+++ b/xos/core/models/slicerole.xproto
@@ -0,0 +1,5 @@
+
+
+message SliceRole (PlCoreBase){
+ required string role = 1 [choices = "(('admin', 'Admin'), ('default', 'Default'))", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+}
diff --git a/xos/core/models/slicetag.py b/xos/core/models/slicetag.py
deleted file mode 100644
index 7c0b57a..0000000
--- a/xos/core/models/slicetag.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase,ModelLink
-from core.models import Slice
-from core.models.plcorebase import StrippedCharField
-
-class SliceTag(PlCoreBase):
- slice = models.ForeignKey(Slice, related_name='slicetags')
-
- NAME_CHOICES = (('privatekey', 'Private Key'), ('publickey', 'Public Key'))
- name = StrippedCharField(help_text="The name of this tag", max_length=30, choices=NAME_CHOICES)
- value = StrippedCharField(help_text="The value of this tag", max_length=1024)
-
- xos_links = [ModelLink(Slice,via='slice')]
-
- def can_update(self, user):
- return user.can_update_slice(self.slice)
-
- @staticmethod
- def select_by_user(user):
- if user.is_admin:
- qs = SliceTag.objects.all()
- else:
- slices = Slice.select_by_user(user)
- qs = SliceTag.objects.filter(slice__in=slices)
- return qs
diff --git a/xos/core/models/slicetag.xproto b/xos/core/models/slicetag.xproto
new file mode 100644
index 0000000..a2cac93
--- /dev/null
+++ b/xos/core/models/slicetag.xproto
@@ -0,0 +1,7 @@
+
+
+message SliceTag (PlCoreBase){
+ required manytoone slice->Slice:slicetags = 1 [db_index = True, null = False, blank = False];
+ required string name = 2 [choices = "(('privatekey', 'Private Key'), ('publickey', 'Public Key'))", max_length = 30, content_type = "stripped", blank = False, help_text = "The name of this tag", null = False, db_index = False];
+ required string value = 3 [max_length = 1024, content_type = "stripped", blank = False, help_text = "The value of this tag", null = False, db_index = False];
+}
diff --git a/xos/core/models/tag.py b/xos/core/models/tag.py
deleted file mode 100644
index 7bd7aea..0000000
--- a/xos/core/models/tag.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import os
-from django.db import models
-from core.models import PlCoreBase
-from core.models import Service
-from core.models.plcorebase import StrippedCharField
-from django.contrib.contenttypes.models import ContentType
-from django.contrib.contenttypes.fields import GenericForeignKey
-
-# Create your models here.
-
-class Tag(PlCoreBase):
-
- service = models.ForeignKey(Service, related_name='tags', help_text="The Service this Tag is associated with")
-
- name = models.SlugField(help_text="The name of this tag", max_length=128)
- value = StrippedCharField(help_text="The value of this tag", 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 = GenericForeignKey('content_type', 'object_id')
-
- def __unicode__(self):
- return self.name
-
-
- def can_update(self, user):
- return user.can_update_root()
-
- @classmethod
- def select_by_content_object(cls, obj):
- return cls.objects.filter(content_type=ContentType.objects.get_for_model(obj), object_id=obj.id)
-
- @staticmethod
- def select_by_user(user):
- return Tag.objects.all()
diff --git a/xos/core/models/tag.xproto b/xos/core/models/tag.xproto
new file mode 100644
index 0000000..45662a8
--- /dev/null
+++ b/xos/core/models/tag.xproto
@@ -0,0 +1,9 @@
+
+
+message Tag (PlCoreBase){
+ required manytoone service->Service:tags = 1 [help_text = "The Service this Tag is associated with", null = False, db_index = True, blank = False];
+ required string name = 2 [help_text = "The name of this tag", max_length = 128, null = False, db_index = True, blank = False];
+ required string value = 3 [max_length = 1024, content_type = "stripped", blank = False, help_text = "The value of this tag", null = False, db_index = False];
+ required manytoone content_type->ContentType:tag = 4 [db_index = True, null = False, blank = False];
+ required uint32 object_id = 5 [db_index = False, null = False, blank = False];
+}
diff --git a/xos/core/models/tenant.xproto b/xos/core/models/tenant.xproto
new file mode 100644
index 0000000..91de112
--- /dev/null
+++ b/xos/core/models/tenant.xproto
@@ -0,0 +1,15 @@
+
+
+message Tenant (PlCoreBase,AttributeMixin){
+ optional string name = 1 [db_index = False, max_length = 200, null = True, content_type = "stripped", blank = True];
+ required string kind = 2 [default = "generic", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+ required manytoone provider_service->Service:provided_tenants = 3 [db_index = True, null = False, blank = False];
+ optional manytoone subscriber_service->Service:subscribed_tenants = 4 [db_index = True, null = True, blank = True];
+ optional manytoone subscriber_tenant->Tenant:subscribed_tenants = 5 [db_index = True, null = True, blank = True];
+ optional manytoone subscriber_user->User:subscribed_tenants = 6 [db_index = True, null = True, blank = True];
+ optional manytoone subscriber_root->TenantRoot:subscribed_tenants = 7 [db_index = True, null = True, blank = True];
+ optional manytoone subscriber_network->Network:subscribed_tenants = 8 [db_index = True, null = True, blank = True];
+ optional string service_specific_id = 9 [db_index = False, max_length = 30, null = True, content_type = "stripped", blank = True];
+ optional string service_specific_attribute = 10 [db_index = False, null = True, blank = True];
+ required string connect_method = 11 [default = "na", choices = "(('public', 'Public'), ('private', 'Private'), ('private-unidirectional', 'Private Unidirectional'), ('na', 'Not Applicable'))", max_length = 30, blank = False, null = False, db_index = False];
+}
diff --git a/xos/core/models/tenantattribute.xproto b/xos/core/models/tenantattribute.xproto
new file mode 100644
index 0000000..f9a3abe
--- /dev/null
+++ b/xos/core/models/tenantattribute.xproto
@@ -0,0 +1,7 @@
+
+
+message TenantAttribute (PlCoreBase){
+ required string name = 1 [help_text = "Attribute Name", max_length = 128, null = False, db_index = False, blank = False];
+ required string value = 2 [help_text = "Attribute Value", null = False, db_index = False, blank = False];
+ required manytoone tenant->Tenant:tenantattributes = 3 [help_text = "The Tenant this attribute is associated with", null = False, db_index = True, blank = False];
+}
diff --git a/xos/core/models/tenantprivilege.xproto b/xos/core/models/tenantprivilege.xproto
new file mode 100644
index 0000000..9d90981
--- /dev/null
+++ b/xos/core/models/tenantprivilege.xproto
@@ -0,0 +1,7 @@
+
+
+message TenantPrivilege (PlCoreBase){
+ required manytoone user->User:tenantprivileges = 1 [db_index = True, null = False, blank = False];
+ required manytoone tenant->Tenant:tenantprivileges = 2 [db_index = True, null = False, blank = False];
+ required manytoone role->TenantRole:tenantprivileges = 3 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/tenantrole.xproto b/xos/core/models/tenantrole.xproto
new file mode 100644
index 0000000..646809e
--- /dev/null
+++ b/xos/core/models/tenantrole.xproto
@@ -0,0 +1,5 @@
+
+
+message TenantRole (PlCoreBase){
+ required string role = 1 [choices = "(('admin', 'Admin'), ('access', 'Access'))", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+}
diff --git a/xos/core/models/tenantroot.xproto b/xos/core/models/tenantroot.xproto
new file mode 100644
index 0000000..3c01492
--- /dev/null
+++ b/xos/core/models/tenantroot.xproto
@@ -0,0 +1,8 @@
+
+
+message TenantRoot (PlCoreBase,AttributeMixin){
+ required string kind = 1 [default = "generic", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+ optional string name = 2 [max_length = 255, content_type = "stripped", blank = True, help_text = "name", null = True, db_index = False];
+ optional string service_specific_attribute = 3 [db_index = False, null = True, blank = True];
+ optional string service_specific_id = 4 [db_index = False, max_length = 30, null = True, content_type = "stripped", blank = True];
+}
diff --git a/xos/core/models/tenantrootprivilege.xproto b/xos/core/models/tenantrootprivilege.xproto
new file mode 100644
index 0000000..cf86119
--- /dev/null
+++ b/xos/core/models/tenantrootprivilege.xproto
@@ -0,0 +1,7 @@
+
+
+message TenantRootPrivilege (PlCoreBase){
+ required manytoone user->User:tenant_root_privileges = 1 [db_index = True, null = False, blank = False];
+ required manytoone tenant_root->TenantRoot:tenant_root_privileges = 2 [db_index = True, null = False, blank = False];
+ required manytoone role->TenantRootRole:tenant_root_privileges = 3 [db_index = True, null = False, blank = False];
+}
diff --git a/xos/core/models/tenantrootrole.xproto b/xos/core/models/tenantrootrole.xproto
new file mode 100644
index 0000000..87346ac
--- /dev/null
+++ b/xos/core/models/tenantrootrole.xproto
@@ -0,0 +1,5 @@
+
+
+message TenantRootRole (PlCoreBase){
+ required string role = 1 [choices = "(('admin', 'Admin'), ('access', 'Access'))", max_length = 30, content_type = "stripped", blank = False, null = False, db_index = False];
+}
diff --git a/xos/core/models/tenantwithcontainer.xproto b/xos/core/models/tenantwithcontainer.xproto
new file mode 100644
index 0000000..2bef221
--- /dev/null
+++ b/xos/core/models/tenantwithcontainer.xproto
@@ -0,0 +1,8 @@
+
+
+message TenantWithContainer (Tenant){
+ optional manytoone instance->Instance:+ = 1 [help_text = "Instance used by this Tenant", null = True, db_index = True, blank = True];
+ optional manytoone creator->User:+ = 2 [help_text = "Creator of this Tenant", null = True, db_index = True, blank = True];
+ optional string external_hostname = 3 [max_length = 30, content_type = "stripped", blank = True, help_text = "External host name", null = True, db_index = False];
+ optional string external_container = 4 [max_length = 30, content_type = "stripped", blank = True, help_text = "External host name", null = True, db_index = False];
+}
diff --git a/xos/core/models/usableobject.xproto b/xos/core/models/usableobject.xproto
new file mode 100644
index 0000000..8437318
--- /dev/null
+++ b/xos/core/models/usableobject.xproto
@@ -0,0 +1,5 @@
+
+
+message UsableObject (PlCoreBase){
+ required string name = 1 [db_index = False, max_length = 1024, null = False, content_type = "stripped", blank = False];
+}
diff --git a/xos/core/models/user.py b/xos/core/models/user.py
index 89464bf..ff7bece 100644
--- a/xos/core/models/user.py
+++ b/xos/core/models/user.py
@@ -345,7 +345,7 @@
msg.send()
def can_update(self, user):
- from core.models import SitePrivilege
+ from core.models.siteprivilege import SitePrivilege
_cant_update_fieldName = None
if user.can_update_root():
return True
@@ -382,7 +382,7 @@
return False
def can_update_deployment(self, deployment):
- from core.models.site import DeploymentPrivilege
+ from core.models.deploymentprivilege import DeploymentPrivilege
if self.can_update_root():
return True
@@ -394,7 +394,7 @@
return False
def can_update_site(self, site, allow=[]):
- from core.models.site import SitePrivilege
+ from core.models.siteprivilege import SitePrivilege
if self.can_update_root():
return True
if SitePrivilege.objects.filter(
@@ -403,7 +403,7 @@
return False
def can_update_slice(self, slice):
- from core.models.slice import SlicePrivilege
+ from core.models.sliceprivilege import SlicePrivilege
if self.can_update_root():
return True
if self == slice.creator:
@@ -417,7 +417,7 @@
return False
def can_update_service(self, service, allow=[]):
- from core.models.service import ServicePrivilege
+ from core.models.serviceprivilege import ServicePrivilege
if self.can_update_root():
return True
if ServicePrivilege.objects.filter(
@@ -426,7 +426,8 @@
return False
def can_update_tenant_root(self, tenant_root, allow=[]):
- from core.models.service import TenantRoot, TenantRootPrivilege
+ from core.models.tenantroot import TenantRoot
+ from core.models.tenantrootprivilege import TenantRootPrivilege
if self.can_update_root():
return True
if TenantRootPrivilege.objects.filter(
@@ -435,7 +436,8 @@
return False
def can_update_tenant(self, tenant, allow=[]):
- from core.models.service import Tenant, TenantPrivilege
+ from core.models.tenant import Tenant
+ from core.models.tenantprivilege import TenantPrivilege
if self.can_update_root():
return True
if TenantPrivilege.objects.filter(
@@ -568,7 +570,7 @@
qs = User.objects.all()
else:
# can see all users at any site where this user has pi role
- from core.models.site import SitePrivilege
+ from core.models.siteprivilege import SitePrivilege
site_privs = SitePrivilege.objects.filter(user=user)
sites = [sp.site for sp in site_privs if sp.role.role in [
'Admin', 'admin', 'pi']]
diff --git a/xos/core/models/usercredential.xproto b/xos/core/models/usercredential.xproto
new file mode 100644
index 0000000..22fc83c
--- /dev/null
+++ b/xos/core/models/usercredential.xproto
@@ -0,0 +1,8 @@
+
+
+message UserCredential (PlCoreBase){
+ required manytoone user->User:usercredentials = 1 [help_text = "The User this credential is associated with", null = False, db_index = True, blank = False];
+ required string name = 2 [help_text = "The credential type, e.g. ec2", max_length = 128, null = False, db_index = True, blank = False];
+ required string key_id = 3 [max_length = 1024, content_type = "stripped", blank = False, help_text = "The backend id of this credential", null = False, db_index = False];
+ required string enc_value = 4 [help_text = "The key value of this credential", max_length = 1024, null = False, db_index = False, blank = False];
+}
diff --git a/xos/core/models/xos.xproto b/xos/core/models/xos.xproto
new file mode 100644
index 0000000..8f0d60f
--- /dev/null
+++ b/xos/core/models/xos.xproto
@@ -0,0 +1,15 @@
+
+
+message XOS (PlCoreBase){
+ required string name = 1 [default = "XOS", max_length = 200, content_type = "stripped", blank = False, help_text = "Name of XOS", null = False, db_index = False];
+ required int32 ui_port = 2 [help_text = "Port for XOS UI", default = 80, null = False, db_index = False, blank = False];
+ required int32 bootstrap_ui_port = 3 [help_text = "Port for XOS Bootstrap UI", default = 81, null = False, db_index = False, blank = False];
+ required string db_container_name = 4 [default = "xos_db", max_length = 200, content_type = "stripped", blank = False, help_text = "name of XOS db container", null = False, db_index = False];
+ required string redis_container_name = 5 [default = "", max_length = 200, content_type = "stripped", blank = True, help_text = "name of XOS redis container", null = False, db_index = False];
+ required string docker_project_name = 6 [max_length = 200, content_type = "stripped", blank = False, help_text = "docker project name", null = False, db_index = False];
+ required bool enable_build = 7 [help_text = "True if Onboarding Synchronizer should build XOS as necessary", default = True, null = False, db_index = False, blank = True];
+ required bool frontend_only = 8 [help_text = "If True, XOS will not start synchronizer containers", default = False, null = False, db_index = False, blank = True];
+ required string source_ui_image = 9 [default = "xosproject/xos", max_length = 200, content_type = "stripped", blank = False, null = False, db_index = False];
+ optional string extra_hosts = 10 [max_length = 1024, content_type = "stripped", blank = True, help_text = "list of hostname mappings that will be passed to docker-compose", null = True, db_index = False];
+ required bool no_start = 11 [help_text = "Do not start the XOS UI inside of the UI docker container", default = False, null = False, db_index = False, blank = True];
+}
diff --git a/xos/core/models/xoscomponent.xproto b/xos/core/models/xoscomponent.xproto
new file mode 100644
index 0000000..057529a
--- /dev/null
+++ b/xos/core/models/xoscomponent.xproto
@@ -0,0 +1,9 @@
+
+
+message XOSComponent (LoadableModule){
+ required string image = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "docker image name", null = False, db_index = False];
+ optional string command = 2 [max_length = 1024, content_type = "stripped", blank = True, help_text = "docker run command", null = True, db_index = False];
+ optional string ports = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "port binding", null = True, db_index = False];
+ optional string extra = 4 [max_length = 200, content_type = "stripped", blank = True, help_text = "extra information needed by containers", null = True, db_index = False];
+ required bool no_start = 5 [help_text = "Do not start the Component", default = False, null = False, db_index = False, blank = True];
+}
diff --git a/xos/core/models/xoscomponentlink.xproto b/xos/core/models/xoscomponentlink.xproto
new file mode 100644
index 0000000..5d95bf0
--- /dev/null
+++ b/xos/core/models/xoscomponentlink.xproto
@@ -0,0 +1,8 @@
+
+
+message XOSComponentLink (PlCoreBase){
+ required manytoone component->XOSComponent:links = 1 [help_text = "The Component object for this Link", null = False, db_index = True, blank = False];
+ required string container = 2 [max_length = 200, content_type = "stripped", blank = False, help_text = "container to link", null = False, db_index = False];
+ required string alias = 3 [max_length = 200, content_type = "stripped", blank = False, help_text = "alias for the link", null = False, db_index = False];
+ required string kind = 4 [default = "internal", choices = "(('internal', 'Internal'), ('external', 'External'))", max_length = 20, blank = False, null = False, db_index = False];
+}
diff --git a/xos/core/models/xoscomponentvolume.xproto b/xos/core/models/xoscomponentvolume.xproto
new file mode 100644
index 0000000..c1f7e91
--- /dev/null
+++ b/xos/core/models/xoscomponentvolume.xproto
@@ -0,0 +1,9 @@
+
+
+message XOSComponentVolume (PlCoreBase){
+ required manytoone component->XOSComponent:volumes = 1 [help_text = "The Component object for this Volume", null = False, db_index = True, blank = False];
+ required string name = 2 [max_length = 300, content_type = "stripped", blank = False, help_text = "Volume Name", null = False, db_index = False];
+ required string container_path = 3 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Path of Volume in Container", null = False, db_index = False];
+ required string host_path = 4 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Path of Volume in Host", null = False, db_index = False];
+ required bool read_only = 5 [help_text = "True if mount read-only", default = False, null = False, db_index = False, blank = True];
+}
diff --git a/xos/core/models/xoscomponentvolumecontainer.xproto b/xos/core/models/xoscomponentvolumecontainer.xproto
new file mode 100644
index 0000000..a8c8223
--- /dev/null
+++ b/xos/core/models/xoscomponentvolumecontainer.xproto
@@ -0,0 +1,7 @@
+
+
+message XOSComponentVolumeContainer (PlCoreBase){
+ required manytoone component->XOSComponent:volumecontainers = 1 [help_text = "The Component object for this VolumeContainer", null = False, db_index = True, blank = False];
+ required string name = 2 [max_length = 300, content_type = "stripped", blank = False, help_text = "Volume Name", null = False, db_index = False];
+ required string container = 3 [max_length = 300, content_type = "stripped", blank = False, help_text = "Volume Name", null = False, db_index = False];
+}
diff --git a/xos/core/models/xosguiextension.xproto b/xos/core/models/xosguiextension.xproto
new file mode 100644
index 0000000..774de4e
--- /dev/null
+++ b/xos/core/models/xosguiextension.xproto
@@ -0,0 +1,6 @@
+
+
+message XOSGuiExtension (PlCoreBase){
+ required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Name of the GUI Extensions", null = False, db_index = False];
+ required string files = 2 [max_length = 1024, content_type = "stripped", blank = False, help_text = "List of comma separated file composing the view", null = False, db_index = False];
+}
diff --git a/xos/core/models/xosvolume.xproto b/xos/core/models/xosvolume.xproto
new file mode 100644
index 0000000..2da83d3
--- /dev/null
+++ b/xos/core/models/xosvolume.xproto
@@ -0,0 +1,8 @@
+
+
+message XOSVolume (PlCoreBase){
+ required manytoone xos->XOS:volumes = 1 [help_text = "The XOS object for this Volume", null = False, db_index = True, blank = False];
+ required string container_path = 2 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Path of Volume in Container", null = False, db_index = False];
+ required string host_path = 3 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Path of Volume in Host", null = False, db_index = False];
+ required bool read_only = 4 [help_text = "True if mount read-only", default = False, null = False, db_index = False, blank = True];
+}
diff --git a/xos/genx/targets/init.xtarget b/xos/genx/targets/init.xtarget
index df0abdf..4cf3c31 100644
--- a/xos/genx/targets/init.xtarget
+++ b/xos/genx/targets/init.xtarget
@@ -2,6 +2,7 @@
#
from .plcorebase import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager,PlModelMixIn,ModelLink
+from .contenttype import ContentType
from .singletonmodel import SingletonModel
from .site import Site
from .dashboardview import DashboardView
diff --git a/xos/genx/targets/service.xtarget b/xos/genx/targets/service.xtarget
new file mode 100644
index 0000000..c2256d2
--- /dev/null
+++ b/xos/genx/targets/service.xtarget
@@ -0,0 +1,49 @@
+from header import *
+
+{% for m in proto.messages %}
+{% if file_exists(m.name|lower+'_header.py') -%}from {{m.name|lower }}_header import *{% endif %}
+{% if file_exists(m.name|lower+'_top.py') -%}{{ include_file(m.name|lower+'_top.py') }} {% endif %}
+
+{%- for l in m.links -%}
+{% if l.peer not in proto.message_names -%}
+from core.models import {{ l.peer }}
+{%- endif -%}
+{%- endfor -%}
+{%- for b in m.bases -%}
+{%- if b!='PlCoreBase' and 'Mixin' not in b -%}
+#from core.models.{{b | lower}} import {{ b }}
+from core.models import {{ b }}
+{%- endif -%}
+{% endfor %}
+
+{% endfor %}
+
+{% for m in proto.messages %}
+
+class {{ m.name }}{{ xproto_base_def(m.bases) }}:
+
+ KIND = {{ xproto_first_non_empty([m.options.kind, options.kind, options.name, "Set a kind in your xproto!"]) }}
+
+ class Meta:
+ app_label = {{ xproto_first_non_empty([m.options.app_label, options.app_label, options.name, "Set an app label in your xproto!"]) | lower}}
+ # name = {{ xproto_first_non_empty([m.options.name, options.name, "Set a name in your xproto!"]) }}
+ verbose_name = {{ xproto_first_non_empty([m.options.verbose_name, options.verbose_name, "Set a verbose name in your xproto!"]) }}
+
+ # Primitive Fields (Not Relations)
+ {% for f in m.fields %}
+ {%- if not f.link -%}
+ {{ f.name }} = {{ xproto_django_type(f.type, f.options) }}( {{ xproto_django_options_str(f) }} )
+ {% endif %}
+ {%- endfor %}
+
+ # Relations
+ {% for l in m.links %}
+ {{ l.src_port }} = {{ xproto_django_link_type(l) }}( {%- if l.peer==m.name -%}'self'{%- else -%}{{ l.peer }} {%- endif -%}, {{ xproto_django_options_str(l, l.dst_port ) }} )
+ {%- endfor %}
+
+ {% if file_exists(m.name|lower + '_model.py') -%}{{ include_file(m.name|lower + '_model.py') | indent(width=2)}}{%- endif %}
+ pass
+
+{% if file_exists(m.name|lower+'_bottom.py') -%}{{ include_file(m.name|lower+'_bottom.py') }}{% endif %}
+{% endfor %}
++++ models.py
diff --git a/xos/genx/tool/Makefile.service b/xos/genx/tool/Makefile.service
new file mode 100644
index 0000000..a465797
--- /dev/null
+++ b/xos/genx/tool/Makefile.service
@@ -0,0 +1,18 @@
+# Replace the line below with the location of xosgen
+PREFIX=.
+XOSGEN=$(PREFIX)/tool/xosgen
+
+DJANGO_TARGET=$(PREFIX)/targets/service.xtarget
+XPROTOS_TMP := $(shell mktemp)
+
+xprotos = $(wildcard *.xproto)
+
+all: models.py
+
+models.py: $(xprotos)
+ $(XOSGEN) --attic attic --input $< --target $(DJANGO_TARGET) --output $@
+
+.PHONY: all
+
+clean:
+ rm -f models.py
diff --git a/xos/genx/tool/lib.py b/xos/genx/tool/lib.py
index 9f6c3a9..1c5200e 100644
--- a/xos/genx/tool/lib.py
+++ b/xos/genx/tool/lib.py
@@ -40,6 +40,10 @@
else:
return '(' + ','.join(base) + ')'
+def xproto_first_non_empty(lst):
+ for l in lst:
+ if l: return l
+
def xproto_django_type(xptype, xptags):
if (xptype=='string'):
return django_string_type(xptags)
diff --git a/xos/genx/tool/xos2jinja.py b/xos/genx/tool/xos2jinja.py
index 9cbc00a..5af2272 100644
--- a/xos/genx/tool/xos2jinja.py
+++ b/xos/genx/tool/xos2jinja.py
@@ -7,6 +7,20 @@
import jinja2
import os
+def count_messages(body):
+ count = 0
+ for e in body:
+ if (type(e)==m.MessageDefinition):
+ count+=1
+ return count
+
+def count_fields(body):
+ count = 0
+ for e in body:
+ if (type(e) in [m.LinkDefinition,m.FieldDefinition,m.LinkSpec]):
+ count+=1
+ return count
+
class Stack(list):
def push(self,x):
self.append(x)
@@ -15,12 +29,15 @@
in addition to traversing it '''
class XOS2Jinja(m.Visitor):
stack = Stack()
+ options = {}
+ message_options = {}
count_stack = Stack()
content=""
offset=0
doNameSanitization=False
statementsChanged=0
prefix=""
+ current_message_name = None
def get_stack(self):
return stack
@@ -41,7 +58,11 @@
return True
def visit_OptionStatement(self, obj):
- '''Ignore'''
+ if (self.current_message_name):
+ self.message_options[obj.name.value.pval] = obj.value.value.pval
+ else:
+ self.options[obj.name.value.pval] = obj.value.value.pval
+
return True
def visit_LU(self, obj):
@@ -148,7 +169,9 @@
return True
def visit_MessageDefinition(self, obj):
- self.count_stack.push(len(obj.body))
+ self.current_message_name = obj.name.value.pval
+ self.message_options = {}
+ self.count_stack.push(count_fields(obj.body))
return True
def visit_MessageDefinition_post(self, obj):
@@ -168,7 +191,8 @@
fields.insert(0,f)
last_field = f
- self.stack.push({'name':obj.name.value.pval,'fields':fields,'links':links, 'bases':obj.bases})
+ self.stack.push({'name':obj.name.value.pval,'fields':fields,'links':links, 'bases':obj.bases, 'options':self.message_options})
+ self.current_message_name = None
return True
def visit_MessageExtension(self, obj):
@@ -192,8 +216,9 @@
def visit_DotName(self, obj):
return True
+
def visit_Proto(self, obj):
- self.count_stack.push(len(obj.body))
+ self.count_stack.push(count_messages(obj.body))
return True
def visit_Proto_post(self, obj):
@@ -203,7 +228,7 @@
try:
m = self.stack.pop()
except IndexError:
- pdb.set_trace()
+ pass
messages.insert(0,m)
diff --git a/xos/genx/tool/xosgen b/xos/genx/tool/xosgen
index 59934a7..addb6ba 100755
--- a/xos/genx/tool/xosgen
+++ b/xos/genx/tool/xosgen
@@ -68,7 +68,7 @@
except:
pass
- rendered = template.render({"proto": {'messages':v.messages},"context":context})
+ rendered = template.render({"proto": {'messages':v.messages, 'message_names':[m['name'] for m in v.messages]},"context":context,"options":v.options})
lines = rendered.splitlines()
current_buffer = []
diff --git a/xos/tools/corebuilder/corebuilder.py b/xos/tools/corebuilder/corebuilder.py
index 6e00962..01ea525 100644
--- a/xos/tools/corebuilder/corebuilder.py
+++ b/xos/tools/corebuilder/corebuilder.py
@@ -1,3 +1,7 @@
+#!/usr/bin/python
+
+from stat import *
+
""" CoreBuilder
Read XOS Tosca Onboarding Recipes and generate a BUILD directory.
@@ -106,8 +110,13 @@
def get_dest_dir(self, kind, service_name):
xos_base = "opt/xos"
+ if service_name!='core':
+ service_subdir = 'services'
+ else:
+ service_subdir = ''
+
base_dirs = {"models": "%s/services/%s/" % (xos_base, service_name),
- "xproto": "%s/services/%s/xproto/" % (xos_base, service_name),
+ "xproto": "%s/%s/%s/" % (xos_base, service_subdir, service_name),
"admin": "%s/services/%s/" % (xos_base, service_name),
"admin_template": "%s/services/%s/templates/" % (xos_base, service_name),
"django_library": "%s/services/%s/" % (xos_base, service_name),
@@ -119,6 +128,7 @@
"private_key": "%s/services/%s/keys/" % (xos_base, service_name),
"public_key": "%s/services/%s/keys/" % (xos_base, service_name),
"vendor_js": "%s/core/xoslib/static/vendor/" % (xos_base)}
+
dest_dir = base_dirs[kind]
return dest_dir
@@ -134,6 +144,7 @@
fixups = ( ("/opt/xos_services/olt/", "/opt/cord/onos-apps/apps/olt/"),
("/opt/xos_services/vtn/", "/opt/cord/onos-apps/apps/vtn/"),
("/opt/xos_services/", "/opt/cord/orchestration/xos_services/"),
+ ("/opt/xos/core/", "/opt/cord/orchestration/xos/xos/core/"),
("/opt/xos_libraries/", "/opt/cord/orchestration/xos_libraries/") )
for (pattern, replace) in fixups:
@@ -197,7 +208,7 @@
# If the ServiceController has models, then add it to the list of
# django apps.
- if (k=="models"):
+ if (k in ["models","xproto"] and service_name!="core"):
self.app_names.append(service_name)
# filenames can be comma-separated
@@ -236,7 +247,7 @@
dest_dir = self.get_dest_dir(k, service_name)
dest_fn = os.path.join(dest_dir, subdirectory, os.path.basename(src_fn))
- self.resources.append( (k, src_fn, dest_fn) )
+ self.resources.append( (k, src_fn, dest_fn, service_name) )
# add __init__.py files anywhere that we created a new
# directory.
@@ -258,18 +269,34 @@
shutil.rmtree(os.path.join(BUILD_DIR, dir))
# Copy all of the resources into the build directory
- for (kind, src_fn, dest_fn) in self.resources:
-# if (kind == "xproto"):
-# build_dest_dir = os.path.join(BUILD_DIR, os.path.dirname(dest_fn))
-
- # TODO: If we wanted to statically compile xproto files, then
- # this is where we could do it. src_fn would be the name of
- # the xproto file, and build_dest_dir would be the place
- # to store the generated files.
-
+ for (kind, src_fn, dest_fn, service_name) in self.resources:
build_dest_fn = os.path.join(BUILD_DIR, dest_fn)
makedirs_if_noexist(os.path.dirname(build_dest_fn))
- shutil.copyfile(src_fn, build_dest_fn)
+ if (os.path.isdir(src_fn)):
+ if (not os.path.isdir(build_dest_fn)):
+ shutil.copytree(src_fn, build_dest_fn, symlinks=True)
+ else:
+ os.system('cp -R %s/*.xproto %s/attic %s/*header.py %s'%(src_fn, src_fn, src_fn, build_dest_fn))
+ else:
+ shutil.copyfile(src_fn, build_dest_fn)
+
+ if (kind=='xproto'):
+ # Invoke xproto toolchain in the destination directory
+ xosgen_path = '/opt/cord/orchestration/xos/xos/genx'
+ is_service = service_name!='core'
+
+ if (is_service):
+ makefile_name = 'Makefile.service'
+ else:
+ makefile_name = 'Makefile'
+
+ xproto_makefile = '%s/tool/%s'%(xosgen_path,makefile_name)
+ xproto_makefile_dst = '/'.join([build_dest_fn, makefile_name])
+ shutil.copyfile(xproto_makefile, xproto_makefile_dst)
+
+ if (os.system('make -C %s -f %s PREFIX=%s'%(build_dest_fn, makefile_name, xosgen_path))):
+ raise Exception('xproto build failed!')
+
# Create the __init__.py files
for fn in self.inits: