Merge branch 'master' of github.com:open-cloud/xos
diff --git a/xos/core/models/site.py b/xos/core/models/site.py
index 3e8fb82..689dea0 100644
--- a/xos/core/models/site.py
+++ b/xos/core/models/site.py
@@ -2,6 +2,7 @@
 from django.db import models
 from django.db.models import Q
 from django.contrib.contenttypes import generic
+from django.core.exceptions import PermissionDenied
 from geoposition.fields import GeopositionField
 from core.models import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager
 from core.models import Tag
@@ -130,6 +131,8 @@
     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):
diff --git a/xos/core/models/slice.py b/xos/core/models/slice.py
index d2998b0..44a918b 100644
--- a/xos/core/models/slice.py
+++ b/xos/core/models/slice.py
@@ -130,6 +130,11 @@
 
     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).delete(*args, **kwds)    
+
     def can_update(self, user):
         return user.can_update_slice(self.slice)
 
diff --git a/xos/core/models/user.py b/xos/core/models/user.py
index dc96c22..e34abdb 100644
--- a/xos/core/models/user.py
+++ b/xos/core/models/user.py
@@ -107,7 +107,7 @@
 
     phone = StrippedCharField(null=True, blank=True, help_text="phone number contact", max_length=100)
     user_url = models.URLField(null=True, blank=True)
-    site = models.ForeignKey(Site, related_name='users', help_text="Site this user will be homed too", null=True)
+    site = models.ForeignKey(Site, related_name='users', help_text="Site this user will be homed too")
     public_key = models.TextField(null=True, blank=True, max_length=1024, help_text="Public key string")
 
     is_active = models.BooleanField(default=True)
diff --git a/xos/openstack_observer/steps/purge_disabled_users.py b/xos/openstack_observer/steps/purge_disabled_users.py
new file mode 100644
index 0000000..9e30708
--- /dev/null
+++ b/xos/openstack_observer/steps/purge_disabled_users.py
@@ -0,0 +1,24 @@
+import os
+import base64
+import datetime
+from django.db.models import F, Q
+from xos.config import Config
+from observer.openstacksyncstep import OpenStackSyncStep
+from core.models.user import User
+from util.logger import observer_logger as logger
+
+class SyncRoles(OpenStackSyncStep):
+    provides=[User]
+    requested_interval=0
+    observes=User
+
+    def fetch_pending(self, deleted):
+        if (deleted):
+            # users marked as deleted
+            return User.deleted_objects.all()
+        else:
+            # disabled users that haven't been updated in over a week 
+            one_week_ago = datetime.datetime.now() - datetime.timedelta(days=7)
+            return User.objects.filter(is_active=False, updated__gt=one_week_ago)             
+    def sync_record(self, user):
+        user.delete() 
diff --git a/xos/openstack_observer/steps/sync_controller_images.py b/xos/openstack_observer/steps/sync_controller_images.py
index 68f4321..19009dd 100644
--- a/xos/openstack_observer/steps/sync_controller_images.py
+++ b/xos/openstack_observer/steps/sync_controller_images.py
@@ -6,11 +6,9 @@
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models import Controller
 from core.models import Image, ControllerImages
-from util.logger import Logger, logging
+from util.logger import observer_logger as logger 
 from observer.ansible import *
 
-logger = Logger(level=logging.INFO)
-
 class SyncControllerImages(OpenStackSyncStep):
     provides=[ControllerImages]
     observes = ControllerImages
diff --git a/xos/openstack_observer/steps/sync_controller_networks.py b/xos/openstack_observer/steps/sync_controller_networks.py
index bdf53a0..cb758ec 100644
--- a/xos/openstack_observer/steps/sync_controller_networks.py
+++ b/xos/openstack_observer/steps/sync_controller_networks.py
@@ -8,14 +8,12 @@
 from core.models.network import *
 from core.models.slice import *
 from core.models.sliver import Sliver
-from util.logger import Logger, logging
+from util.logger import observer_logger as logger
 from observer.ansible import *
 from openstack.driver import OpenStackDriver
 
 import pdb
 
-logger = Logger(level=logging.INFO)
-
 class SyncControllerNetworks(OpenStackSyncStep):
     requested_interval = 0
     provides=[Network]
diff --git a/xos/openstack_observer/steps/sync_controller_site_privileges.py b/xos/openstack_observer/steps/sync_controller_site_privileges.py
index e58f9a1..499a0ff 100644
--- a/xos/openstack_observer/steps/sync_controller_site_privileges.py
+++ b/xos/openstack_observer/steps/sync_controller_site_privileges.py
@@ -7,12 +7,9 @@
 from core.models.site import Controller, SitePrivilege 
 from core.models.user import User
 from core.models.controlleruser import ControllerUser, ControllerSitePrivilege
-from util.logger import Logger, logging
-
+from util.logger import observer_logger as logger
 from observer.ansible import *
 
-logger = Logger(level=logging.INFO)
-
 class SyncControllerSitePrivileges(OpenStackSyncStep):
     provides=[SitePrivilege]
     requested_interval=0
diff --git a/xos/openstack_observer/steps/sync_controller_sites.py b/xos/openstack_observer/steps/sync_controller_sites.py
index 9aa6c5b..acb6ba9 100644
--- a/xos/openstack_observer/steps/sync_controller_sites.py
+++ b/xos/openstack_observer/steps/sync_controller_sites.py
@@ -5,6 +5,7 @@
 from openstack_observer.openstacksyncstep import OpenStackSyncStep
 from core.models.site import *
 from observer.ansible import *
+from util.logger import observer_logger as logger
 
 class SyncControllerSites(OpenStackSyncStep):
     requested_interval=0
diff --git a/xos/openstack_observer/steps/sync_controller_slice_privileges.py b/xos/openstack_observer/steps/sync_controller_slice_privileges.py
index bb03bc3..f1600ca 100644
--- a/xos/openstack_observer/steps/sync_controller_slice_privileges.py
+++ b/xos/openstack_observer/steps/sync_controller_slice_privileges.py
@@ -7,11 +7,8 @@
 from core.models.slice import Controller, SlicePrivilege 
 from core.models.user import User
 from core.models.controlleruser import ControllerUser, ControllerSlicePrivilege
-from util.logger import Logger, logging
-
 from observer.ansible import *
-
-logger = Logger(level=logging.INFO)
+from util.logger import observer_logger as logger
 
 class SyncControllerSlicePrivileges(OpenStackSyncStep):
     provides=[SlicePrivilege]
diff --git a/xos/openstack_observer/steps/sync_controller_slices.py b/xos/openstack_observer/steps/sync_controller_slices.py
index fa62dba..591a1b6 100644
--- a/xos/openstack_observer/steps/sync_controller_slices.py
+++ b/xos/openstack_observer/steps/sync_controller_slices.py
@@ -8,11 +8,9 @@
 from core.models import User
 from core.models.slice import Slice, ControllerSlice
 from core.models.controlleruser import ControllerUser
-from util.logger import Logger, logging, logger
 from observer.ansible import *
 from openstack.driver import OpenStackDriver
-
-logger = Logger(level=logging.INFO)
+from util.logger import observer_logger as logger
 
 class SyncControllerSlices(OpenStackSyncStep):
     provides=[Slice]
diff --git a/xos/openstack_observer/steps/sync_controller_users.py b/xos/openstack_observer/steps/sync_controller_users.py
index 43053b7..acb3050 100644
--- a/xos/openstack_observer/steps/sync_controller_users.py
+++ b/xos/openstack_observer/steps/sync_controller_users.py
@@ -7,11 +7,8 @@
 from core.models.site import Controller, SiteDeployment, SiteDeployment
 from core.models.user import User
 from core.models.controlleruser import ControllerUser
-from util.logger import Logger, logging
-
 from observer.ansible import *
-
-logger = Logger(level=logging.INFO)
+from util.logger import observer_logger as logger
 
 class SyncControllerUsers(OpenStackSyncStep):
     provides=[User]
diff --git a/xos/openstack_observer/steps/sync_images.py b/xos/openstack_observer/steps/sync_images.py
index 5133b7a..d126834 100644
--- a/xos/openstack_observer/steps/sync_images.py
+++ b/xos/openstack_observer/steps/sync_images.py
@@ -4,9 +4,7 @@
 from xos.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models.image import Image
-from util.logger import Logger, logging
-
-logger = Logger(level=logging.INFO)
+from util.logger import observer_logger as logger
 
 class SyncImages(OpenStackSyncStep):
     provides=[Image]
diff --git a/xos/openstack_observer/steps/sync_network_slivers.py b/xos/openstack_observer/steps/sync_network_slivers.py
index 024e1d6..78751d1 100644
--- a/xos/openstack_observer/steps/sync_network_slivers.py
+++ b/xos/openstack_observer/steps/sync_network_slivers.py
@@ -5,9 +5,7 @@
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models import Controller
 from core.models.network import *
-from util.logger import Logger, logging
-
-logger = Logger(level=logging.INFO)
+from util.logger import observer_logger as logger
 
 class SyncNetworkSlivers(OpenStackSyncStep):
     requested_interval = 0 # 3600
diff --git a/xos/openstack_observer/steps/sync_roles.py b/xos/openstack_observer/steps/sync_roles.py
index 0bd26c6..42a36c6 100644
--- a/xos/openstack_observer/steps/sync_roles.py
+++ b/xos/openstack_observer/steps/sync_roles.py
@@ -6,6 +6,7 @@
 from core.models.role import Role
 from core.models.site import SiteRole, Controller, ControllerRole
 from core.models.slice import SliceRole
+from util.logger import observer_logger as logger
 
 class SyncRoles(OpenStackSyncStep):
     provides=[Role]
diff --git a/xos/openstack_observer/steps/sync_slivers.py b/xos/openstack_observer/steps/sync_slivers.py
index 539efba..1774e69 100644
--- a/xos/openstack_observer/steps/sync_slivers.py
+++ b/xos/openstack_observer/steps/sync_slivers.py
@@ -8,10 +8,8 @@
 from core.models.sliver import Sliver
 from core.models.slice import Slice, SlicePrivilege, ControllerSlice
 from core.models.network import Network, NetworkSlice, ControllerNetwork
-from util.logger import Logger, logging
 from observer.ansible import *
-
-logger = Logger(level=logging.INFO)
+from util.logger import observer_logger as logger
 
 def escape(s):
     s = s.replace('\n',r'\n').replace('"',r'\"')