CORD-1345: Rename PlCoreBase to XOSBase and generate xosbase through
xproto

Change-Id: I5cffb1ccc1a6a7eaba8c89aeec1c769a7c51f9a0
diff --git a/xos/core/models/addresspool.xproto b/xos/core/models/addresspool.xproto
index 737de26..e00dbb5 100644
--- a/xos/core/models/addresspool.xproto
+++ b/xos/core/models/addresspool.xproto
@@ -1,6 +1,6 @@
 
 
-message AddressPool (PlCoreBase){
+message AddressPool (XOSBase){
      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];
diff --git a/xos/core/models/attic/header.py b/xos/core/models/attic/header.py
index 6a19856..300f57f 100644
--- a/xos/core/models/attic/header.py
+++ b/xos/core/models/attic/header.py
@@ -4,7 +4,7 @@
 import json
 import operator
 from operator import attrgetter
-from core.models.plcorebase import *
+from core.models.xosbase import *
 from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
 from django.contrib.contenttypes.models import ContentType
 from django.utils.timezone import now
@@ -97,5 +97,3 @@
             return flavor
 
     return flavors[0]
-
-
diff --git a/xos/core/models/attic/service_header.py b/xos/core/models/attic/service_header.py
index 04e7353..09019b8 100644
--- a/xos/core/models/attic/service_header.py
+++ b/xos/core/models/attic/service_header.py
@@ -1,7 +1,7 @@
 from __future__ import absolute_import
 
 from core.models.xos import XOS
-from core.models.plcorebase import *
+from core.models.xosbase import *
 from django.core.validators import URLValidator
 import urlparse
 from operator import attrgetter
diff --git a/xos/core/models/attic/xosbase_header.py b/xos/core/models/attic/xosbase_header.py
new file mode 100644
index 0000000..d67b56a
--- /dev/null
+++ b/xos/core/models/attic/xosbase_header.py
@@ -0,0 +1,272 @@
+import datetime
+import json
+import pytz
+import inspect
+import sys
+import threading
+from django.db import models
+from django.utils.timezone import now
+from django.db.models import *
+from django.db import transaction
+from django.forms.models import model_to_dict
+from django.utils import timezone
+from django.core.exceptions import PermissionDenied
+from cgi import escape as html_escape
+from journal import journal_object
+from django.db.models.deletion import Collector
+from django.db import router
+from django.contrib.contenttypes.models import ContentType
+
+import redis
+from redis import ConnectionError
+
+def date_handler(obj):
+    if isinstance(obj, pytz.tzfile.DstTzInfo):
+        # json can't serialize DstTzInfo
+        return str(obj)
+    return obj.isoformat() if hasattr(obj, 'isoformat') else obj
+
+try:
+    # This is a no-op if observer_disabled is set to 1 in the config file
+    from synchronizers.base import *
+except:
+    print >> sys.stderr, "import of observer failed! printing traceback and disabling observer:"
+    import traceback
+    traceback.print_exc()
+
+    # guard against something failing
+    def notify_observer(*args, **kwargs):
+        pass
+
+class StrippedCharField(models.CharField):
+    """ CharField that strips trailing and leading spaces."""
+    def clean(self, value, *args, **kwds):
+        if value is not None:
+            value = value.strip()
+        return super(StrippedCharField, self).clean(value, *args, **kwds)
+
+
+# This manager will be inherited by all subclasses because
+# the core model is abstract.
+class XOSBaseDeletionManager(models.Manager):
+    def get_queryset(self):
+        parent=super(XOSBaseDeletionManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(deleted=True)
+        else:
+            return parent.get_query_set().filter(deleted=True)
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+# This manager will be inherited by all subclasses because
+# the core model is abstract.
+class XOSBaseManager(models.Manager):
+    def get_queryset(self):
+        parent=super(XOSBaseManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(deleted=False)
+        else:
+            return parent.get_query_set().filter(deleted=False)
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+class PlModelMixIn(object):
+    # Provides useful methods for computing which objects in a model have
+    # changed. Make sure to do self._initial = self._dict in the __init__
+    # method.
+
+    # Also includes useful utility, like getValidators
+
+    # This is broken out of XOSBase into a Mixin so the User model can
+    # also make use of it.
+
+    @property
+    def _dict(self):
+        return model_to_dict(self, fields=[field.name for field in
+                             self._meta.fields])
+
+    def fields_differ(self,f1,f2):
+        if isinstance(f1,datetime.datetime) and isinstance(f2,datetime.datetime) and (timezone.is_aware(f1) != timezone.is_aware(f2)):
+            return True
+        else:
+            return (f1 != f2)
+
+    @property
+    def diff(self):
+        d1 = self._initial
+        d2 = self._dict
+        diffs = [(k, (v, d2[k])) for k, v in d1.items() if self.fields_differ(v,d2[k])]
+        return dict(diffs)
+
+    @property
+    def has_changed(self):
+        return bool(self.diff)
+
+    @property
+    def changed_fields(self):
+        return self.diff.keys()
+
+    def has_field_changed(self, field_name):
+        return field_name in self.diff.keys()
+
+    def get_field_diff(self, field_name):
+        return self.diff.get(field_name, None)
+
+    #classmethod
+    def getValidators(cls):
+        """ primarily for REST API, return a dictionary of field names mapped
+            to lists of the type of validations that need to be applied to
+            those fields.
+        """
+        validators = {}
+        for field in cls._meta.fields:
+            l = []
+            if field.blank==False:
+                l.append("notBlank")
+            if field.__class__.__name__=="URLField":
+                l.append("url")
+            validators[field.name] = l
+        return validators
+
+    def get_backend_register(self, k, default=None):
+        try:
+            return json.loads(self.backend_register).get(k, default)
+        except AttributeError:
+            return default
+
+    def set_backend_register(self, k, v):
+        br = {}
+        try:
+            br=json.loads(self.backend_register)
+        except AttributeError:
+            br={}
+
+        br[k] = v
+        self.backend_register = json.dumps(br)
+
+    def get_backend_details(self):
+        try:
+            scratchpad = json.loads(self.backend_register)
+        except AttributeError:
+            return (None, None, None, None)
+
+        try:
+            exponent = scratchpad['exponent']
+        except KeyError:
+            exponent = None
+
+        try:
+            last_success_time = scratchpad['last_success']
+            dt = datetime.datetime.fromtimestamp(last_success_time)
+            last_success = dt.strftime("%Y-%m-%d %H:%M")
+        except KeyError:
+            last_success = None
+
+        try:
+            failures = scratchpad['failures']
+        except KeyError:
+            failures=None
+
+        try:
+            last_failure_time = scratchpad['last_failure']
+            dt = datetime.datetime.fromtimestamp(last_failure_time)
+            last_failure = dt.strftime("%Y-%m-%d %H:%M")
+        except KeyError:
+            last_failure = None
+
+        return (exponent, last_success, last_failure, failures)
+
+    def get_backend_icon(self):
+        is_perfect = (self.backend_status is not None) and self.backend_status.startswith("1 -")
+        is_good = (self.backend_status is not None) and (self.backend_status.startswith("0 -") or self.backend_status.startswith("1 -"))
+        is_provisioning = self.backend_status is None or self.backend_status == "Provisioning in progress" or self.backend_status==""
+
+        # returns (icon_name, tooltip)
+        if (self.enacted is not None) and (self.enacted >= self.updated and is_good) or is_perfect:
+            return ("success", "successfully enacted")
+        else:
+            if is_good or is_provisioning:
+                return ("clock", "Pending sync, last_status = " + html_escape(self.backend_status, quote=True))
+            else:
+                return ("error", html_escape(self.backend_status, quote=True))
+
+    def enforce_choices(self, field, choices):
+        choices = [x[0] for x in choices]
+        for choice in choices:
+            if field==choice:
+                return
+            if (choice==None) and (field==""):
+                # allow "" and None to be equivalent
+                return
+        raise Exception("Field value %s is not in %s" % (field, str(choices)))
+
+    def serialize_for_redis(self):
+        """ Serialize the object for posting to redis.
+
+            The API serializes ForeignKey fields by naming them <name>_id
+            whereas model_to_dict leaves them with the original name. Modify
+            the results of model_to_dict to provide the same fieldnames.
+        """
+
+        field_types = {}
+        for f in self._meta.fields:
+            field_types[f.name] = f.get_internal_type()
+
+        fields = model_to_dict(self)
+        for k in fields.keys():
+            if field_types.get(k,None) == "ForeignKey":
+                new_key_name = "%s_id" % k
+                if (k in fields) and (new_key_name not in fields):
+                    fields[new_key_name] = fields[k]
+                    del fields[k]
+
+        return fields
+
+    def push_redis_event(self):
+        # Transmit update via Redis
+        changed_fields = []
+
+        if self.pk is not None:
+            my_model = type(self)
+            try:
+                orig = my_model.objects.get(pk=self.pk)
+
+                for f in my_model._meta.fields:
+                    oval = getattr(orig, f.name)
+                    nval = getattr(self, f.name)
+                    if oval != nval:
+                        changed_fields.append(f.name)
+            except:
+                changed_fields.append('__lookup_error')
+
+        try:
+            r = redis.Redis("redis")
+            # NOTE the redis event has been extended with model properties to facilitate the support of real time notification in the UI
+            # keep this monitored for performance reasons and eventually revert it back to fetch model properties via the REST API
+            model = self.serialize_for_redis()
+            bases = inspect.getmro(self.__class__)
+            # bases = [x for x in bases if issubclass(x, XOSBase)]
+            class_names = ",".join([x.__name__ for x in bases])
+            model['class_names'] = class_names
+            payload = json.dumps({'pk': self.pk, 'changed_fields': changed_fields, 'object': model}, default=date_handler)
+            r.publish(self.__class__.__name__, payload)
+        except ConnectionError:
+            # Redis not running.
+            pass
+
+# For cascading deletes, we need a Collector that doesn't do fastdelete,
+# so we get a full list of models.
+class XOSCollector(Collector):
+  def can_fast_delete(self, *args, **kwargs):
+    return False
+
+class ModelLink:
+    def __init__(self,dest,via,into=None):
+        self.dest=dest
+        self.via=via
+        self.into=into
+
diff --git a/xos/core/models/attic/xosbase_model.py b/xos/core/models/attic/xosbase_model.py
new file mode 100644
index 0000000..094c466
--- /dev/null
+++ b/xos/core/models/attic/xosbase_model.py
@@ -0,0 +1,148 @@
+objects = XOSBaseManager()
+deleted_objects = XOSBaseDeletionManager()
+
+class Meta:
+    # Changing abstract to False would require the managers of subclasses of
+    # XOSBase to be customized individually.
+    abstract = True
+    app_label = "core"
+
+def __init__(self, *args, **kwargs):
+    super(XOSBase, self).__init__(*args, **kwargs)
+    self._initial = self._dict # for PlModelMixIn
+    self.silent = False
+
+def get_controller(self):
+    return self.controller
+
+def can_update(self, user):
+    return user.can_update_root()
+
+def delete(self, *args, **kwds):
+    # so we have something to give the observer
+    purge = kwds.get('purge',False)
+    if purge:
+        del kwds['purge']
+    silent = kwds.get('silent',False)
+    if silent:
+        del kwds['silent']
+    try:
+        purge = purge or observer_disabled
+    except NameError:
+        pass
+
+    if (purge):
+        journal_object(self, "delete.purge")
+        super(XOSBase, self).delete(*args, **kwds)
+    else:
+        if (not self.write_protect ):
+            self.deleted = True
+            self.enacted=None
+            self.policed=None
+            journal_object(self, "delete.mark_deleted")
+            self.save(update_fields=['enacted','deleted','policed'], silent=silent)
+
+            collector = XOSCollector(using=router.db_for_write(self.__class__, instance=self))
+            collector.collect([self])
+            with transaction.atomic():
+                for (k, models) in collector.data.items():
+                    for model in models:
+                        if model.deleted:
+                            # in case it's already been deleted, don't delete again
+                            continue
+                        model.deleted = True
+                        model.enacted=None
+                        model.policed=None
+                        journal_object(model, "delete.cascade.mark_deleted", msg="root = %r" % self)
+                        model.save(update_fields=['enacted','deleted','policed'], silent=silent)
+
+def save(self, *args, **kwargs):
+    journal_object(self, "xosbase.save")
+
+    # let the user specify silence as either a kwarg or an instance varible
+    silent = self.silent
+    if "silent" in kwargs:
+        silent=silent or kwargs.pop("silent")
+
+    caller_kind = "unknown"
+
+    if ('synchronizer' in threading.current_thread().name):
+        caller_kind = "synchronizer"
+
+    if "caller_kind" in kwargs:
+        caller_kind = kwargs.pop("caller_kind")
+
+    always_update_timestamp = False
+    if "always_update_timestamp" in kwargs:
+        always_update_timestamp = always_update_timestamp or kwargs.pop("always_update_timestamp")
+
+    # SMBAKER: if an object is trying to delete itself, or if the observer
+    # is updating an object's backend_* fields, then let it slip past the
+    # composite key check.
+    ignore_composite_key_check=False
+    if "update_fields" in kwargs:
+        ignore_composite_key_check=True
+        for field in kwargs["update_fields"]:
+            if not (field in ["backend_register", "backend_status", "deleted", "enacted", "updated"]):
+                ignore_composite_key_check=False
+
+    if (caller_kind!="synchronizer") or always_update_timestamp:
+        self.updated = timezone.now()
+
+    journal_object(self, "xosbase.save.super_save")
+
+    super(XOSBase, self).save(*args, **kwargs)
+
+    journal_object(self, "xosbase.save.super_save_returned")
+
+    self.push_redis_event()
+
+    # This is a no-op if observer_disabled is set
+    # if not silent:
+    #    notify_observer()
+
+    self._initial = self._dict
+
+def save_by_user(self, user, *args, **kwds):
+    if not self.can_update(user):
+        if getattr(self, "_cant_update_fieldName", None) is not None:
+            raise PermissionDenied("You do not have permission to update field %s on object %s" % (self._cant_update_fieldName, self.__class__.__name__))
+        else:
+            raise PermissionDenied("You do not have permission to update %s objects" % self.__class__.__name__)
+
+    self.save(*args, **kwds)
+
+def delete_by_user(self, user, *args, **kwds):
+    if not self.can_update(user):
+        raise PermissionDenied("You do not have permission to delete %s objects" % self.__class__.__name__)
+    self.delete(*args, **kwds)
+
+@classmethod
+def select_by_user(cls, user):
+    # This should be overridden by descendant classes that want to perform
+    # filtering of visible objects by user.
+    return cls.objects.all()
+
+def tologdict(self):
+    try:
+        d = {'model_name':self.__class__.__name__, 'pk': self.pk}
+    except:
+        d = {}
+
+    return d
+
+def get_content_type_key(self):
+    ct = ContentType.objects.get_for_model(self.__class__)
+    return "%s.%s" % (ct.app_label, ct.model)
+
+@staticmethod
+def get_content_type_from_key(key):
+    (app_name, model_name) = key.split(".")
+    return ContentType.objects.get_by_natural_key(app_name, model_name)
+
+@staticmethod
+def get_content_object(content_type, object_id):
+    ct = XOSBase.get_content_type_from_key(content_type)
+    cls = ct.model_class()
+    return cls.objects.get(id=object_id)
+
diff --git a/xos/core/models/controller.xproto b/xos/core/models/controller.xproto
index da2d1e3..760ccc5 100644
--- a/xos/core/models/controller.xproto
+++ b/xos/core/models/controller.xproto
@@ -1,6 +1,6 @@
 
 
-message Controller (PlCoreBase){
+message Controller (XOSBase){
      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];
diff --git a/xos/core/models/controllerdashboardview.xproto b/xos/core/models/controllerdashboardview.xproto
index ed4229c..ff84b95 100644
--- a/xos/core/models/controllerdashboardview.xproto
+++ b/xos/core/models/controllerdashboardview.xproto
@@ -1,6 +1,6 @@
 
 
-message ControllerDashboardView (PlCoreBase){
+message ControllerDashboardView (XOSBase){
      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];
diff --git a/xos/core/models/controllerimages.xproto b/xos/core/models/controllerimages.xproto
index 38d6237..aae8361 100644
--- a/xos/core/models/controllerimages.xproto
+++ b/xos/core/models/controllerimages.xproto
@@ -1,6 +1,6 @@
 
 
-message ControllerImages (PlCoreBase){
+message ControllerImages (XOSBase){
      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
index ba6acec..e6d2ef4 100644
--- a/xos/core/models/controllernetwork.xproto
+++ b/xos/core/models/controllernetwork.xproto
@@ -1,6 +1,6 @@
 
 
-message ControllerNetwork (PlCoreBase){
+message ControllerNetwork (XOSBase){
      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];
diff --git a/xos/core/models/controllerrole.xproto b/xos/core/models/controllerrole.xproto
index 4ae4bb2..e2b586c 100644
--- a/xos/core/models/controllerrole.xproto
+++ b/xos/core/models/controllerrole.xproto
@@ -1,5 +1,5 @@
 
 
-message ControllerRole (PlCoreBase){
+message ControllerRole (XOSBase){
      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
index 6fb4be8..c092629 100644
--- a/xos/core/models/controllersite.xproto
+++ b/xos/core/models/controllersite.xproto
@@ -1,6 +1,6 @@
 
 
-message ControllerSite (PlCoreBase){
+message ControllerSite (XOSBase){
      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
index ca5ca75..0bfd962 100644
--- a/xos/core/models/controllersiteprivilege.xproto
+++ b/xos/core/models/controllersiteprivilege.xproto
@@ -1,6 +1,6 @@
 
 
-message ControllerSitePrivilege (PlCoreBase){
+message ControllerSitePrivilege (XOSBase){
      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
index 46e15ae..022835a 100644
--- a/xos/core/models/controllerslice.xproto
+++ b/xos/core/models/controllerslice.xproto
@@ -1,6 +1,6 @@
 
 
-message ControllerSlice (PlCoreBase){
+message ControllerSlice (XOSBase){
      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
index c1308dc..5895519 100644
--- a/xos/core/models/controllersliceprivilege.xproto
+++ b/xos/core/models/controllersliceprivilege.xproto
@@ -1,6 +1,6 @@
 
 
-message ControllerSlicePrivilege (PlCoreBase){
+message ControllerSlicePrivilege (XOSBase){
      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.xproto b/xos/core/models/controlleruser.xproto
index 5560d6d..14737eb 100644
--- a/xos/core/models/controlleruser.xproto
+++ b/xos/core/models/controlleruser.xproto
@@ -1,6 +1,6 @@
 
 
-message ControllerUser (PlCoreBase){
+message ControllerUser (XOSBase){
      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/dashboardview.xproto b/xos/core/models/dashboardview.xproto
index 76e4f30..ed67e5a 100644
--- a/xos/core/models/dashboardview.xproto
+++ b/xos/core/models/dashboardview.xproto
@@ -1,6 +1,6 @@
 
 
-message DashboardView (PlCoreBase){
+message DashboardView (XOSBase){
      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];
diff --git a/xos/core/models/deployment.xproto b/xos/core/models/deployment.xproto
index 779f74d..3a0e03b 100644
--- a/xos/core/models/deployment.xproto
+++ b/xos/core/models/deployment.xproto
@@ -1,6 +1,6 @@
 
 
-message Deployment (PlCoreBase){
+message Deployment (XOSBase){
      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
index 33efc2a..2bd0286 100644
--- a/xos/core/models/deploymentprivilege.xproto
+++ b/xos/core/models/deploymentprivilege.xproto
@@ -1,6 +1,6 @@
 
 
-message DeploymentPrivilege (PlCoreBase){
+message DeploymentPrivilege (XOSBase){
      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
index 61adab5..fa483f7 100644
--- a/xos/core/models/deploymentrole.xproto
+++ b/xos/core/models/deploymentrole.xproto
@@ -1,5 +1,5 @@
 
 
-message DeploymentRole (PlCoreBase){
+message DeploymentRole (XOSBase){
      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
index 7869f50..6396bb4 100644
--- a/xos/core/models/diag.xproto
+++ b/xos/core/models/diag.xproto
@@ -1,5 +1,5 @@
 
 
-message Diag (PlCoreBase){
+message Diag (XOSBase){
      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.xproto b/xos/core/models/flavor.xproto
index d30a7c2..08714d0 100644
--- a/xos/core/models/flavor.xproto
+++ b/xos/core/models/flavor.xproto
@@ -1,6 +1,6 @@
 
 
-message Flavor (PlCoreBase){
+message Flavor (XOSBase){
      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];
diff --git a/xos/core/models/image.xproto b/xos/core/models/image.xproto
index f810e0d..a06070d 100644
--- a/xos/core/models/image.xproto
+++ b/xos/core/models/image.xproto
@@ -1,6 +1,6 @@
 
 
-message Image (PlCoreBase){
+message Image (XOSBase){
      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];
diff --git a/xos/core/models/imagedeployments.xproto b/xos/core/models/imagedeployments.xproto
index e11fedb..6d985ce 100644
--- a/xos/core/models/imagedeployments.xproto
+++ b/xos/core/models/imagedeployments.xproto
@@ -1,6 +1,6 @@
 
 
-message ImageDeployments (PlCoreBase){
+message ImageDeployments (XOSBase){
      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.xproto b/xos/core/models/instance.xproto
index bc86813..b34291e 100644
--- a/xos/core/models/instance.xproto
+++ b/xos/core/models/instance.xproto
@@ -1,6 +1,6 @@
 
 
-message Instance (PlCoreBase){
+message Instance (XOSBase){
      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];
diff --git a/xos/core/models/network.xproto b/xos/core/models/network.xproto
index 5305416..ffd1eb1 100644
--- a/xos/core/models/network.xproto
+++ b/xos/core/models/network.xproto
@@ -1,6 +1,6 @@
 
 
-message Network (PlCoreBase,ParameterMixin){
+message Network (XOSBase,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];
diff --git a/xos/core/models/networkparameter.xproto b/xos/core/models/networkparameter.xproto
index a162d9a..01ce43e 100644
--- a/xos/core/models/networkparameter.xproto
+++ b/xos/core/models/networkparameter.xproto
@@ -1,6 +1,6 @@
 
 
-message NetworkParameter (PlCoreBase){
+message NetworkParameter (XOSBase){
      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 string content_type = 4 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Content type id linked to this network parameter", null = False, db_index = False];
diff --git a/xos/core/models/networkparametertype.xproto b/xos/core/models/networkparametertype.xproto
index 6eb7804..840a345 100644
--- a/xos/core/models/networkparametertype.xproto
+++ b/xos/core/models/networkparametertype.xproto
@@ -1,6 +1,6 @@
 
 
-message NetworkParameterType (PlCoreBase){
+message NetworkParameterType (XOSBase){
      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
index 7ae04a2..1697fec 100644
--- a/xos/core/models/networkslice.xproto
+++ b/xos/core/models/networkslice.xproto
@@ -1,6 +1,6 @@
 
 
-message NetworkSlice (PlCoreBase){
+message NetworkSlice (XOSBase){
      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
index 4957784..d9653ab 100644
--- a/xos/core/models/networktemplate.xproto
+++ b/xos/core/models/networktemplate.xproto
@@ -1,6 +1,6 @@
 
 
-message NetworkTemplate (PlCoreBase,ParameterMixin){
+message NetworkTemplate (XOSBase,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 string visibility = 4 [default = "private", choices = "(('public', 'public'), ('private', 'private'))", max_length = 30, blank = False, null = False, db_index = False];
diff --git a/xos/core/models/node.xproto b/xos/core/models/node.xproto
index 9000fbb..36495d5 100644
--- a/xos/core/models/node.xproto
+++ b/xos/core/models/node.xproto
@@ -1,6 +1,4 @@
-
-
-message Node (PlCoreBase){
+message Node (XOSBase){
      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];
diff --git a/xos/core/models/nodelabel.xproto b/xos/core/models/nodelabel.xproto
index fc89a46..bf00ae7 100644
--- a/xos/core/models/nodelabel.xproto
+++ b/xos/core/models/nodelabel.xproto
@@ -1,6 +1,4 @@
-
-
-message NodeLabel (PlCoreBase){
+message NodeLabel (XOSBase){
      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/plcorebase.py b/xos/core/models/plcorebase.py
deleted file mode 100644
index aa80718..0000000
--- a/xos/core/models/plcorebase.py
+++ /dev/null
@@ -1,464 +0,0 @@
-import datetime
-import json
-import pytz
-import inspect
-import sys
-import threading
-from django.db import models
-from django.db import transaction
-from django.forms.models import model_to_dict
-from django.utils import timezone
-from django.core.exceptions import PermissionDenied
-from cgi import escape as html_escape
-from journal import journal_object
-from django.db.models.deletion import Collector
-from django.db import router
-from django.contrib.contenttypes.models import ContentType
-
-import redis
-from redis import ConnectionError
-
-def date_handler(obj):
-    if isinstance(obj, pytz.tzfile.DstTzInfo):
-        # json can't serialize DstTzInfo
-        return str(obj)
-    return obj.isoformat() if hasattr(obj, 'isoformat') else obj
-
-try:
-    # This is a no-op if observer_disabled is set to 1 in the config file
-    from synchronizers.base import *
-except:
-    print >> sys.stderr, "import of observer failed! printing traceback and disabling observer:"
-    import traceback
-    traceback.print_exc()
-
-    # guard against something failing
-    def notify_observer(*args, **kwargs):
-        pass
-
-class StrippedCharField(models.CharField):
-    """ CharField that strips trailing and leading spaces."""
-    def clean(self, value, *args, **kwds):
-        if value is not None:
-            value = value.strip()
-        return super(StrippedCharField, self).clean(value, *args, **kwds)
-
-
-# This manager will be inherited by all subclasses because
-# the core model is abstract.
-class PlCoreBaseDeletionManager(models.Manager):
-    def get_queryset(self):
-        parent=super(PlCoreBaseDeletionManager, self)
-        if hasattr(parent, "get_queryset"):
-            return parent.get_queryset().filter(deleted=True)
-        else:
-            return parent.get_query_set().filter(deleted=True)
-
-    # deprecated in django 1.7 in favor of get_queryset().
-    def get_query_set(self):
-        return self.get_queryset()
-
-# This manager will be inherited by all subclasses because
-# the core model is abstract.
-class PlCoreBaseManager(models.Manager):
-    def get_queryset(self):
-        parent=super(PlCoreBaseManager, self)
-        if hasattr(parent, "get_queryset"):
-            return parent.get_queryset().filter(deleted=False)
-        else:
-            return parent.get_query_set().filter(deleted=False)
-
-    # deprecated in django 1.7 in favor of get_queryset().
-    def get_query_set(self):
-        return self.get_queryset()
-
-class PlModelMixIn(object):
-    # Provides useful methods for computing which objects in a model have
-    # changed. Make sure to do self._initial = self._dict in the __init__
-    # method.
-
-    # Also includes useful utility, like getValidators
-
-    # This is broken out of PlCoreBase into a Mixin so the User model can
-    # also make use of it.
-
-    @property
-    def _dict(self):
-        return model_to_dict(self, fields=[field.name for field in
-                             self._meta.fields])
-
-    def fields_differ(self,f1,f2):
-        if isinstance(f1,datetime.datetime) and isinstance(f2,datetime.datetime) and (timezone.is_aware(f1) != timezone.is_aware(f2)):
-            return True
-        else:
-            return (f1 != f2)
-
-    @property
-    def diff(self):
-        d1 = self._initial
-        d2 = self._dict
-        diffs = [(k, (v, d2[k])) for k, v in d1.items() if self.fields_differ(v,d2[k])]
-        return dict(diffs)
-
-    @property
-    def has_changed(self):
-        return bool(self.diff)
-
-    @property
-    def changed_fields(self):
-        return self.diff.keys()
-
-    def has_field_changed(self, field_name):
-        return field_name in self.diff.keys()
-
-    def get_field_diff(self, field_name):
-        return self.diff.get(field_name, None)
-
-    #classmethod
-    def getValidators(cls):
-        """ primarily for REST API, return a dictionary of field names mapped
-            to lists of the type of validations that need to be applied to
-            those fields.
-        """
-        validators = {}
-        for field in cls._meta.fields:
-            l = []
-            if field.blank==False:
-                l.append("notBlank")
-            if field.__class__.__name__=="URLField":
-                l.append("url")
-            validators[field.name] = l
-        return validators
-
-    def get_backend_register(self, k, default=None):
-        try:
-            return json.loads(self.backend_register).get(k, default)
-        except AttributeError:
-            return default
-
-    def set_backend_register(self, k, v):
-        br = {}
-        try:
-            br=json.loads(self.backend_register)
-        except AttributeError:
-            br={}
-
-        br[k] = v
-        self.backend_register = json.dumps(br)
-
-    def get_backend_details(self):
-        try:
-            scratchpad = json.loads(self.backend_register)
-        except AttributeError:
-            return (None, None, None, None)
-
-        try:
-            exponent = scratchpad['exponent']
-        except KeyError:
-            exponent = None
-
-        try:
-            last_success_time = scratchpad['last_success']
-            dt = datetime.datetime.fromtimestamp(last_success_time)
-            last_success = dt.strftime("%Y-%m-%d %H:%M")
-        except KeyError:
-            last_success = None
-
-        try:
-            failures = scratchpad['failures']
-        except KeyError:
-            failures=None
-
-        try:
-            last_failure_time = scratchpad['last_failure']
-            dt = datetime.datetime.fromtimestamp(last_failure_time)
-            last_failure = dt.strftime("%Y-%m-%d %H:%M")
-        except KeyError:
-            last_failure = None
-
-        return (exponent, last_success, last_failure, failures)
-
-    def get_backend_icon(self):
-        is_perfect = (self.backend_status is not None) and self.backend_status.startswith("1 -")
-        is_good = (self.backend_status is not None) and (self.backend_status.startswith("0 -") or self.backend_status.startswith("1 -"))
-        is_provisioning = self.backend_status is None or self.backend_status == "Provisioning in progress" or self.backend_status==""
-
-        # returns (icon_name, tooltip)
-        if (self.enacted is not None) and (self.enacted >= self.updated and is_good) or is_perfect:
-            return ("success", "successfully enacted")
-        else:
-            if is_good or is_provisioning:
-                return ("clock", "Pending sync, last_status = " + html_escape(self.backend_status, quote=True))
-            else:
-                return ("error", html_escape(self.backend_status, quote=True))
-
-    def enforce_choices(self, field, choices):
-        choices = [x[0] for x in choices]
-        for choice in choices:
-            if field==choice:
-                return
-            if (choice==None) and (field==""):
-                # allow "" and None to be equivalent
-                return
-        raise Exception("Field value %s is not in %s" % (field, str(choices)))
-
-    def serialize_for_redis(self):
-        """ Serialize the object for posting to redis.
-
-            The API serializes ForeignKey fields by naming them <name>_id
-            whereas model_to_dict leaves them with the original name. Modify
-            the results of model_to_dict to provide the same fieldnames.
-        """
-
-        field_types = {}
-        for f in self._meta.fields:
-            field_types[f.name] = f.get_internal_type()
-
-        fields = model_to_dict(self)
-        for k in fields.keys():
-            if field_types.get(k,None) == "ForeignKey":
-                new_key_name = "%s_id" % k
-                if (k in fields) and (new_key_name not in fields):
-                    fields[new_key_name] = fields[k]
-                    del fields[k]
-
-        return fields
-
-    def push_redis_event(self):
-        # Transmit update via Redis
-        changed_fields = []
-
-        if self.pk is not None:
-            my_model = type(self)
-            try:
-                orig = my_model.objects.get(pk=self.pk)
-
-                for f in my_model._meta.fields:
-                    oval = getattr(orig, f.name)
-                    nval = getattr(self, f.name)
-                    if oval != nval:
-                        changed_fields.append(f.name)
-            except:
-                changed_fields.append('__lookup_error')
-
-        try:
-            r = redis.Redis("redis")
-            # NOTE the redis event has been extended with model properties to facilitate the support of real time notification in the UI
-            # keep this monitored for performance reasons and eventually revert it back to fetch model properties via the REST API
-            model = self.serialize_for_redis()
-            bases = inspect.getmro(self.__class__)
-            bases = [x for x in bases if issubclass(x, PlCoreBase)]
-            class_names = ",".join([x.__name__ for x in bases])
-            model['class_names'] = class_names
-            payload = json.dumps({'pk': self.pk, 'changed_fields': changed_fields, 'object': model}, default=date_handler)
-            r.publish(self.__class__.__name__, payload)
-        except ConnectionError:
-            # Redis not running.
-            pass
-
-# For cascading deletes, we need a Collector that doesn't do fastdelete,
-# so we get a full list of models.
-class XOSCollector(Collector):
-  def can_fast_delete(self, *args, **kwargs):
-    return False
-
-class PlCoreBase(models.Model, PlModelMixIn):
-    objects = PlCoreBaseManager()
-    deleted_objects = PlCoreBaseDeletionManager()
-
-    # default values for created and updated are only there to keep evolution
-    # from failing.
-    created = models.DateTimeField(auto_now_add=True)
-    updated = models.DateTimeField(default=timezone.now)
-    enacted = models.DateTimeField(null=True, blank=True, default=None)
-    policed = models.DateTimeField(null=True, blank=True, default=None)
-
-    # This is a scratchpad used by the Observer
-    backend_register = models.CharField(max_length=1024,
-                                      default="{}", null=True)
-
-    # backend_need_delete and backend_need_reap are used by the synchronizer to
-    # handle deleting and reaping objects.
-    #
-    # backend_need_delete is set by a syncstep when it starts to work on an
-    # object. It indicates that the syncstep will, in the future, want an
-    # opportunity to delete the object. This bit prevents the reaper from
-    # auto-deleting the object.
-    #
-    # backend_need_reap is set when a syncstep has successfully enacted a delete
-    # and is ready for it to be permanently deleted. The reaper will, assuming
-    # the object has no cascades to other objects that need deleting, permanently
-    # delete the object.
-
-    backend_need_delete = models.BooleanField(default=False)
-    backend_need_reap = models.BooleanField(default=False)
-
-    backend_status = models.CharField(max_length=1024,
-                                      default="0 - Provisioning in progress")
-    deleted = models.BooleanField(default=False)
-    write_protect = models.BooleanField(default=False)
-    lazy_blocked = models.BooleanField(default=False)
-    no_sync = models.BooleanField(default=False)     # prevent object sync
-    no_policy = models.BooleanField(default=False)   # prevent model_policy run
-
-    class Meta:
-        # Changing abstract to False would require the managers of subclasses of
-        # PlCoreBase to be customized individually.
-        abstract = True
-        app_label = "core"
-
-    def __init__(self, *args, **kwargs):
-        super(PlCoreBase, self).__init__(*args, **kwargs)
-        self._initial = self._dict # for PlModelMixIn
-        self.silent = False
-
-    def get_controller(self):
-        return self.controller
-
-    def can_update(self, user):
-        return user.can_update_root()
-
-    def delete(self, *args, **kwds):
-        # so we have something to give the observer
-        purge = kwds.get('purge',False)
-        if purge:
-            del kwds['purge']
-        silent = kwds.get('silent',False)
-        if silent:
-            del kwds['silent']
-        try:
-            purge = purge or observer_disabled
-        except NameError:
-            pass
-
-        if (purge):
-            journal_object(self, "delete.purge")
-            super(PlCoreBase, self).delete(*args, **kwds)
-        else:
-            if (not self.write_protect ):
-                self.deleted = True
-                self.enacted=None
-                self.policed=None
-                journal_object(self, "delete.mark_deleted")
-                self.save(update_fields=['enacted','deleted','policed'], silent=silent)
-
-                collector = XOSCollector(using=router.db_for_write(self.__class__, instance=self))
-                collector.collect([self])
-                with transaction.atomic():
-                    for (k, models) in collector.data.items():
-                        for model in models:
-                            if model.deleted:
-                                # in case it's already been deleted, don't delete again
-                                continue
-                            model.deleted = True
-                            model.enacted=None
-                            model.policed=None
-                            journal_object(model, "delete.cascade.mark_deleted", msg="root = %r" % self)
-                            model.save(update_fields=['enacted','deleted','policed'], silent=silent)
-
-    def save(self, *args, **kwargs):
-        journal_object(self, "plcorebase.save")
-
-        # let the user specify silence as either a kwarg or an instance varible
-        silent = self.silent
-        if "silent" in kwargs:
-            silent=silent or kwargs.pop("silent")
-
-        caller_kind = "unknown"
-
-        if ('synchronizer' in threading.current_thread().name):
-            caller_kind = "synchronizer"
-
-        if "caller_kind" in kwargs:
-            caller_kind = kwargs.pop("caller_kind")
-
-        always_update_timestamp = False
-        if "always_update_timestamp" in kwargs:
-            always_update_timestamp = always_update_timestamp or kwargs.pop("always_update_timestamp")
-
-        # SMBAKER: if an object is trying to delete itself, or if the observer
-        # is updating an object's backend_* fields, then let it slip past the
-        # composite key check.
-        ignore_composite_key_check=False
-        if "update_fields" in kwargs:
-            ignore_composite_key_check=True
-            for field in kwargs["update_fields"]:
-                if not (field in ["backend_register", "backend_status", "deleted", "enacted", "updated"]):
-                    ignore_composite_key_check=False
-
-        if (caller_kind!="synchronizer") or always_update_timestamp:
-            self.updated = timezone.now()
-
-        journal_object(self, "plcorebase.save.super_save")
-
-        super(PlCoreBase, self).save(*args, **kwargs)
-
-        journal_object(self, "plcorebase.save.super_save_returned")
-
-        self.push_redis_event()
-
-        # This is a no-op if observer_disabled is set
-        # if not silent:
-        #    notify_observer()
-
-        self._initial = self._dict
-
-    def save_by_user(self, user, *args, **kwds):
-        if not self.can_update(user):
-            if getattr(self, "_cant_update_fieldName", None) is not None:
-                raise PermissionDenied("You do not have permission to update field %s on object %s" % (self._cant_update_fieldName, self.__class__.__name__))
-            else:
-                raise PermissionDenied("You do not have permission to update %s objects" % self.__class__.__name__)
-
-        self.save(*args, **kwds)
-
-    def delete_by_user(self, user, *args, **kwds):
-        if not self.can_update(user):
-            raise PermissionDenied("You do not have permission to delete %s objects" % self.__class__.__name__)
-        self.delete(*args, **kwds)
-
-    @classmethod
-    def select_by_user(cls, user):
-        # This should be overridden by descendant classes that want to perform
-        # filtering of visible objects by user.
-        return cls.objects.all()
-
-    def tologdict(self):
-        try:
-            d = {'model_name':self.__class__.__name__, 'pk': self.pk}
-        except:
-            d = {}
-
-        return d
-
-    # for the old django admin UI
-    def __unicode__(self):
-        if hasattr(self, "name") and self.name:
-            return u'%s' % self.name
-        elif hasattr(self, "id") and self.id:
-            return u'%s-%s' % (self.__class__.__name__, self.id)
-        else:
-            return u'%s-unsaved' % self.__class__.__name__
-
-    def get_content_type_key(self):
-        ct = ContentType.objects.get_for_model(self.__class__)
-        return "%s.%s" % (ct.app_label, ct.model)
-
-    @staticmethod
-    def get_content_type_from_key(key):
-        (app_name, model_name) = key.split(".")
-        return ContentType.objects.get_by_natural_key(app_name, model_name)
-
-    @staticmethod
-    def get_content_object(content_type, object_id):
-        ct = PlCoreBase.get_content_type_from_key(content_type)
-        cls = ct.model_class()
-        return cls.objects.get(id=object_id)
-
-class ModelLink:
-    def __init__(self,dest,via,into=None):
-        self.dest=dest
-        self.via=via
-        self.into=into
-
-
diff --git a/xos/core/models/port.xproto b/xos/core/models/port.xproto
index a3a9cdc..115b0db 100644
--- a/xos/core/models/port.xproto
+++ b/xos/core/models/port.xproto
@@ -1,6 +1,6 @@
 
 
-message Port (PlCoreBase,ParameterMixin){
+message Port (XOSBase,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];
diff --git a/xos/core/models/role.xproto b/xos/core/models/role.xproto
index 9e48abc..d55dcc0 100644
--- a/xos/core/models/role.xproto
+++ b/xos/core/models/role.xproto
@@ -1,6 +1,6 @@
 
 
-message Role (PlCoreBase){
+message Role (XOSBase){
      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];
diff --git a/xos/core/models/service.xproto b/xos/core/models/service.xproto
index 74bb66d..daaddf6 100644
--- a/xos/core/models/service.xproto
+++ b/xos/core/models/service.xproto
@@ -1,6 +1,6 @@
 
 
-message Service (PlCoreBase,AttributeMixin){
+message Service (XOSBase,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];
diff --git a/xos/core/models/serviceattribute.xproto b/xos/core/models/serviceattribute.xproto
index d333aa2..8c9d209 100644
--- a/xos/core/models/serviceattribute.xproto
+++ b/xos/core/models/serviceattribute.xproto
@@ -1,6 +1,6 @@
 
 
-message ServiceAttribute (PlCoreBase){
+message ServiceAttribute (XOSBase){
      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/servicemonitoringagentinfo.xproto b/xos/core/models/servicemonitoringagentinfo.xproto
index 4a4e466..59ce1c8 100644
--- a/xos/core/models/servicemonitoringagentinfo.xproto
+++ b/xos/core/models/servicemonitoringagentinfo.xproto
@@ -1,6 +1,6 @@
 
 
-message ServiceMonitoringAgentInfo (PlCoreBase){
+message ServiceMonitoringAgentInfo (XOSBase){
      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
index f88acef..6714b17 100644
--- a/xos/core/models/serviceprivilege.xproto
+++ b/xos/core/models/serviceprivilege.xproto
@@ -1,6 +1,6 @@
 
 
-message ServicePrivilege (PlCoreBase){
+message ServicePrivilege (XOSBase){
      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/servicerole.xproto b/xos/core/models/servicerole.xproto
index 3661df4..74c9bb9 100644
--- a/xos/core/models/servicerole.xproto
+++ b/xos/core/models/servicerole.xproto
@@ -1,5 +1,5 @@
 
 
-message ServiceRole (PlCoreBase){
+message ServiceRole (XOSBase){
      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.xproto b/xos/core/models/site.xproto
index ce2fbd1..c71fa20 100644
--- a/xos/core/models/site.xproto
+++ b/xos/core/models/site.xproto
@@ -1,6 +1,6 @@
 
 
-message Site (PlCoreBase){
+message Site (XOSBase){
      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];
diff --git a/xos/core/models/sitedeployment.xproto b/xos/core/models/sitedeployment.xproto
index ae12aa1..ff23abf 100644
--- a/xos/core/models/sitedeployment.xproto
+++ b/xos/core/models/sitedeployment.xproto
@@ -1,6 +1,6 @@
 
 
-message SiteDeployment (PlCoreBase){
+message SiteDeployment (XOSBase){
      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];
diff --git a/xos/core/models/siteprivilege.xproto b/xos/core/models/siteprivilege.xproto
index c63677a..0f277c2 100644
--- a/xos/core/models/siteprivilege.xproto
+++ b/xos/core/models/siteprivilege.xproto
@@ -1,6 +1,6 @@
 
 
-message SitePrivilege (PlCoreBase){
+message SitePrivilege (XOSBase){
      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
index a42ef5c..58b638e 100644
--- a/xos/core/models/siterole.xproto
+++ b/xos/core/models/siterole.xproto
@@ -1,5 +1,5 @@
 
 
-message SiteRole (PlCoreBase){
+message SiteRole (XOSBase){
      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.xproto b/xos/core/models/slice.xproto
index 222813d..9adf2a9 100644
--- a/xos/core/models/slice.xproto
+++ b/xos/core/models/slice.xproto
@@ -1,4 +1,4 @@
-message Slice (PlCoreBase){
+message Slice (XOSBase){
      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 string description = 4 [help_text = "High level description of the slice and expected activities", max_length = 1024, null = False, db_index = False, blank = True];
diff --git a/xos/core/models/sliceprivilege.xproto b/xos/core/models/sliceprivilege.xproto
index 587f423..6c85a8c 100644
--- a/xos/core/models/sliceprivilege.xproto
+++ b/xos/core/models/sliceprivilege.xproto
@@ -1,6 +1,6 @@
 
 
-message SlicePrivilege (PlCoreBase){
+message SlicePrivilege (XOSBase){
      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
index 6396518..7d6eb19 100644
--- a/xos/core/models/slicerole.xproto
+++ b/xos/core/models/slicerole.xproto
@@ -1,5 +1,5 @@
 
 
-message SliceRole (PlCoreBase){
+message SliceRole (XOSBase){
      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/tag.xproto b/xos/core/models/tag.xproto
index 6e5daef..a2cd9b2 100644
--- a/xos/core/models/tag.xproto
+++ b/xos/core/models/tag.xproto
@@ -1,6 +1,6 @@
 
 
-message Tag (PlCoreBase){
+message Tag (XOSBase){
      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];
diff --git a/xos/core/models/tenant.xproto b/xos/core/models/tenant.xproto
index 91de112..384d119 100644
--- a/xos/core/models/tenant.xproto
+++ b/xos/core/models/tenant.xproto
@@ -1,6 +1,6 @@
 
 
-message Tenant (PlCoreBase,AttributeMixin){
+message Tenant (XOSBase,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];
diff --git a/xos/core/models/tenantattribute.xproto b/xos/core/models/tenantattribute.xproto
index f9a3abe..82c35d5 100644
--- a/xos/core/models/tenantattribute.xproto
+++ b/xos/core/models/tenantattribute.xproto
@@ -1,6 +1,6 @@
 
 
-message TenantAttribute (PlCoreBase){
+message TenantAttribute (XOSBase){
      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
index 9d90981..e98aaec 100644
--- a/xos/core/models/tenantprivilege.xproto
+++ b/xos/core/models/tenantprivilege.xproto
@@ -1,6 +1,6 @@
 
 
-message TenantPrivilege (PlCoreBase){
+message TenantPrivilege (XOSBase){
      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
index 646809e..54ed436 100644
--- a/xos/core/models/tenantrole.xproto
+++ b/xos/core/models/tenantrole.xproto
@@ -1,5 +1,5 @@
 
 
-message TenantRole (PlCoreBase){
+message TenantRole (XOSBase){
      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
index 3c01492..00c3154 100644
--- a/xos/core/models/tenantroot.xproto
+++ b/xos/core/models/tenantroot.xproto
@@ -1,6 +1,6 @@
 
 
-message TenantRoot (PlCoreBase,AttributeMixin){
+message TenantRoot (XOSBase,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];
diff --git a/xos/core/models/tenantrootprivilege.xproto b/xos/core/models/tenantrootprivilege.xproto
index cf86119..39e8b5c 100644
--- a/xos/core/models/tenantrootprivilege.xproto
+++ b/xos/core/models/tenantrootprivilege.xproto
@@ -1,6 +1,6 @@
 
 
-message TenantRootPrivilege (PlCoreBase){
+message TenantRootPrivilege (XOSBase){
      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
index 87346ac..2297b33 100644
--- a/xos/core/models/tenantrootrole.xproto
+++ b/xos/core/models/tenantrootrole.xproto
@@ -1,5 +1,5 @@
 
 
-message TenantRootRole (PlCoreBase){
+message TenantRootRole (XOSBase){
      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/user.py b/xos/core/models/user.py
index eb11c18..8a191f5 100644
--- a/xos/core/models/user.py
+++ b/xos/core/models/user.py
@@ -7,8 +7,8 @@
 from operator import attrgetter, itemgetter
 
 from core.middleware import get_request
-from core.models import DashboardView, PlCoreBase, PlModelMixIn, Site, ModelLink
-from core.models.plcorebase import StrippedCharField, XOSCollector
+from core.models import DashboardView, XOSBase, PlModelMixIn, Site, ModelLink
+from core.models.xosbase import StrippedCharField, XOSCollector
 from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
 from django.core.exceptions import PermissionDenied
 from django.core.mail import EmailMultiAlternatives
@@ -25,7 +25,7 @@
 import redis
 from redis import ConnectionError
 
-# ------ from plcorebase.py ------
+# ------ from xosbase.py ------
 try:
     # This is a no-op if observer_disabled is set to 1 in the config file
     from synchronizers.base import *
@@ -277,7 +277,7 @@
                             model.save(update_fields=['enacted','deleted','policed'], silent=silent)
 
     def save(self, *args, **kwargs):
-        journal_object(self, "plcorebase.save")
+        journal_object(self, "xosbase.save")
 
         if not self.id:
             self.set_password(self.password)
@@ -317,11 +317,11 @@
 
         self.username = self.email
 
-        journal_object(self, "plcorebase.save.super_save")
+        journal_object(self, "xosbase.save.super_save")
 
         super(User, self).save(*args, **kwargs)
 
-        journal_object(self, "plcorebase.save.super_save_returned")
+        journal_object(self, "xosbase.save.super_save_returned")
 
         self.push_redis_event()
 
@@ -625,7 +625,7 @@
         return cls.objects.get(id=object_id)
 
 
-class UserDashboardView(PlCoreBase):
+class UserDashboardView(XOSBase):
     user = models.ForeignKey(User, related_name='userdashboardviews')
     dashboardView = models.ForeignKey(
         DashboardView, related_name='userdashboardviews')
diff --git a/xos/core/models/xos.xproto b/xos/core/models/xos.xproto
index 2335b0d..32ed1d7 100644
--- a/xos/core/models/xos.xproto
+++ b/xos/core/models/xos.xproto
@@ -1,5 +1,5 @@
 
 
-message XOS (PlCoreBase){
+message XOS (XOSBase){
      required string name = 1 [default = "XOS", max_length = 200, content_type = "stripped", blank = False, help_text = "Name of XOS", null = False, db_index = False];
 }
diff --git a/xos/core/models/xosbase.xproto b/xos/core/models/xosbase.xproto
new file mode 100644
index 0000000..f3def66
--- /dev/null
+++ b/xos/core/models/xosbase.xproto
@@ -0,0 +1,15 @@
+message XOSBase {
+     required string created = 1 [content_type = "date", auto_now_add = True];
+     required string updated = 2 [default = "now()", content_type = "date"];
+     optional string enacted = 3 [null = True, content_type = "date", blank = True, default = None];
+     optional string policed = 4 [null = True, content_type = "date", blank = True, default = None];
+     optional string backend_register = 5 [default = "{}", max_length = 1024, null = True];
+     required bool backend_need_delete = 6 [default = False];
+     required bool backend_need_reap = 7 [default = False];
+     required string backend_status = 8 [default = "0 - Provisioning in progress", max_length = 1024];
+     required bool deleted = 9 [default = False];
+     required bool write_protect = 10 [default = False];
+     required bool lazy_blocked = 11 [default = False];
+     required bool no_sync = 12 [default = False];
+     required bool no_policy = 13 [default = False];
+}
diff --git a/xos/core/models/xosbase_header.py b/xos/core/models/xosbase_header.py
new file mode 120000
index 0000000..dd654e6
--- /dev/null
+++ b/xos/core/models/xosbase_header.py
@@ -0,0 +1 @@
+attic/xosbase_header.py
\ No newline at end of file
diff --git a/xos/core/models/xosguiextension.xproto b/xos/core/models/xosguiextension.xproto
index 774de4e..5d0c58e 100644
--- a/xos/core/models/xosguiextension.xproto
+++ b/xos/core/models/xosguiextension.xproto
@@ -1,6 +1,6 @@
 
 
-message XOSGuiExtension (PlCoreBase){
+message XOSGuiExtension (XOSBase){
      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/coreapi/apihelper.py b/xos/coreapi/apihelper.py
index e64a8a2..e76bf97 100644
--- a/xos/coreapi/apihelper.py
+++ b/xos/coreapi/apihelper.py
@@ -185,11 +185,11 @@
                 getattr(p_obj,related_name+"_ids").append(rel_obj.id)
 
         # Generate a list of class names for the object. This includes its
-        # ancestors. Anything that is a descendant of PlCoreBase or User
+        # ancestors. Anything that is a descendant of XOSBase or User
         # counts.
 
         bases = inspect.getmro(obj.__class__)
-        bases = [x for x in bases if issubclass(x, PlCoreBase) or issubclass(x, User)]
+        bases = [x for x in bases if issubclass(x, XOSBase) or issubclass(x, User)]
         p_obj.class_names = ",".join( [x.__name__ for x in bases] )
 
         p_obj.self_content_type_id = obj.get_content_type_key()
diff --git a/xos/coreapi/reaper.py b/xos/coreapi/reaper.py
index f7adb06..879831e 100644
--- a/xos/coreapi/reaper.py
+++ b/xos/coreapi/reaper.py
@@ -25,7 +25,7 @@
 from django.dispatch import receiver
 from django.utils import timezone
 from django.db import models as django_models
-from core.models.plcorebase import XOSCollector
+from core.models.xosbase import XOSCollector
 from django.db import router
 from xos.logger import Logger, logging
 
diff --git a/xos/generate/dependency_walker.py b/xos/generate/dependency_walker.py
index 210ec0f..65721a9 100644
--- a/xos/generate/dependency_walker.py
+++ b/xos/generate/dependency_walker.py
@@ -85,7 +85,7 @@
 				peer_objects = []
 
 			for o in peer_objects:
-				#if (isinstance(o,PlCoreBase)):
+				#if (isinstance(o,XOSBase)):
 				if (hasattr(o,'updated')):
 					fn(o, object)
 					ret.append(o)
diff --git a/xos/genx/targets/django-split.xtarget b/xos/genx/targets/django-split.xtarget
index f3a998b..af3a8cc 100644
--- a/xos/genx/targets/django-split.xtarget
+++ b/xos/genx/targets/django-split.xtarget
@@ -1,7 +1,6 @@
 
-from header import *
 {% for m in proto.messages %}
-{% if file_exists(xproto_base_name(m.name)|lower+'_header.py') -%}from {{xproto_base_name(m.name)|lower }}_header import *{% endif %}
+{% if file_exists(xproto_base_name(m.name)|lower+'_header.py') -%}from {{xproto_base_name(m.name)|lower }}_header import *{%- else -%}from header import *{% endif %}
 {% if file_exists(xproto_base_name(m.name)|lower+'_top.py') -%}{{ include_file(xproto_base_name(m.name)|lower+'_top.py') }} {% endif %}
 
 {%- for l in m.links %}
@@ -12,13 +11,13 @@
 
 {%- endfor %}
 {% for b in m.bases %}
-{% if b!='PlCoreBase' and 'Mixin' not in b%}
+{% if b!='XOSBase' and 'Mixin' not in b%}
 from core.models.{{b | lower}} import {{ b }}
 {% endif %}
 {% endfor %}
 
 
-class {{ m.name }}{{ xproto_base_def(m.bases) }}:
+class {{ m.name }}{{ xproto_base_def(m.name, m.bases) }}:
   # Primitive Fields (Not Relations)
   {% for f in m.fields %}
   {%- if not f.link -%}
diff --git a/xos/genx/targets/django.xtarget b/xos/genx/targets/django.xtarget
index 131676a..8ebd2a7 100644
--- a/xos/genx/targets/django.xtarget
+++ b/xos/genx/targets/django.xtarget
@@ -12,13 +12,13 @@
 
 {%- endfor %}
 {% for b in m.bases %}
-{% if b!='PlCoreBase' and 'Mixin' not in b%}
+{% if b!='XOSBase' and 'Mixin' not in b%}
 from core.models.{{b | lower}} import {{ b }}
 {% endif %}
 {% endfor %}
 
 
-class {{ m.name }}{{ xproto_base_def(m.bases) }}:
+class {{ m.name }}{{ xproto_base_def(m.name, m.bases) }}:
   # Primitive Fields (Not Relations)
   {% for f in m.fields %}
   {%- if not f.link -%}
diff --git a/xos/genx/targets/init.xtarget b/xos/genx/targets/init.xtarget
index 770502d..b089e53 100644
--- a/xos/genx/targets/init.xtarget
+++ b/xos/genx/targets/init.xtarget
@@ -1,7 +1,7 @@
 # The hardcoded entries cannot be inferred from the models. To get rid of in the long run
 # 
 
-from .plcorebase import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager,PlModelMixIn,ModelLink
+from .xosbase import XOSBase,XOSBaseManager,XOSBaseDeletionManager,PlModelMixIn,ModelLink
 from .contenttype import ContentType
 from .site import Site
 from .dashboardview import DashboardView
diff --git a/xos/genx/targets/service.xtarget b/xos/genx/targets/service.xtarget
index c2256d2..e5bf019 100644
--- a/xos/genx/targets/service.xtarget
+++ b/xos/genx/targets/service.xtarget
@@ -10,7 +10,7 @@
 {%- endif -%}
 {%- endfor -%}
 {%- for b in m.bases -%}
-{%- if b!='PlCoreBase' and 'Mixin' not in b -%}
+{%- if b!='XOSBase' and 'Mixin' not in b -%}
 #from core.models.{{b | lower}} import {{ b }}
 from core.models import {{ b }}
 {%- endif -%}
@@ -20,7 +20,7 @@
 
 {% for m in proto.messages %}
 
-class {{ m.name }}{{ xproto_base_def(m.bases) }}:
+class {{ m.name }}{{ xproto_base_def(m.name, m.bases) }}:
 
   KIND = {{ xproto_first_non_empty([m.options.kind, options.kind, options.name, "Set a kind in your xproto!"]) }}
 
diff --git a/xos/genx/tool/lib.py b/xos/genx/tool/lib.py
index 1e0cf4d..6a5409b 100644
--- a/xos/genx/tool/lib.py
+++ b/xos/genx/tool/lib.py
@@ -62,8 +62,10 @@
     else:
         return 'TextField'
 
-def xproto_base_def(base):
-    if (not base):
+def xproto_base_def(model_name, base):
+    if (model_name=='XOSBase'):
+        return '(models.Model, PlModelMixIn)'
+    elif (not base):
         return ''
     else:
         return '(' + ','.join(base) + ')'
@@ -137,7 +139,7 @@
         return ', '.join(lst)
 
 def map_xproto_to_django(f):
-    allowed_keys=['help_text','default','max_length','modifier','blank','choices','db_index','null','editable','on_delete','verbose_name'] 
+    allowed_keys=['help_text','default','max_length','modifier','blank','choices','db_index','null','editable','on_delete','verbose_name', 'auto_now_add'] 
 
     m = {'modifier':{'optional':True, 'required':False, '_target':'null'}}
     out = {}
@@ -183,7 +185,7 @@
     if (n.startswith('NetworkParameter')):
         return '_'
 
-    expr = r'^[A-Z][a-z]+'
+    expr = r'^[A-Z]+[a-z]*'
 
     try:
         match = re.findall(expr, n)[0]
diff --git a/xos/genx/tool/tests/counts b/xos/genx/tool/tests/counts
index c08e39b..8ab44d4 100755
--- a/xos/genx/tool/tests/counts
+++ b/xos/genx/tool/tests/counts
@@ -2,7 +2,7 @@
 
 import core.models
 import inspect
-from core.models import PlCoreBase, PlModelMixIn
+from core.models import XOSBase, PlModelMixIn
 import pdb
 
 def count(lst):
@@ -21,7 +21,7 @@
         return False
     bases = inspect.getmro(model)
     bases = [x.__name__ for x in bases]
-    if ("PlCoreBase" in bases) or ("PlModelMixIn" in bases):
+    if ("XOSBase" in bases) or ("PlModelMixIn" in bases):
         return True
 
     return False
diff --git a/xos/genx/tool/tests/django_generator_test.py b/xos/genx/tool/tests/django_generator_test.py
index 4ea339a..052a48f 100644
--- a/xos/genx/tool/tests/django_generator_test.py
+++ b/xos/genx/tool/tests/django_generator_test.py
@@ -5,7 +5,7 @@
     def test_proto_generator(self):
         xproto = \
 """
-message VRouterPort (PlCoreBase){
+message VRouterPort (XOSBase){
      optional string name = 1 [help_text = "port friendly name", max_length = 20, null = True, db_index = False, blank = True];
      required string openflow_id = 2 [help_text = "port identifier in ONOS", max_length = 21, null = False, db_index = False, blank = False];
      required manytoone vrouter_device->VRouterDevice:ports = 3 [db_index = True, null = False, blank = False];
@@ -27,7 +27,7 @@
 
 {%- endfor %}
 {% for b in m.bases %}
-{% if b!='PlCoreBase' and 'Mixin' not in b%}
+{% if b!='XOSBase' and 'Mixin' not in b%}
 from core.models.{{b | lower}} import {{ b }}
 {% endif %}
 {% endfor %}
diff --git a/xos/genx/tool/tests/proto_generator_test.py b/xos/genx/tool/tests/proto_generator_test.py
index b36f109..f9c2d69 100644
--- a/xos/genx/tool/tests/proto_generator_test.py
+++ b/xos/genx/tool/tests/proto_generator_test.py
@@ -9,7 +9,7 @@
     def __disabled_test_proto_generator(self):
         xproto = \
 """
-message VRouterPort (PlCoreBase){
+message VRouterPort (XOSBase){
      optional string name = 1 [help_text = "port friendly name", max_length = 20, null = True, db_index = False, blank = True];
      required string openflow_id = 2 [help_text = "port identifier in ONOS", max_length = 21, null = False, db_index = False, blank = False];
      required manytoone vrouter_device->VRouterDevice:ports = 3 [db_index = True, null = False, blank = False];
diff --git a/xos/genx/tool/tests/pure_proto_test.py b/xos/genx/tool/tests/pure_proto_test.py
index 8402c93..e6153a3 100644
--- a/xos/genx/tool/tests/pure_proto_test.py
+++ b/xos/genx/tool/tests/pure_proto_test.py
@@ -5,7 +5,7 @@
     def test_pure_proto(self):
         xproto = \
 """
-message VRouterPort (PlCoreBase){
+message VRouterPort (XOSBase){
      optional string name = 1 [help_text = "port friendly name", max_length = 20, null = True, db_index = False, blank = True];
      required string openflow_id = 2 [help_text = "port identifier in ONOS", max_length = 21, null = False, db_index = False, blank = False];
      required manytoone vrouter_device->VRouterDevice:ports = 3 [db_index = True, null = False, blank = False];
@@ -16,7 +16,7 @@
         proto = \
 """
 message VRouterPort {
-  option bases = "PlCoreBase";
+  option bases = "XOSBase";
   optional string name = 1 [ null = "True",  max_length = "20",  blank = "True",  help_text = "port friendly name",  modifier = "optional",  db_index = "False" ];
   required string openflow_id = 2 [ null = "False",  max_length = "21",  blank = "False",  help_text = "port identifier in ONOS",  modifier = "required",  db_index = "False" ];
   required int32 vrouter_device = 3 [ null = "False",  blank = "False",  model = "VRouterDevice",  modifier = "required",  type = "link",  port = "ports",  db_index = "True", link = "manytoone"];
@@ -38,7 +38,7 @@
 
 {%- endfor %}
 {% for b in m.bases %}
-{% if b!='PlCoreBase' and 'Mixin' not in b%}
+{% if b!='XOSBase' and 'Mixin' not in b%}
 from core.models.{{b | lower}} import {{ b }}
 {% endif %}
 {% endfor %}
diff --git a/xos/services/syndicate_storage/models.py b/xos/services/syndicate_storage/models.py
index 6ea9c41..ccaf813 100644
--- a/xos/services/syndicate_storage/models.py
+++ b/xos/services/syndicate_storage/models.py
@@ -1,4 +1,4 @@
-from core.models import User,Site,Service,PlCoreBase,Slice,SlicePrivilege
+from core.models import User,Site,Service,XOSBase,Slice,SlicePrivilege
 import os
 from django.db import models
 from django.db.models import Q
@@ -16,7 +16,7 @@
     def __unicode__(self):  return u'Syndicate Service'
 
 
-class SyndicatePrincipal(PlCoreBase):
+class SyndicatePrincipal(XOSBase):
     class Meta:
         app_label = "syndicate_storage"
 
@@ -28,7 +28,7 @@
     def __unicode__self(self):  return "%s" % self.principal_id
 
 
-class Volume(PlCoreBase):
+class Volume(XOSBase):
     class Meta:
         app_label = "syndicate_storage"
 
@@ -64,7 +64,7 @@
         return qs
 
 
-class VolumeAccessRight(PlCoreBase):
+class VolumeAccessRight(XOSBase):
     class Meta:
         app_label = "syndicate_storage"
 
@@ -171,7 +171,7 @@
           raise syndicatelib.SyndicateObserverError( "Internal Syndicate Observer error: No slice secret generated" )
                                                     
 
-class SliceSecret(models.Model):        # NOTE: not a PlCoreBase
+class SliceSecret(models.Model):        # NOTE: not a XOSBase
     class Meta:
        app_label = "syndicate_storage"
     
@@ -195,7 +195,7 @@
         return qs
  
 
-class VolumeSlice(PlCoreBase):
+class VolumeSlice(XOSBase):
     class Meta:
         app_label = "syndicate_storage"
 
diff --git a/xos/synchronizers/ec2/dmdot b/xos/synchronizers/ec2/dmdot
index de07a78..9b2b587 100644
--- a/xos/synchronizers/ec2/dmdot
+++ b/xos/synchronizers/ec2/dmdot
@@ -21,7 +21,7 @@
 model_classes = []
 class_names = []
 for c in g.values():
-	if type(c)==type(PlCoreBase):
+	if type(c)==type(XOSBase):
 		model_classes.append(c)
 		class_names.append(c.__name__)
 
diff --git a/xos/synchronizers/new_base/modelaccessor.py b/xos/synchronizers/new_base/modelaccessor.py
index 9b9e657..51c326e 100644
--- a/xos/synchronizers/new_base/modelaccessor.py
+++ b/xos/synchronizers/new_base/modelaccessor.py
@@ -94,7 +94,7 @@
     for (k, v) in model_accessor.all_model_classes.items():
         globals()[k] = v
 
-    # plcorebase doesn't exist from the synchronizer's perspective, so fake out
+    # xosbase doesn't exist from the synchronizer's perspective, so fake out
     # ModelLink.
     if "ModelLink" not in globals():
         class ModelLink:
diff --git a/xos/tools/apigen/modelgen b/xos/tools/apigen/modelgen
index 7ef76a4..215feb9 100755
--- a/xos/tools/apigen/modelgen
+++ b/xos/tools/apigen/modelgen
@@ -22,7 +22,7 @@
 
 django.setup()
 
-from core.models import PlCoreBase
+from core.models import XOSBase
 
 options = None
 
@@ -34,7 +34,7 @@
         return False
     bases = inspect.getmro(model)
     bases = [x.__name__ for x in bases]
-    if ("PlCoreBase" in bases) or ("PlModelMixIn" in bases):
+    if ("XOSBase" in bases) or ("PlModelMixIn" in bases):
         return True
 
     return False
@@ -127,7 +127,6 @@
 		self.refs = []
                 self.reverse_refs = []
 		self.plural_name = None
-                self.content_type_id = ContentType.objects.get_for_model(m).id
 
 	def plural(self):
 		if (self.plural_name):
@@ -204,7 +203,7 @@
 		self[str(obj).lower()]=obj
 
 	def compute_links(self):
-                base_props = [f.name for f in PlCoreBase._meta.fields]
+                base_props = [f.name for f in XOSBase._meta.fields]
 
 		for obj in self.values():
 			#if (str(obj)=='network'):
@@ -290,9 +289,9 @@
         parser.add_option("-a", "--app", dest="apps",
              help="list of applications to parse", metavar="APP", default=[], action="append")
         parser.add_option("-b", "--blacklist", dest="blacklist",
-             help="add model name to blacklist", metavar="MODEL", default=["SingletonModel", "PlCoreBase"], action="append")
+             help="add model name to blacklist", metavar="MODEL", default=["SingletonModel", "XOSBase"], action="append")
         parser.add_option("-n", "--no-rest", dest="norest",
-             help="do not generate rest api for model", metavar="MODEL", default=["SingletonModel", "PlCoreBase"], action="append")
+             help="do not generate rest api for model", metavar="MODEL", default=["SingletonModel", "XOSBase"], action="append")
 
         (options, args) = parser.parse_args(sys.argv[1:])
 
diff --git a/xos/tools/apigen/modelgen2 b/xos/tools/apigen/modelgen2
index b78719a..5620f9f 100755
--- a/xos/tools/apigen/modelgen2
+++ b/xos/tools/apigen/modelgen2
@@ -24,7 +24,7 @@
 
 django.setup()
 
-from core.models import PlCoreBase
+from core.models import XOSBase
 
 options = None
 
@@ -37,7 +37,7 @@
         return False
     bases = inspect.getmro(model)
     bases = [x.__name__ for x in bases]
-    if ("PlCoreBase" in bases) or ("PlModelMixIn" in bases):
+    if ("XOSBase" in bases) or ("PlModelMixIn" in bases):
         return True
 
     return False
@@ -307,9 +307,9 @@
         parser.add_option("-a", "--app", dest="apps",
              help="list of applications to parse", metavar="APP", default=[], action="append")
         parser.add_option("-b", "--blacklist", dest="blacklist",
-             help="add model name to blacklist", metavar="MODEL", default=["SingletonModel", "PlCoreBase"], action="append")
+             help="add model name to blacklist", metavar="MODEL", default=["SingletonModel", "XOSBase"], action="append")
         parser.add_option("-n", "--no-rest", dest="norest",
-             help="do not generate rest api for model", metavar="MODEL", default=["SingletonModel", "PlCoreBase"], action="append")
+             help="do not generate rest api for model", metavar="MODEL", default=["SingletonModel", "XOSBase"], action="append")
         parser.add_option("-l", "--local", dest="local",
              help="skip base models", metavar="MODEL", default=False, action="store_true")
         (options, args) = parser.parse_args(sys.argv[1:])
diff --git a/xos/tools/dmdot b/xos/tools/dmdot
index 9cde0ed..d0e6566 100755
--- a/xos/tools/dmdot
+++ b/xos/tools/dmdot
@@ -44,15 +44,15 @@
 	#models_module = imp.load_source(app, ".")
 	models_module = __import__(app)
 	for part in app.split(".")[1:]:
-	    if hasattr(models_module, "PlCoreBase"):
+	    if hasattr(models_module, "XOSBase"):
 		break
 	    models_module = getattr(models_module,part)
 
-	PlCoreBase = getattr(models_module,"PlCoreBase")
+	XOSBase = getattr(models_module,"XOSBase")
 
 	for classname in dir(models_module):
 		c = getattr(models_module, classname, None)
-		if type(c)==type(PlCoreBase):
+		if type(c)==type(XOSBase):
 			model_classes.append(c)
 			class_names.append(c.__name__)
 			lower_class_names[c.__name__.lower()] = c
diff --git a/xos/tools/mldeps b/xos/tools/mldeps
index c4dc68a..12a0edc 100755
--- a/xos/tools/mldeps
+++ b/xos/tools/mldeps
@@ -46,15 +46,15 @@
     #models_module = imp.load_source(app, ".")
     models_module = __import__(app)
     for part in app.split(".")[1:]:
-        if hasattr(models_module, "PlCoreBase"):
+        if hasattr(models_module, "XOSBase"):
             break
         models_module = getattr(models_module,part)
 
-    PlCoreBase = getattr(models_module,"PlCoreBase")
+    XOSBase = getattr(models_module,"XOSBase")
 
     for classname in dir(models_module):
         c = getattr(models_module, classname, None)
-        if type(c)==type(PlCoreBase):
+        if type(c)==type(XOSBase):
             model_classes.append(c)
             class_names.append(c.__name__)
             lower_class_names[c.__name__.lower()] = c