refactor
diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py
index ffa21d9..d1e4cd0 100644
--- a/planetstack/core/admin.py
+++ b/planetstack/core/admin.py
@@ -426,7 +426,7 @@
     model = SiteDeployments
     extra = 0
     suit_classes = 'suit-tab suit-tab-deployments'
-    fields = ['backend_status_icon', 'deployment','site']
+    fields = ['backend_status_icon', 'deployment','site', 'controller']
     readonly_fields = ('backend_status_icon', )
 
     def formfield_for_foreignkey(self, db_field, request, **kwargs):
@@ -435,29 +435,15 @@
 
         if db_field.name == 'deployment':
             kwargs['queryset'] = Deployment.select_by_user(request.user)
+
+        if db_field.name == 'controller':
+            kwargs['queryset'] = Controller.select_by_user(request.user)
+
         return super(SiteDeploymentsInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
 
     def queryset(self, request):
         return SiteDeployments.select_by_user(request.user)
 
-class ControllerSitesInline(PlStackTabularInline):
-    model = ControllerSites
-    extra = 0
-    suit_classes = 'suit-tab suit-tab-admin-only'
-    fields = ['backend_status_icon', 'controller','site']
-    readonly_fields = ('backend_status_icon', )
-
-    def formfield_for_foreignkey(self, db_field, request, **kwargs):
-        if db_field.name == 'site':
-            kwargs['queryset'] = Site.select_by_user(request.user)
-
-        if db_field.name == 'controller':
-            kwargs['queryset'] = Controller.select_by_user(request.user)
-        return super(ControllerSitesInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
-
-    def queryset(self, request):
-        return ControllerSites.select_by_user(request.user)
-
 
 class SlicePrivilegeInline(PlStackTabularInline):
     model = SlicePrivilege
@@ -646,6 +632,96 @@
 
         return AdminFormMetaClass
 
+class ControllerAdminForm(forms.ModelForm):
+    site_deployments = forms.ModelMultipleChoiceField(
+        queryset=SiteDeployment.objects.all(),
+        required=False,
+        help_text="Select which sites deployments are managed by this controller",
+        widget=FilteredSelectMultiple(
+            verbose_name=('Site Deployments'), is_stacked=False
+        )
+    )
+
+    class Meta: 
+        model = Controller
+        
+    def __init__(self, *args, **kwds):
+        request = kwargs.pop('request', None)
+        super(ControllerAdminForm, self).__init__(*args, **kwargs)  
+
+        if self.instance and self.instance.pk:
+            self.fields['site_deployments'].initial = [x.site_deployment for x in self.instance.controllersitedeployments.all()]
+
+        def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
+        """ helper function for handling m2m relations from the MultipleChoiceField
+            this_obj: the source object we want to link from
+            selected_objs: a list of destination objects we want to link to
+            all_relations: the full set of relations involving this_obj, including ones we don't want
+            relation_class: the class that implements the relation from source to dest
+            local_attrname: field name representing this_obj in relation_class
+            foreign_attrname: field name representing selected_objs in relation_class
+            This function will remove all newobjclass relations from this_obj
+            that are not contained in selected_objs, and add any relations that
+            are in selected_objs but don't exist in the data model yet.
+        """
+        existing_dest_objs = []
+        for relation in list(all_relations):
+            if getattr(relation, foreign_attrname) not in selected_objs:
+                #print "deleting site", sdp.site
+                relation.delete()
+            else:
+                existing_dest_objs.append(getattr(relation, foreign_attrname))
+
+        for dest_obj in selected_objs:
+            if dest_obj not in existing_dest_objs:
+                #print "adding site", site
+                kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
+                relation = relation_class(**kwargs)
+                relation.save()
+
+        def save(self, commit=True):
+            controller = super(ControllerAdminForm, self).save(commit=False)
+
+            if commit:
+                controller.save()
+
+            if controller.pk:
+                # save_m2m() doesn't seem to work with 'through' relations. So we
+                #    create/destroy the through models ourselves. There has to be
+                #    a better way...
+            self.manipulate_m2m_objs(controller, self.cleaned_data['site_deployments'], controller.controllersitedeployments.all(), ControllerSiteDeployments, "controller", "site_deployment")
+
+            self.save_m2m()
+
+            return controller 
+      
+class ControllerAdmin(PlanetStackBaseAdmin):
+    model = Controller 
+    fieldList = ['name', 'version', 'backend_type', 'auth_url', 'admin_user', 'admin_tenant',]
+    fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-admin-only']})]
+    inlines = [ControllerPrivilegeInline, ContrllerSiteInline] # ,ControllerImagesInline]
+    list_display = ['backend_status_icon', 'name', 'version', 'backend_type']
+    list_display_links = ('backend_status_icon', 'name', )
+    readonly_fields = ('backend_status_text',)
+
+    user_readonly_fields = []
+
+    def get_form(self, request, obj=None, **kwargs):
+        if request.user.isReadOnlyUser():
+            kwargs["form"] = ControllerAdminROForm
+        else:
+            kwargs["form"] = ControllerAdminForm
+        adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
+
+        # from stackexchange: pass the request object into the form
+
+        class AdminFormMetaClass(adminForm):
+           def __new__(cls, *args, **kwargs):
+               kwargs['request'] = request
+               return adminForm(*args, **kwargs)
+
+        return AdminFormMetaClass
+
 class ServiceAttrAsTabInline(PlStackTabularInline):
     model = ServiceAttribute
     fields = ['name','value']
diff --git a/planetstack/core/models/__init__.py b/planetstack/core/models/__init__.py
index 423fe0b..08e6178 100644
--- a/planetstack/core/models/__init__.py
+++ b/planetstack/core/models/__init__.py
@@ -5,11 +5,11 @@
 from .service import ServiceAttribute
 from .tag import Tag
 from .role import Role
-from .site import Site, Deployment, Controller, ControllerRole, ControllerPrivilege, SiteDeployments, ControllerSites
+from .site import Site, Deployment, Controller, ControllerRole, ControllerPrivilege, SiteDeployments, ControllerSiteDeployments
 from .dashboard import DashboardView
 from .user import User, UserDashboardView
 from .serviceclass import ServiceClass
-from .site import ControllerLinkManager,ControllerLinkDeletionManager
+from .site import ControllerManager, ControllerDeletionManager, ControllerLinkManager,ControllerLinkDeletionManager
 from .slice import Slice, ControllerSlices
 from .controllerusers import ControllerUsers
 from .image import Image, ImageDeployments, ControllerImages
diff --git a/planetstack/core/models/controlleruser.py b/planetstack/core/models/controlleruser.py
deleted file mode 100644
index 5a3568a..0000000
--- a/planetstack/core/models/controlleruser.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import os
-import datetime
-from collections import defaultdict
-from django.db import models
-from django.db.models import F, Q
-from core.models import PlCoreBase,User,Controller
-from core.models import Controller,ControllerLinkManager,ControllerLinkDeletionManager
-
-class ControllerUsers(PlCoreBase):
-    objects = ControllerLinkManager()
-    deleted_objects = ControllerLinkDeletionManager()
-
-    user = models.ForeignKey(User,related_name='controllerusers')
-    controller = models.ForeignKey(Controller,related_name='controllersusers')
-    kuser_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone user id")
-
-    def __unicode__(self):  return u'%s %s' % (self.controller, self.user)
-
-    @staticmethod
-    def select_by_user(user):
-        if user.is_admin:
-            qs = ControllerUsers.objects.all()
-        else:
-            users = Users.select_by_user(user)
-            qs = ControllerUsers.objects.filter(user__in=users)
-        return qs
diff --git a/planetstack/core/models/node.py b/planetstack/core/models/node.py
index 6ef3a47..2ff503e 100644
--- a/planetstack/core/models/node.py
+++ b/planetstack/core/models/node.py
@@ -1,7 +1,7 @@
 import os
 from django.db import models
 from core.models import PlCoreBase
-from core.models import SiteDeployments, Controller
+from core.models import SiteDeployments
 from core.models import Tag
 from django.contrib.contenttypes import generic
 
diff --git a/planetstack/core/models/site.py b/planetstack/core/models/site.py
index ae07fc0..f0f372d 100644
--- a/planetstack/core/models/site.py
+++ b/planetstack/core/models/site.py
@@ -255,33 +255,38 @@
             qs = ControllerPrivilege.objects.filter(id__in=cpriv_ids)
         return qs 
 
-class SiteDeployments(PlCoreBase):
-    #objects = ControllerLinkManager()
-    #deleted_objects = ControllerLinkDeletionManager()
+class Controller(PlCoreBase):
+
     objects = ControllerManager()
     deleted_objects = ControllerDeletionManager()
 
-    site = models.ForeignKey(Site,related_name='sitedeployments')
-    deployment = models.ForeignKey(Deployment,related_name='sitedeployments')
-    availability_zone = models.CharField(max_length=200, null=True, blank=True, help_text="OpenStack availability zone")
-    #tenant_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")    
-    def __unicode__(self):  return u'%s %s' % (self.deployment, self.site)
-
-class Controller(PlCoreBase):
-    site_deployment = models.ForeignKey(SiteDeployments,related_name='controller')
-
+    name = models.CharField(max_length=200, unique=True, help_text="Name of the Controller")
+    version = models.CharField(max_length=200, unique=True, help_text="Controller version")
     backend_type = models.CharField(max_length=200, null=True, blank=True, help_text="Type of compute controller, e.g. EC2, OpenStack, or OpenStack version")
     auth_url = models.CharField(max_length=200, null=True, blank=True, help_text="Auth url for the compute controller")
     admin_user = models.CharField(max_length=200, null=True, blank=True, help_text="Username of an admin user at this controller")
     admin_password = models.CharField(max_length=200, null=True, blank=True, help_text="Password of theadmin user at this controller")
     admin_tenant = models.CharField(max_length=200, null=True, blank=True, help_text="Name of the tenant the admin user belongs to")
 
-    def __unicode__(self):  return u'%s %s' % (self.site_deployment, self.backend_type)
+    def __unicode__(self):  return u'%s %s' % (self.name, self.backend_type)
 
-class ControllerSites(PlCoreBase):
+class SiteDeployments(PlCoreBase):
     objects = ControllerLinkManager()
-    deleted_objects = ControllerLinkDeletionManager() 
+    deleted_objects = ControllerLinkDeletionManager()
 
-    controller = models.ForeignKey(Controller, related_name='controllersites')
-    site_deployment = models.ForeignKey(SiteDeployments, related_name='controllersites')
+    site = models.ForeignKey(Site,related_name='sitedeployments')
+    deployment = models.ForeignKey(Deployment,related_name='sitedeployments')
+    controller = models.ForeignKey(Controller, relaed_name='sitedeployments')
+    availability_zone = models.CharField(max_length=200, null=True, blank=True, help_text="OpenStack availability zone")
+
+    def __unicode__(self):  return u'%s %s' % (self.deployment, self.site)
+
+class ControllerSiteDeployments(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+    
+    controller = models.ForeignKey(Controller, related_name='controllersitedeployments')
+    site_deployment = models.ForeignKey(SiteDeployments, related _name='controllersitedeployments') 
     tenant_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")
+
+    def __unicode__(self):  return u'%s %s' % (self.controller, self.site_deployment)
diff --git a/planetstack/genapi.py b/planetstack/genapi.py
index 13c41d4..880587c 100644
--- a/planetstack/genapi.py
+++ b/planetstack/genapi.py
@@ -164,8 +164,6 @@
     
         url(r'plstackapi/sitedeployments/$', SiteDeploymentsList.as_view(), name='sitedeployments-list'),
         url(r'plstackapi/sitedeployments/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteDeploymentsDetail.as_view(), name ='sitedeployments-detail'),
-        url(r'plstackapi/controllersites/$', ControllerSitesList.as_view(), name='sitedeployments-list'),
-        url(r'plstackapi/controllersites/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerSitesDetail.as_view(), name ='sitedeployments-detail'),
     
         url(r'plstackapi/slicetags/$', SliceTagList.as_view(), name='slicetag-list'),
         url(r'plstackapi/slicetags/(?P<pk>[a-zA-Z0-9\-]+)/$', SliceTagDetail.as_view(), name ='slicetag-detail'),
@@ -1474,24 +1472,6 @@
         model = Deployment
         fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','backend_status','deleted','name','accessControl','sites','sites','flavors','flavors',)
 
-
-class ControllerSerializer(serializers.HyperlinkedModelSerializer):
-    id = serializers.Field()
-    site_deployments = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='sitedeployment-detail')
-    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
-    validators = serializers.SerializerMethodField("getValidators")
-    def getHumanReadableName(self, obj):
-        return str(obj)
-    def getValidators(self, obj):
-        try:
-            return obj.getValidators()
-        except:
-            return None
-    class Meta:
-        model = Controller
-        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','backend_status','deleted','admin_user','admin_password','admin_tenant','auth_url','backend_type','availability_zone','accessControl',)
-
-
 class DeploymentIdSerializer(serializers.ModelSerializer):
     id = serializers.Field()
     
@@ -1544,7 +1524,7 @@
 
 class ControllerIdSerializer(serializers.ModelSerializer):
     id = serializers.Field()
-    sites = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='site-detail')
+    site_deployments = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='sitedeployment-detail')
     humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
     validators = serializers.SerializerMethodField("getValidators")
     def getHumanReadableName(self, obj):
@@ -1977,39 +1957,6 @@
         fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','backend_status','deleted','site','deployment')
 
 
-class ControllerSitesSerializer(serializers.HyperlinkedModelSerializer):
-    id = serializers.Field()
-
-    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
-    validators = serializers.SerializerMethodField("getValidators")
-    def getHumanReadableName(self, obj):
-        return str(obj)
-    def getValidators(self, obj):
-        try:
-            return obj.getValidators()
-        except:
-            return None
-    class Meta:
-        model = ControllerSites
-        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','backend_status','deleted','site_deployment','controller','tenant_id',)
-
-class ControllerSitesIdSerializer(serializers.ModelSerializer):
-    id = serializers.Field()
-
-    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
-    validators = serializers.SerializerMethodField("getValidators")
-    def getHumanReadableName(self, obj):
-        return str(obj)
-    def getValidators(self, obj):
-        try:
-            return obj.getValidators()
-        except:
-            return None
-    class Meta:
-        model = ControllerSites
-        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','backend_status','deleted','site_deployment','controller','tenant_id',)
-
-
 class SliceTagSerializer(serializers.HyperlinkedModelSerializer):
     id = serializers.Field()
     
@@ -5008,58 +4955,6 @@
 
     # destroy() is handled by PlanetStackRetrieveUpdateDestroyAPIView
 
-class ControllerSitesList(generics.ListCreateAPIView):
-    queryset = ControllerSites.objects.select_related().all()
-    serializer_class = ControllerSitesSerializer
-    id_serializer_class = ControllerSiteIdSerializer
-    filter_backends = (filters.DjangoFilterBackend,)
-    filter_fields = ('id','created','updated','enacted','backend_status','deleted','site_deployment','controller','tenant_id',)
-
-    def get_serializer_class(self):
-        no_hyperlinks = self.request.QUERY_PARAMS.get('no_hyperlinks', False)
-        if (no_hyperlinks):
-            return self.id_serializer_class
-        else:
-            return self.serializer_class
-
-    def get_queryset(self):
-        return ControllerSites.select_by_user(self.request.user)
-
-    def create(self, request, *args, **kwargs):
-        serializer = self.get_serializer(data=request.DATA, files=request.FILES)
-        if not (serializer.is_valid()):
-            response = {"error": "validation",
-                        "specific_error": "not serializer.is_valid()",
-                        "reasons": serializer.errors}
-            return Response(response, status=status.HTTP_400_BAD_REQUEST)
-        obj = serializer.object
-        obj.caller = request.user
-        if obj.can_update(request.user):
-            return super(ControllerSitesList, self).create(request, *args, **kwargs)
-        else:
-            raise Exception("failed obj.can_update")
-
-        ret = super(ControllerSitesList, self).create(request, *args, **kwargs)
-        if (ret.status_code%100 != 200):
-            raise Exception(ret.data)
-
-        return ret
-
-class ControllerSitesDetail(PlanetStackRetrieveUpdateDestroyAPIView):
-    queryset = ControllerSites.objects.select_related().all()
-    serializer_class = ControllerSitesSerializer
-    id_serializer_class = ControllerSitesIdSerializer
-
-    def get_serializer_class(self):
-        no_hyperlinks = self.request.QUERY_PARAMS.get('no_hyperlinks', False)
-        if (no_hyperlinks):
-            return self.id_serializer_class
-        else:
-            return self.serializer_class
-
-    def get_queryset(self):
-        return ControllerSites.select_by_user(self.request.user)
-
 class SliceTagList(generics.ListCreateAPIView):
     queryset = SliceTag.objects.select_related().all()
     serializer_class = SliceTagSerializer
diff --git a/planetstack/model_policies/model_policy_Slice.py b/planetstack/model_policies/model_policy_Slice.py
index af07e51..46ca9b8 100644
--- a/planetstack/model_policies/model_policy_Slice.py
+++ b/planetstack/model_policies/model_policy_Slice.py
@@ -1,22 +1,20 @@
 
 def handle(slice):
-	from core.models import ControllerSites,ControllerSlices,Controller,Network,NetworkSlice,NetworkTemplate
+	from core.models import Controller, ControllerSiteDeployments, ControllerSlices,Controller,Network,NetworkSlice,NetworkTemplate
 	from collections import defaultdict
-	site_controllers = ControllerSites.objects.all()
+	ctrl_site_deployments = ControllerSiteDeployments.objects.all()
 	site_deploy_lookup = defaultdict(list)
-	for site_controller in site_controllers:
-		site_deploy_lookup[site_controller.site].append(site_controller.controller)
+	for ctrl_site_deployment in ctrl_site_deployments:
+		site_deploy_lookup[ctrl_site_deployment.site_deployment].append(ctrl_site_deployment)
 	
 	slice_controllers = ControllerSlices.objects.all()
 	slice_deploy_lookup = defaultdict(list)
 	for slice_controller in slice_controllers:
-		slice_deploy_lookup[slice_controller.slice].append(slice_controller.controller)
+		slice_deploy_lookup[slice_controller.slice].append(slice_controller)
 	
-	all_controllers = Controller.objects.all() 
-	# slices are added to all controllers for now
-	expected_controllers = all_controllers
 	#expected_controllers = site_deploy_lookup[slice.site]
-	for expected_controller in expected_controllers:
+        all_controllers = Controller.objects.all() 
+	for expected_controller in controllers:
 		if slice not in slice_deploy_lookup or \
 		   expected_controller not in slice_deploy_lookup[slice]:
 			sd = ControllerSlices(slice=slice, controller=expected_controller)
diff --git a/planetstack/model_policies/model_policy_User.py b/planetstack/model_policies/model_policy_User.py
index 593ba9d..703b28c 100644
--- a/planetstack/model_policies/model_policy_User.py
+++ b/planetstack/model_policies/model_policy_User.py
@@ -1,19 +1,17 @@
 from core.models import *
 
 def handle(user):
-	from core.models import Controller,ControllerSites,ControllerUsers
+	from core.models import Controller, ControllerSiteDeployments, ControllerUsers
 	from collections import defaultdict
-	controllers = Controller.objects.all()
-	controller_sitements = ControllerSites.objects.all()
-	controller_site_lookup = defaultdict(list)
-	for controller_sitement in controller_sitements:
-		controller_site_lookup[controller_sitement.site].append(controller_sitement.controller)
+	ctrl_site_deployments = ControllerSiteDeployments.objects.all()
+	controller_lookup = defaultdict(list)
+	for ctrl_site_deployment in ctrl_site_deployments:
+		controller_site_lookup[ctrl_site_deployment.site_deployment].append(ctrl_site_deployment)
 
 	controller_user_lookup = defaultdict(list)
-	for controller_userment in ControllerUsers.objects.all():
-		controller_user_lookup[controller_userment.user].append(controller_userment.controller)
+	for controller_user in ControllerUsers.objects.all():
+		controller_user_lookup[controller_user.user].append(controller_user.controller)
    
-	all_controllers = Controller.objects.filter() 
 	if user.is_admin:
 		# admins should have an account at all controllers
 		expected_controllers = controllers
diff --git a/planetstack/openstack_observer/steps/sync_controller_site_deployments.py b/planetstack/openstack_observer/steps/sync_controller_site_deployments.py
index 89bea2c..32ca19b 100644
--- a/planetstack/openstack_observer/steps/sync_controller_site_deployments.py
+++ b/planetstack/openstack_observer/steps/sync_controller_site_deployments.py
@@ -6,7 +6,7 @@
 from core.models.site import *
 from observer.ansible import *
 
-class SyncControllerSites(OpenStackSyncStep):
+class SyncControllerSiteDeployments(OpenStackSyncStep):
     requested_interval=0
     provides=[ControllerSiteDeployments, SiteDeployments]
 
diff --git a/planetstack/openstack_observer/steps/sync_controller_sites.py b/planetstack/openstack_observer/steps/sync_controller_sites.py
deleted file mode 100644
index 7e76cc4..0000000
--- a/planetstack/openstack_observer/steps/sync_controller_sites.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import os
-import base64
-from django.db.models import F, Q
-from planetstack.config import Config
-from observer.openstacksyncstep import OpenStackSyncStep
-from core.models.site import *
-from observer.ansible import *
-
-class SyncControllerSites(OpenStackSyncStep):
-    requested_interval=0
-    provides=[Controller, Site]
-
-    def sync_record(self, controller):
-
-	template = os_template_env.get_template('sync_controller_sites.yaml')
-	tenant_fields = {'endpoint':controller.auth_url,
-		         'admin_user': controller.admin_user,
-		         'admin_password': controller.admin_password,
-		         'admin_tenant': 'admin',
-		         'tenant': controller.site_deployment.site.login_base,
-		         'tenant_description': controller.site_deployment.site.name}
-
-	rendered = template.render(tenant_fields)
-	res = run_template('sync_controller_sites.yaml', tenant_fields)
-
-	if (len(res)==1):
-		controller.tenant_id = res[0]['id']
-        	controller.save()
-	elif (len(res)):
-		raise Exception('Could not assign roles for user %s'%tenant_fields['tenant'])
-	else:
-		raise Exception('Could not create or update user %s'%tenant_fields['tenant'])
-            
-    def delete_record(self, controller):
-        if controller.tenant_id:
-            driver = self.driver.admin_driver(controller=controller)
-            driver.delete_tenant(controller.tenant_id)
diff --git a/planetstack/openstack_observer/steps/sync_controller_sites.yaml b/planetstack/openstack_observer/steps/sync_controller_sites.yaml
deleted file mode 100644
index 4129802..0000000
--- a/planetstack/openstack_observer/steps/sync_controller_sites.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-- hosts: 127.0.0.1
-  connection: local
-  tasks:
-  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} tenant={{ tenant }} tenant_description="{{ tenant_description }}"
diff --git a/planetstack/openstack_observer/steps/sync_controller_slices.py b/planetstack/openstack_observer/steps/sync_controller_slices.py
index e51ba7e..07aca4c 100644
--- a/planetstack/openstack_observer/steps/sync_controller_slices.py
+++ b/planetstack/openstack_observer/steps/sync_controller_slices.py
@@ -5,7 +5,6 @@
 from django.db.models import F, Q
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
-from core.models.site import Controller, ControllerSites
 from core.models.slice import Slice, ControllerSlices
 from core.models.usercontrollers import ControllerUsers
 from util.logger import Logger, logging
diff --git a/planetstack/openstack_observer/steps/sync_controller_users.py b/planetstack/openstack_observer/steps/sync_controller_users.py
index 63f5ca3..8723694 100644
--- a/planetstack/openstack_observer/steps/sync_controller_users.py
+++ b/planetstack/openstack_observer/steps/sync_controller_users.py
@@ -5,7 +5,7 @@
 from django.db.models import F, Q
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
-from core.models.site import ControllerSites, Controller
+from core.models.site import Controller, SiteDeployments
 from core.models.user import User
 from core.models.usercontrollers import ControllerUsers
 from util.logger import Logger, logging
@@ -36,26 +36,27 @@
 	
         name = controller_user.user.email[:controller_user.user.email.find('@')]
 
-	roles = []
-	# setup user controller home site roles  
-        if controller_user.user.site:
-            site_controllers = ControllerSites.objects.filter(site=controller_user.user.site,
-                                                              controller=controller_user.controller)
-            if site_controllers:
-                # need the correct tenant id for site at the controller
-                tenant_id = site_controllers[0].tenant_id  
-		tenant_name = site_controllers[0].site.login_base
-
-		roles.append('user')
-                if controller_user.user.is_admin:
-                    roles.append('admin')
-	    else:
-		raise Exception('Internal error. Missing ControllerSites for user %s'%controller_user.user.email)
-	else:
+	roles = ['user']
+        if controller_user.user.is_admin:
+            roles.append('admin')
+        else:
+            raise Exception('Internal error. Missing controller for user %s'%controller_user.user.email)
+   
+	# setup user home site roles at controller 
+        if not controller_user.user.site:
 	    raise Exception('Siteless user %s'%controller_user.user.email)
+        else:
+            # look up tenant id for the user's site at the controller
+            ctrl_site_deployments = ControllerSiteDeployments.objects.filter(
+              site_deployment__site=controller_user.user.site,
+              controller=controller_user.controller)
 
+            if ctrl_site_deployments:
+                # need the correct tenant id for site at the controller
+                tenant_id = ctrl_site_deployments[0].tenant_id  
+		tenant_name = ctrl_site_deployment[0].site_deployment.site.login_base
 
-        user_fields = {'endpoint':controller_user.controller.auth_url,
+                user_fields = {'endpoint':controller_user.controller.auth_url,
 		       'name': controller_user.user.email,
                        'email': controller_user.user.email,
                        'password': hashlib.md5(controller_user.user.password).hexdigest()[:6],
@@ -65,20 +66,21 @@
 		       'roles':roles,
 		       'tenant':tenant_name}    
 	
-	rendered = template.render(user_fields)
-	res = run_template('sync_controller_users.yaml', user_fields)
+	        rendered = template.render(user_fields)
+	        res = run_template('sync_controller_users.yaml', user_fields)
 
-	# results is an array in which each element corresponds to an 
-	# "ok" string received per operation. If we get as many oks as
-	# the number of operations we issued, that means a grand success.
-	# Otherwise, the number of oks tell us which operation failed.
-	expected_length = len(roles) + 1
-	if (len(res)==expected_length):
-        	controller_user.save()
-	elif (len(res)):
-		raise Exception('Could not assign roles for user %s'%user_fields['name'])
-	else:
-		raise Exception('Could not create or update user %s'%user_fields['name'])
+	        # results is an array in which each element corresponds to an 
+	        # "ok" string received per operation. If we get as many oks as
+	        # the number of operations we issued, that means a grand success.
+	        # Otherwise, the number of oks tell us which operation failed.
+	        expected_length = len(roles) + 1
+	        if (len(res)==expected_length):
+                    controller_user.kuser_id = res[0]['id']
+        	    controller_user.save()
+	        elif (len(res)):
+		    raise Exception('Could not assign roles for user %s'%user_fields['name'])
+	        else:
+		    raise Exception('Could not create or update user %s'%user_fields['name'])
 
     def delete_record(self, controller_user):
         if controller_user.kuser_id:
diff --git a/planetstack/openstack_observer/steps/sync_image_deployments.py b/planetstack/openstack_observer/steps/sync_image_deployments.py
deleted file mode 100644
index 20c22a2..0000000
--- a/planetstack/openstack_observer/steps/sync_image_deployments.py
+++ /dev/null
@@ -1,77 +0,0 @@
-import os
-import base64
-from collections import defaultdict
-from django.db.models import F, Q
-from planetstack.config import Config
-from observer.openstacksyncstep import OpenStackSyncStep
-from core.models import Deployment
-from core.models import Image, ImageDeployments
-from util.logger import Logger, logging
-

-logger = Logger(level=logging.INFO)
-
-class SyncImageDeployments(OpenStackSyncStep):
-    provides=[ImageDeployments]
-    requested_interval=0
-
-    def fetch_pending(self, deleted):
-        if (deleted):
-            return []
-         # smbaker: commented out automatic creation of ImageDeployments as
-         #    as they will now be configured in GUI. Not sure if this is
-         #    sufficient.
-
-#        # ensure images are available across all deployments
-#        image_deployments = ImageDeployments.objects.all()
-#        image_deploy_lookup = defaultdict(list)
-#        for image_deployment in image_deployments:
-#            image_deploy_lookup[image_deployment.image].append(image_deployment.deployment)
-#
-#        all_deployments = Deployment.objects.all()
-#        for image in Image.objects.all():
-#            expected_deployments = all_deployments
-#            for expected_deployment in expected_deployments:
-#                if image not in image_deploy_lookup or \
-#                  expected_deployment not in image_deploy_lookup[image]:
-#                    id = ImageDeployments(image=image, deployment=expected_deployment)
-#                    id.save()
-
-        # now we return all images that need to be enacted
-        return ImageDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
-
-    def sync_record(self, image_deployment):
-        logger.info("Working on image %s on deployment %s" % (image_deployment.image.name, image_deployment.deployment.name))
-        driver = self.driver.admin_driver(deployment=image_deployment.deployment.name)
-        images = driver.shell.glance.get_images()
-        glance_image = None
-        for image in images:
-            if image['name'] == image_deployment.image.name:
-                glance_image = image
-                break
-        if glance_image:
-            logger.info("Found image %s on deployment %s" % (image_deployment.image.name, image_deployment.deployment.name))
-            image_deployment.glance_image_id = glance_image['id']
-        elif image_deployment.image.path:
-            image = {
-                'name': image_deployment.image.name,
-                'is_public': True,
-                'disk_format': 'raw',
-                'container_format': 'bare',
-                'file': image_deployment.image.path,
-            }
-
-            logger.info("Creating image %s on deployment %s" % (image_deployment.image.name, image_deployment.deployment.name))
-
-            glance_image = driver.shell.glanceclient.images.create(name=image_deployment.image.name,
-                                                                   is_public=True,
-                                                                   disk_format='raw',
-                                                                   container_format='bare')
-            glance_image.update(data=open(image_deployment.image.path, 'rb'))
-
-            # While the images returned by driver.shell.glance.get_images()
-            #   are dicts, the images returned by driver.shell.glanceclient.images.create
-            #   are not dicts. We have to use getattr() instead of [] operator.
-            if not glance_image or not getattr(glance_image,"id",None):
-                raise Exception, "Add image failed at deployment %s" % image_deployment.deployment.name
-            image_deployment.glance_image_id = getattr(glance_image, "id")
-        image_deployment.save()
diff --git a/planetstack/openstack_observer/steps/sync_network_deployments.py b/planetstack/openstack_observer/steps/sync_network_deployments.py
deleted file mode 100644
index a6fc389..0000000
--- a/planetstack/openstack_observer/steps/sync_network_deployments.py
+++ /dev/null
@@ -1,136 +0,0 @@
-import os
-import base64
-from collections import defaultdict
-from netaddr import IPAddress, IPNetwork
-from django.db.models import F, Q
-from planetstack.config import Config
-from observer.openstacksyncstep import OpenStackSyncStep
-from core.models.network import *
-from core.models.slice import *
-from core.models.sliver import Sliver
-from util.logger import Logger, logging
-
-logger = Logger(level=logging.INFO)
-
-class SyncNetworkDeployments(OpenStackSyncStep):
-    requested_interval = 0
-    provides=[Network, NetworkDeployments, Sliver]
-
-    def fetch_pending(self, deleted):
-        if (deleted):
-            return NetworkDeployments.deleted_objects.all()
-        else:
-            return NetworkDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
-
-    def get_next_subnet(self, deployment=None):
-        # limit ourself to 10.0.x.x for now
-        valid_subnet = lambda net: net.startswith('10.0')
-
-        driver = self.driver.admin_driver(deployment=deployment,tenant='admin')
-        subnets = driver.shell.quantum.list_subnets()['subnets']
-        ints = [int(IPNetwork(subnet['cidr']).ip) for subnet in subnets \
-                if valid_subnet(subnet['cidr'])]
-        ints.sort()
-        if ints:
-            last_ip = IPAddress(ints[-1])
-        else:
-            last_ip = IPAddress('10.0.0.0')
-        last_network = IPNetwork(str(last_ip) + "/24")
-        next_network = IPNetwork(str(IPAddress(last_network) + last_network.size) + "/24")
-        return next_network
-
-    def save_network_deployment(self, network_deployment):
-        if (not network_deployment.net_id) and network_deployment.network.template.sharedNetworkName:
-            # It's a shared network, try to find the shared network id
-
-            quantum_networks = self.driver.shell.quantum.list_networks(name=network_deployment.network.template.sharedNetworkName)["networks"]
-            if quantum_networks:
-                logger.info("set shared network id %s" % quantum_networks[0]["id"])
-                network_deployment.net_id = quantum_networks[0]["id"]
-            else:
-                logger.info("failed to find shared network id for deployment")
-                return
-
-        # At this point, it must be a private network, so create it if it does
-        # not exist.
-
-        if not network_deployment.net_id:
-            network_name = network_deployment.network.name
-
-            # create network
-            os_network = self.driver.create_network(network_name, shared=True)
-            network_deployment.net_id = os_network['id']
-
-            # create router
-            #router = self.driver.create_router(network_name)
-            #network_deployment.router_id = router['id']
-
-            # create subnet
-            next_subnet = self.get_next_subnet(deployment=network_deployment.deployment.name)
-            cidr = str(next_subnet.cidr)
-            ip_version = next_subnet.version
-            start = str(next_subnet[2])
-            end = str(next_subnet[-2])
-            subnet = self.driver.create_subnet(name=network_name,
-                                               network_id = network_deployment.net_id,
-                                               cidr_ip = cidr,
-                                               ip_version = ip_version,
-                                               start = start,
-                                               end = end)
-            network_deployment.subnet = cidr
-            network_deployment.subnet_id = subnet['id']
-            # add subnet as interface to slice's router
-            #self.driver.add_router_interface(router['id'], subnet['id'])
-            # add external route
-            #self.driver.add_external_route(subnet)
-            logger.info("created private subnet (%s) for network: %s" % (cidr, network_deployment.network))
-
-        # Now, figure out the subnet and subnet_id for the network. This works
-        # for both private and shared networks.
-
-        if (not network_deployment.subnet_id) or (not network_deployment.subnet):
-            (network_deployment.subnet_id, network_deployment.subnet) = self.driver.get_network_subnet(network_deployment.net_id)
-            logger.info("sync'ed subnet (%s) for network: %s" % (network_deployment.subnet, network_deployment.network))
-
-        if (not network_deployment.subnet):
-            # this will generate a non-null database constraint error
-            #   ... which in turn leads to transaction errors
-            # it's probably caused by networks that no longer exist at the
-            # quantum level.
-
-            logger.info("null subnet for network %s, skipping save" % network_deployment.network)
-            return
-
-        network_deployment.save()
-
-    def sync_record(self, network_deployment):
-        logger.info("sync'ing network deployment %s for network %s slice %s deployment %s" % (network_deployment, network_deployment.network, str(network_deployment.network.owner), network_deployment.deployment))
-
-        if not network_deployment.deployment.admin_user:
-            logger.info("deployment %r has no admin_user, skipping" % network_deployment.deployment)
-            return
-
-        self.driver = self.driver.admin_driver(deployment=network_deployment.deployment,tenant='admin')
-        if network_deployment.network.owner and network_deployment.network.owner.creator:
-            try:
-                # update manager context
-		# Bring back
-                self.save_network_deployment(network_deployment)
-                logger.info("saved network deployment: %s" % (network_deployment))
-            except Exception,e:
-                logger.log_exc("save network deployment failed: %s" % network_deployment)
-                raise e
-
-
-    def delete_record(self, network_deployment):
-        driver = OpenStackDriver().client_driver(caller=network_deployment.network.owner.creator,
-                                                 tenant=network_deployment.network.owner.name,
-                                                 deployment=network_deployment.deployment.name)
-        if (network_deployment.router_id) and (network_deployment.subnet_id):
-            driver.delete_router_interface(network_deployment.router_id, network_deployment.subnet_id)
-        if network_deployment.subnet_id:
-            driver.delete_subnet(network_deployment.subnet_id)
-        if network_deployment.router_id:
-            driver.delete_router(network_deployment.router_id)
-        if network_deployment.net_id:
-            driver.delete_network(network_deployment.net_id)
diff --git a/planetstack/openstack_observer/steps/sync_nodes.py b/planetstack/openstack_observer/steps/sync_nodes.py
index abd5b98..d5edb02 100644
--- a/planetstack/openstack_observer/steps/sync_nodes.py
+++ b/planetstack/openstack_observer/steps/sync_nodes.py
@@ -31,7 +31,7 @@
         new_nodes = []
         for controller in controllers:
             try:
-                driver = self.driver.admin_driver(controller=controller.name)
+                driver = self.driver.admin_driver(controller=controller)
                 compute_nodes = driver.shell.nova.hypervisors.list()
             except:
                 logger.log_exc("Failed to get nodes from controller %s" % str(controller))
@@ -43,7 +43,7 @@
                     # XX pick a random site to add the node to for now
                     site_index = random.randint(0, len(site_deployments))
                     node = Node(name=compute_node.hypervisor_hostname,
-                                site_deployment=site_deployments[site_index], controller=controller)
+                                site_deployment=site_deployments[site_index])
                     new_nodes.append(node)
 
         return new_nodes    
diff --git a/planetstack/openstack_observer/steps/sync_site_deployments.py b/planetstack/openstack_observer/steps/sync_site_deployments.py
deleted file mode 100644
index 8b2d3b8..0000000
--- a/planetstack/openstack_observer/steps/sync_site_deployments.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import os
-import base64
-from django.db.models import F, Q
-from planetstack.config import Config
-from observer.openstacksyncstep import OpenStackSyncStep
-from core.models.site import *
-from observer.ansible import *
-
-class SyncSiteDeployments(OpenStackSyncStep):
-    requested_interval=0
-    provides=[SiteDeployments, Site]
-
-    def sync_record(self, site_deployment):
-
-	template = os_template_env.get_template('sync_site_deployments.yaml')
-	tenant_fields = {'endpoint':site_deployment.deployment.auth_url,
-		         'admin_user': site_deployment.deployment.admin_user,
-		         'admin_password': site_deployment.deployment.admin_password,
-		         'admin_tenant': 'admin',
-		         'tenant': site_deployment.site.login_base,
-				 'ansible_tag': '%s@%s'%(site_deployment.site.login_base,site_deployment.deployment.name), # name of ansible playbook
-		         'tenant_description': site_deployment.site.name}
-
-	rendered = template.render(tenant_fields)
-	res = run_template('sync_site_deployments.yaml', tenant_fields, path='site_deployments')
-
-	if (len(res)==1):
-		site_deployment.tenant_id = res[0]['id']
-        	site_deployment.save()
-	elif (len(res)):
-		raise Exception('Could not assign roles for user %s'%tenant_fields['tenant'])
-	else:
-		raise Exception('Could not create or update user %s'%tenant_fields['tenant'])
-            
-    def delete_record(self, site_deployment):
-        if site_deployment.tenant_id:
-            driver = self.driver.admin_driver(deployment=site_deployment.deployment.name)
-            driver.delete_tenant(site_deployment.tenant_id)
diff --git a/planetstack/openstack_observer/steps/sync_site_deployments.yaml b/planetstack/openstack_observer/steps/sync_site_deployments.yaml
deleted file mode 100644
index 4129802..0000000
--- a/planetstack/openstack_observer/steps/sync_site_deployments.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-- hosts: 127.0.0.1
-  connection: local
-  tasks:
-  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} tenant={{ tenant }} tenant_description="{{ tenant_description }}"
diff --git a/planetstack/openstack_observer/steps/sync_site_privileges.py b/planetstack/openstack_observer/steps/sync_site_privileges.py
index 2378b88..9dcd07e 100644
--- a/planetstack/openstack_observer/steps/sync_site_privileges.py
+++ b/planetstack/openstack_observer/steps/sync_site_privileges.py
@@ -3,7 +3,7 @@
 from django.db.models import F, Q
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
-from core.models import User, ControllerUsers, SitePrivilege, ControllerSites   
+from core.models import User, ControllerUsers, SitePrivilege, ControllerSiteDeployments   
 
 class SyncSitePrivileges(OpenStackSyncStep):
     requested_interval=0
@@ -18,12 +18,13 @@
 
     def sync_record(self, site_priv):
         # sync site privileges at all site controllers
-        controller_sites = ControllerSites.objects.filter(site=site_priv.site)
-        for controller_site in controller_sites:
-            controller_users = ControllerUsers.objects.filter(controller=controller_site.controller)
+        ctrl_site_deployments = ControllerSiteDeployments.objects.filter(site_deployment__site=site_priv.site)
+        for ctrl_site_deployment in ctrl_site_deployments:
+            controller_users = ControllerUsers.objects.filter(controller=ctrl_site_deployment.controller,
+                                                              user=site_priv.user)
             if controller_users:
                 kuser_id  = controller_users[0].kuser_id
-                driver = self.driver.admin_driver(controller=controller_site.controller)
+                driver = self.driver.admin_driver(controller=ctrl_site_deployment.controller)
                 driver.add_user_role(kuser_id,
-                                     controller_site.tenant_id,
+                                     ctrl_site_deployment.controller.tenant_id,
                                      site_priv.role.role)
diff --git a/planetstack/openstack_observer/steps/sync_sites.py b/planetstack/openstack_observer/steps/sync_sites.py
index 530301a..e18e2f8 100644
--- a/planetstack/openstack_observer/steps/sync_sites.py
+++ b/planetstack/openstack_observer/steps/sync_sites.py
@@ -3,8 +3,8 @@
 from django.db.models import F, Q
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
-from core.models.site import Site
-from observer.steps.sync_controller_sites import *
+from core.models.site import Site, SiteDeployments, ControllerSiteDeployments 
+from observer.steps.sync_controller_site_deployments import *
 
 class SyncSites(OpenStackSyncStep):
     provides=[Site]
@@ -14,7 +14,16 @@
         site.save()
 
     def delete_record(self, site):
-        controller_sites = ControllerSites.objects.filter(site=site)
-        controller_site_deleter = SyncControllerSites().delete_record
-        for controller_site in controller_sites:
-            controller_site_deleter(controller_site)
+        # delete associated controllers site deployments
+        ctrl_site_deployments = ControllerSiteDeployments.objects.filter(site_deployment__site=site)
+        ctrl_site_deploy_deleter = SyncControllerSiteDeployments().delete_record
+        for ctrl_site_deployment in ctrl_site_deployments:
+            ctrl_site_deployment_deleter(ctrl_site_deployment)
+
+        # delete site deployments
+        site_deployments = SiteDeployments.objects.filter(site=site)
+        for site_deployment in site_deployments:
+            site_deployment.delete()    
+         
+
+	
diff --git a/planetstack/openstack_observer/steps/sync_slice_deployments.py b/planetstack/openstack_observer/steps/sync_slice_deployments.py
deleted file mode 100644
index e8d760d..0000000
--- a/planetstack/openstack_observer/steps/sync_slice_deployments.py
+++ /dev/null
@@ -1,107 +0,0 @@
-import os
-import base64
-from collections import defaultdict
-from netaddr import IPAddress, IPNetwork
-from django.db.models import F, Q
-from planetstack.config import Config
-from observer.openstacksyncstep import OpenStackSyncStep
-from core.models.site import Deployment, SiteDeployments
-from core.models.slice import Slice, SliceDeployments
-from core.models.userdeployments import UserDeployments
-from util.logger import Logger, logging
-from observer.ansible import *
-
-logger = Logger(level=logging.INFO)
-
-class SyncSliceDeployments(OpenStackSyncStep):
-    provides=[SliceDeployments]
-    requested_interval=0
-
-    def fetch_pending(self, deleted):
-        if (deleted):
-            return SliceDeployments.deleted_objects.all()
-        else:
-            return SliceDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
-
-    def get_next_subnet(self, deployment=None):
-        # limit ourself to 10.0.x.x for now
-        valid_subnet = lambda net: net.startswith('10.0')
-        driver = self.driver.admin_driver(deployment=deployment)
-        subnets = driver.shell.quantum.list_subnets()['subnets']
-        ints = [int(IPNetwork(subnet['cidr']).ip) for subnet in subnets \
-                if valid_subnet(subnet['cidr'])]
-        ints.sort()
-        if ints:
-            last_ip = IPAddress(ints[-1])
-        else:
-            last_ip = IPAddress('10.0.0.1')
-        last_ip = IPAddress(ints[-1])
-        last_network = IPNetwork(str(last_ip) + "/24")
-        next_network = IPNetwork(str(IPAddress(last_network) + last_network.size) + "/24")
-        return next_network
-
-
-    def sync_record(self, slice_deployment):
-        logger.info("sync'ing slice deployment %s" % slice_deployment)
-
-        if not slice_deployment.deployment.admin_user:
-            logger.info("deployment %r has no admin_user, skipping" % slice_deployment.deployment)
-            return
-
-	deployment_users = UserDeployments.objects.filter(user=slice_deployment.slice.creator,
-                                                             deployment=slice_deployment.deployment)            
-    	if not deployment_users:
-	    logger.info("slice createor %s has not accout at deployment %s" % (slice_deployment.slice.creator, slice_deployment.deployment.name))
-	    roles = ['admin']
-	    deployment_user = 'Unknown user'
-    	else:
-	    deployment_user = deployment_users[0].user.email
-	    roles = ['admin']
-	    
-	max_instances=int(slice_deployment.slice.max_slivers)
-	tenant_fields = {'endpoint':slice_deployment.deployment.auth_url,
-		         'admin_user': slice_deployment.deployment.admin_user,
-		         'admin_password': slice_deployment.deployment.admin_password,
-		         'admin_tenant': 'admin',
-		         'tenant': slice_deployment.slice.name,
-		         'tenant_description': slice_deployment.slice.description,
-			 'roles':roles,
-			 'name':deployment_user,
-			 'ansible_tag':'%s@%s'%(slice_deployment.slice.name,slice_deployment.deployment.name),
-			 'max_instances':max_instances}
-
-	res = run_template('sync_slice_deployments.yaml', tenant_fields, path='slice_deployments')
-	expected_num = len(roles)+1
-	if (len(res)!=expected_num):
-	    raise Exception('Could not sync tenants for slice %s'%slice_deployment.slice.name)
-	else:
-	    tenant_id = res[0]['id']
-	    if (not slice_deployment.tenant_id):
-	        handle = os.popen('nova quota-update --instances %d %s'%(max_instances,tenant_id))
-		output = handle.read()
-		result = handle.close()
-		if (result):
-		    logging.info('Could not update quota for %s'%slice_deployment.slice.name)
-		slice_deployment.tenant_id = tenant_id
-		slice_deployment.save()
-			
-
-
-    def delete_record(self, slice_deployment):
-        user = User.objects.get(id=slice_deployment.slice.creator.id)
-        driver = OpenStackDriver().admin_driver(deployment=slice_deployment.deployment.name)
-        client_driver = driver.client_driver(caller=user,
-                                             tenant=slice_deployment.slice.name,
-                                             deployment=slice_deployment.deployment.name)
-
-        if slice_deployment.router_id and slice_deployment.subnet_id:
-            client_driver.delete_router_interface(slice_deployment.router_id, slice_deployment.subnet_id)
-        if slice_deployment.subnet_id:
-            client_driver.delete_subnet(slice_deployment.subnet_id)
-        if slice_deployment.router_id:    
-            client_driver.delete_router(slice_deployment.router_id)
-        if slice_deployment.network_id:
-            client_driver.delete_network(slice_deployment.network_id)
-        if slice_deployment.tenant_id:
-            driver.delete_tenant(slice_deployment.tenant_id)
-        
diff --git a/planetstack/openstack_observer/steps/sync_slice_deployments.yaml b/planetstack/openstack_observer/steps/sync_slice_deployments.yaml
deleted file mode 100644
index de1caf4..0000000
--- a/planetstack/openstack_observer/steps/sync_slice_deployments.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-- hosts: 127.0.0.1
-  connection: local
-  tasks:
-  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} tenant={{ tenant }} tenant_description="{{ tenant_description }}"
-  {% for role in roles %}
-  - keystone_user: endpoint={{ endpoint}} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} user="{{ name }}" role={{ role }} tenant={{ tenant }}
-  {% endfor %}
diff --git a/planetstack/openstack_observer/steps/sync_user_deployments.py b/planetstack/openstack_observer/steps/sync_user_deployments.py
deleted file mode 100644
index 821e67e..0000000
--- a/planetstack/openstack_observer/steps/sync_user_deployments.py
+++ /dev/null
@@ -1,87 +0,0 @@
-import os
-import base64
-import hashlib
-from collections import defaultdict
-from django.db.models import F, Q
-from planetstack.config import Config
-from observer.openstacksyncstep import OpenStackSyncStep
-from core.models.site import SiteDeployments, Deployment
-from core.models.user import User
-from core.models.userdeployments import UserDeployments
-from util.logger import Logger, logging
-
-from observer.ansible import *
-
-logger = Logger(level=logging.INFO)
-
-class SyncUserDeployments(OpenStackSyncStep):
-    provides=[UserDeployments, User]
-    requested_interval=0
-
-    def fetch_pending(self, deleted):
-
-        if (deleted):
-            return UserDeployments.deleted_objects.all()
-        else:
-            return UserDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None)) 
-
-    def sync_record(self, user_deployment):
-        logger.info("sync'ing user %s at deployment %s" % (user_deployment.user, user_deployment.deployment.name))
-
-        if not user_deployment.deployment.admin_user:
-            logger.info("deployment %r has no admin_user, skipping" % user_deployment.deployment)
-            return
-
-	template = os_template_env.get_template('sync_user_deployments.yaml')
-	
-        name = user_deployment.user.email[:user_deployment.user.email.find('@')]
-
-	roles = []
-	# setup user deployment home site roles  
-        if user_deployment.user.site:
-            site_deployments = SiteDeployments.objects.filter(site=user_deployment.user.site,
-                                                              deployment=user_deployment.deployment)
-            if site_deployments:
-                # need the correct tenant id for site at the deployment
-                tenant_id = site_deployments[0].tenant_id  
-		tenant_name = site_deployments[0].site.login_base
-
-		roles.append('user')
-                if user_deployment.user.is_admin:
-                    roles.append('admin')
-	    else:
-		raise Exception('Internal error. Missing SiteDeployments for user %s'%user_deployment.user.email)
-	else:
-	    raise Exception('Siteless user %s'%user_deployment.user.email)
-
-
-        user_fields = {'endpoint':user_deployment.deployment.auth_url,
-		       'name': user_deployment.user.email,
-		       'ansible_tag': '%s@%s'%(user_deployment.user.email,user_deployment.deployment.name),
-                       'email': user_deployment.user.email,
-                       'password': hashlib.md5(user_deployment.user.password).hexdigest()[:6],
-                       'admin_user': user_deployment.deployment.admin_user,
-		       'admin_password': user_deployment.deployment.admin_password,
-		       'admin_tenant': 'admin',
-		       'roles':roles,
-		       'tenant':tenant_name}    
-	
-	rendered = template.render(user_fields)
-	res = run_template('sync_user_deployments.yaml', user_fields, 'user_deployments')
-
-	# results is an array in which each element corresponds to an 
-	# "ok" string received per operation. If we get as many oks as
-	# the number of operations we issued, that means a grand success.
-	# Otherwise, the number of oks tell us which operation failed.
-	expected_length = len(roles) + 1
-	if (len(res)==expected_length):
-        	user_deployment.save()
-	elif (len(res)):
-		raise Exception('Could not assign roles for user %s'%user_fields['name'])
-	else:
-		raise Exception('Could not create or update user %s'%user_fields['name'])
-
-    def delete_record(self, user_deployment):
-        if user_deployment.kuser_id:
-            driver = self.driver.admin_driver(deployment=user_deployment.deployment.name)
-            driver.delete_user(user_deployment.kuser_id)
diff --git a/planetstack/openstack_observer/steps/sync_user_deployments.yaml b/planetstack/openstack_observer/steps/sync_user_deployments.yaml
deleted file mode 100644
index 95cdba3..0000000
--- a/planetstack/openstack_observer/steps/sync_user_deployments.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
----
-- hosts: 127.0.0.1
-  connection: local
-  tasks:
-  - keystone_user: 
-       endpoint={{ endpoint }} 
-       user="{{ name }}" 
-       email={{ email }} 
-       password={{ password }} 
-       login_user={{ admin_user }} 
-       login_password={{ admin_password }} 
-       login_tenant_name={{ admin_tenant }} 
-       tenant={{ tenant }}
-  {% for role in roles %}
-  - keystone_user: endpoint={{ endpoint}} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} user="{{ name }}" role={{ role }} tenant={{ tenant }}
-  {% endfor %}