initial checkin of observer
diff --git a/planetstack/openstack/driver.py b/planetstack/openstack/driver.py
index a38b0a1..e9988e3 100644
--- a/planetstack/openstack/driver.py
+++ b/planetstack/openstack/driver.py
@@ -69,6 +69,10 @@
     def delete_user(self, id):
         users = self.shell.keystone.users.findall(id=id)
         for user in users:
+            # delete users keys
+            keys = self.shell.nova.keypairs.findall()
+            for key in keys:
+                self.shell.nova.keypairs.delete(key)
             self.shell.keystone.users.delete(user)
         return 1 
 
diff --git a/planetstack/openstack/manager.py b/planetstack/openstack/manager.py
index 3c77952..e310883 100644
--- a/planetstack/openstack/manager.py
+++ b/planetstack/openstack/manager.py
@@ -54,15 +54,18 @@
                 self.init_admin()
 
     @require_enabled 
-    def init_user(self, auth, caller):
+    def init_caller(self, caller, tenant):
+        auth = {'username': caller.email,
+                'password': '',
+                'tenant': tenant}
         self.client = OpenStackClient(**auth)
         self.driver = OpenStackDriver(client=self.client)
         self.caller = caller                 
     
     @require_enabled
-    def init_admin(self):
+    def init_admin(self, tenant=None):
         # use the admin credentials 
-        self.client = OpenStackClient()
+        self.client = OpenStackClient(tenant=tenant)
         self.driver = OpenStackDriver(client=self.client)
         self.caller = self.driver.admin_user
         self.caller.kuser_id = self.caller.id 
@@ -203,8 +206,8 @@
             if subnet:
                 self.driver.delete_external_route(subnet)
 
-    
 
+    @require_enabled
     def get_next_subnet(self):
         # limit ourself to 10.0.x.x for now
         valid_subnet = lambda net: net.startswith('10.0')  
diff --git a/planetstack/openstack/observer.py b/planetstack/openstack/observer.py
new file mode 100644
index 0000000..ac2d58a
--- /dev/null
+++ b/planetstack/openstack/observer.py
@@ -0,0 +1,120 @@
+import time
+from datetime import datetime
+from core.models import *
+from django.db.models import F, Q
+from openstack.manager import OpenStackManager
+
+
+class OpenStackObserver:
+    
+    def __init__(self):
+        self.manager = OpenStackManager() 
+
+    def sync_sites(self):
+        """
+        save all sites where enacted < updated or enacted == None. Remove sites that
+        no don't exist in openstack db if they have an enacted time (enacted != None).
+        """ 
+        # get all sites that need to be synced (enacted < updated or enacted is None)
+        pending_sites = Site.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+        for site in pending_sites:
+            self.manager.save_site(site)
+            site.enacted = datetime.now()
+            site.save()
+
+        # get all sites that where enacted != null. We can assume these sites
+        # have previously been synced and need to be checed for deletion.
+        sites = Site.objects.filter(enacted__isnull=False)
+        site_dict = {}
+        for site in sites:
+            site_dict[site.login_base] = site
+
+        # delete keystone tenants that don't have a site record
+        tenants = self.manager.driver.shell.keystone.tenants.findall()
+        for tenant in tenants:
+            if tenant.name not in site_dict:
+                self.manager.driver.delete_tenant(tenant.id)
+
+    def sync_slices(self):
+        """
+        save all slices where enacted < updated or enacted == None. Remove slices that
+        no don't exist in openstack db if they have an enacted time (enacted != None).
+        """
+        # get all slices that need to be synced (enacted < updated or enacted is None)
+        pending_slices = Slice.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+        for slice in pending_slices:
+            self.manager.save_slice(slice)
+            slice.enacted = datetime.now()
+            slice.save()
+
+        # get all slices that where enacted != null. We can assume these slices
+        # have previously been synced and need to be checed for deletion.
+        slices = Slice.objects.filter(enacted__isnull=False)
+        slice_dict = {}
+        for slice in slices:
+            slice_dict[slice.name] = slice
+
+        # delete keystone tenants that don't have a site record
+        tenants = self.manager.driver.shell.keystone.tenants.findall()
+        for tenant in tenants:
+            if tenant.name not in slice_dict:
+                self.manager.driver.delete_tenant(tenant.id)                
+
+    def sync_users(self):
+        """
+        save all users where enacted < updated or enacted == None. Remove users that
+        no don't exist in openstack db if they have an enacted time (enacted != None).
+        """ 
+        # get all users that need to be synced (enacted < updated or enacted is None)
+        pending_users = User.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+        for user in pending_users:
+            self.manager.save_user(user)
+            user.enacted = datetime.now()
+            user.save()
+
+        # get all users that where enacted != null. We can assume these users
+        # have previously been synced and need to be checed for deletion.
+        users = User.objects.filter(enacted__isnull=False)
+        user_dict = {}
+        for user in users:
+            user_dict[user.kuser_id] = user
+
+        # delete keystone users that don't have a user record
+        user = self.manager.driver.shell.keystone.users.findall()
+        for user in users:
+            if user.id not in user_dict:
+                self.manager.driver.delete_user(user.id)
+        
+
+        
+    def sync_slivers(self):
+        """
+        save all slivers where enacted < updated or enacted == None. Remove slivers that
+        no don't exist in openstack db if they have an enacted time (enacted != None).
+        """
+        # get all users that need to be synced (enacted < updated or enacted is None)
+        pending_slivers = Sliver.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+        for sliver in pending_slivers:
+            if sliver.creator:  
+                # update manager context
+                self.manager.init_caller(sliver.creator)
+                self.manager.save_sliver(sliver)
+                sliver.enacted = datetime.now()
+                sliver.save()
+
+        # get all slivers that where enacted != null. We can assume these users
+        # have previously been synced and need to be checed for deletion.
+        slivers = Sliver.objects.filter(enacted__isnull=False)
+        sliver_dict = {}
+        for sliver in slivers:
+            sliver_dict[sliver.instance_id] = sliver
+
+        # delete sliver that don't have a sliver record
+        ctx = self.manager.driver.shell.nova_db.ctx 
+        instances = self.manager.driver.shell.nova_db.instance_get_all(ctx)
+        for instance in instances:
+            if instance.id not in sliver_dict:
+                # lookup tenant and update context  
+                tenant = self.manager.driver.shell.keystone.tenants.findall(id=instance.tenant_id) 
+                self.manager.init_admin(tenant=tenant.name)  
+                self.manager.driver.destroy_instance(instance.id)