Merge pick up, tweaked role/site/plcore_base or os_manager path when OpenStack not present
diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py
index 6a8b71e..c9bba2c 100644
--- a/planetstack/core/admin.py
+++ b/planetstack/core/admin.py
@@ -30,8 +30,10 @@
 
 class SliverInline(admin.TabularInline):
     model = Sliver
-    fields = ['ip', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
+    fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
     extra = 0
+    #readonly_fields = ['ip', 'instance_name', 'image']
+    readonly_fields = ['ip', 'instance_name']
 
 class SiteInline(admin.TabularInline):
     model = Site
@@ -57,9 +59,13 @@
     model = Node
     extra = 0
 
-class PlainTextWidget(forms.Widget):
-    def render(self, _name, value, attrs):
-        return mark_safe(value) if value is not None else ''
+class PlainTextWidget(forms.HiddenInput):
+    input_type = 'hidden'
+
+    def render(self, name, value, attrs=None):
+        if value is None:
+            value = ''
+        return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
 
 class PlanetStackBaseAdmin(admin.ModelAdmin):
     save_on_top = False
@@ -68,15 +74,17 @@
     """Attach client connection to openstack on delete() and save()"""
 
     def save_model(self, request, obj, form, change):
-        auth = request.session.get('auth', {})
-        #auth['tenant'] = request.user.site.login_base
-        obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+        if request.user.site:
+            auth = request.session.get('auth', {})
+            auth['tenant'] = request.user.site.login_base
+            obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
         obj.save()
 
     def delete_model(self, request, obj):
-        auth = request.session.get('auth', {})
-        #auth['tenant'] = request.user.site.login_base
-        obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+        if request.user.site:
+            auth = request.session.get('auth', {})
+            auth['tenant'] = request.user.site.login_base
+            obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
         obj.delete() 
 
 class RoleAdmin(OSModelAdmin):
@@ -125,7 +133,8 @@
                 continue
             # give inline object access to driver and caller
             auth = request.session.get('auth', {})
-            auth['tenant'] = request.user.site.login_base
+            if request.user.site:
+                auth['tenant'] = request.user.site.login_base
             inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
             yield inline.get_formset(request, obj)
 
@@ -140,6 +149,17 @@
     inlines = [NodeInline, UserInline]
     search_fields = ['name']
 
+    def queryset(self, request):
+        # admins can see all keys. Users can only see sites they belong to.
+        qs = super(SiteAdmin, self).queryset(request)
+        if not request.user.is_admin:
+            valid_sites = [request.user.site.login_base]
+            roles = request.user.get_roles()
+            for tenant_list in roles.values():
+                valid_sites.extend(tenant_list)
+            qs = qs.filter(login_base__in=valid_sites)
+        return qs
+
     def get_formsets(self, request, obj=None):
         for inline in self.get_inline_instances(request, obj):
             # hide MyInline in the add view
@@ -157,6 +177,20 @@
     ]
     list_display = ('user', 'site', 'role')
 
+    def queryset(self, request):
+        # admins can see all privileges. Users can only see privileges at sites
+        # where they have the admin role.
+        qs = super(SitePrivilegeAdmin, self).queryset(request)
+        if not request.user.is_admin:
+            roles = request.user.get_roles()
+            tenants = []
+            for (role, tenant_list) in roles:
+                if role == 'admin':
+                    tenants.extend(tenant_list)
+            valid_sites = Sites.objects.filter(login_base__in=tenants)    
+            qs = qs.filter(site__in=valid_sites)
+        return qs
+
     def save_model(self, request, obj, form, change):
         # update openstack connection to use this site/tenant   
         auth = request.session.get('auth', {})
@@ -173,24 +207,34 @@
 
 class KeyAdmin(OSModelAdmin):
     fieldsets = [
-        ('Key', {'fields': ['name', 'key', 'type', 'blacklisted']})
+        ('Key', {'fields': ['key', 'type', 'blacklisted']})
     ]
-    list_display = ['name', 'key', 'type', 'blacklisted']
+    list_display = ['key', 'type', 'blacklisted']
 
-    def get_queryset(self, request):
-        # get keys user is allowed to see
-        qs = super(KeyAdmin, self).get_queryset(request)
-        if request.user.is_superuser:
-            return qs
-        # users can only see their own keys
-        return qs.filter(user=request.user)  
+    #def queryset(self, request):
+        # admins can see all keys. Users can only see their own key.
+        #if request.user.is_admin:
+        #    qs = super(KeyAdmin, self).queryset(request) 
+        #else:
+        #    qs = Key.objects.filter(user=request.user)
+        #return qs 
         
-
 class SliceAdmin(OSModelAdmin):
     fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
     list_display = ('name', 'site','serviceClass', 'slice_url')
     inlines = [SliverInline]
 
+    def queryset(self, request):
+        # admins can see all keys. Users can only see slices they belong to.
+        qs = super(SliceAdmin, self).queryset(request)
+        if not request.user.is_admin:
+            valid_slices = []
+            roles = request.user.get_roles()
+            for tenant_list in roles.values():
+                valid_slices.extend(tenant_list)
+            qs = qs.filter(name__in=valid_slices)
+        return qs
+
     def get_formsets(self, request, obj=None):
         for inline in self.get_inline_instances(request, obj):
             # hide MyInline in the add view
@@ -215,24 +259,19 @@
     ]
     list_display = ('user', 'slice', 'role')
 
-    def save_model(self, request, obj, form, change):
-        # update openstack connection to use this site/tenant
-        auth = request.session.get('auth', {})
-        auth['tenant'] = obj.slice.name
-        obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
-        obj.save()
-
-    def delete_model(self, request, obj):
-        # update openstack connection to use this site/tenant
-        auth = request.session.get('auth', {})
-        auth['tenant'] = obj.slice.name
-        obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
-        obj.delete()
-
-
-class SubnetAdmin(PlanetStackBaseAdmin):
-    fields = ['cidr', 'ip_version', 'start', 'end', 'slice']
-    list_display = ('slice','cidr', 'start', 'end', 'ip_version')
+    def queryset(self, request):
+        # admins can see all memberships. Users can only see memberships of
+        # slices where they have the admin role.
+        qs = super(SliceMembershipAdmin, self).queryset(request)
+        if not request.user.is_admin:
+            roles = request.user.get_roles()
+            tenants = []
+            for (role, tenant_list) in roles:
+                if role == 'admin':
+                    tenants.extend(tenant_list)
+            valid_slices = Slice.objects.filter(name__in=tenants)
+            qs = qs.filter(slice__in=valid_slices)
+        return qs
 
     def save_model(self, request, obj, form, change):
         # update openstack connection to use this site/tenant
@@ -248,6 +287,7 @@
         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
         obj.delete()
 
+
 class ImageAdmin(admin.ModelAdmin):
     fields = ['image_id', 'name', 'disk_format', 'container_format']
 
@@ -258,9 +298,9 @@
 
 class SliverForm(forms.ModelForm):
     class Meta:
+        model = Sliver
         ip = forms.CharField(widget=PlainTextWidget)
         instance_name = forms.CharField(widget=PlainTextWidget)
-        model = Sliver
         widgets = {
             'ip': PlainTextWidget(),
             'instance_name': PlainTextWidget(),
@@ -269,9 +309,40 @@
 class SliverAdmin(PlanetStackBaseAdmin):
     form = SliverForm
     fieldsets = [
-        ('Sliver', {'fields': ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
+        ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
     ]
-    list_display = ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
+    list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
+
+    def queryset(self, request):
+        # admins can see all slivers. Users can only see slivers of 
+        # the slices they belong to.
+        qs = super(SliverAdmin, self).queryset(request)
+        if not request.user.is_admin:
+            tenants = []
+            roles = request.user.get_roles()
+            for tenant_list in roles.values():
+                tenants.extend(tenant_list)
+            valid_slices = Slice.objects.filter(name__in=tenants)
+            qs = qs.filter(slice__in=valid_slices)
+        return qs
+
+    def get_formsets(self, request, obj=None):
+        # make some fields read only if we are updating an existing record
+        if obj == None:
+            #self.readonly_fields = ('ip', 'instance_name') 
+            self.readonly_fields = () 
+        else:
+            self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key') 
+
+        for inline in self.get_inline_instances(request, obj):
+            # hide MyInline in the add view
+            if obj is None:
+                continue
+            # give inline object access to driver and caller
+            auth = request.session.get('auth', {})
+            auth['tenant'] = obj.name       # meed to connect using slice's tenant
+            inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
+            yield inline.get_formset(request, obj)
 
     def save_model(self, request, obj, form, change):
         # update openstack connection to use this site/tenant
@@ -343,17 +414,17 @@
     # The fields to be used in displaying the User model.
     # These override the definitions on the base UserAdmin
     # that reference specific fields on auth.User.
-    list_display = ('email', 'site', 'firstname', 'lastname', 'last_login')
+    list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
     list_filter = ('site',)
     fieldsets = (
         (None, {'fields': ('email', 'password')}),
-        ('Personal info', {'fields': ('firstname','lastname','phone','site', 'key')}),
+        ('Personal info', {'fields': ('firstname','lastname','phone', 'is_admin', 'site', 'key')}),
         #('Important dates', {'fields': ('last_login',)}),
     )
     add_fieldsets = (
         (None, {
             'classes': ('wide',),
-            'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'password1', 'password2', 'key')}
+            'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'is_admin', 'key','password1', 'password2')}
         ),
     )
     search_fields = ('email',)
@@ -377,8 +448,8 @@
 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
 admin.site.register(Slice, SliceAdmin)
 #admin.site.register(SliceMembership, SliceMembershipAdmin)
-admin.site.register(Subnet, SubnetAdmin)
-#admin.site.register(Image, ImageAdmin)
+#admin.site.register(Subnet, SubnetAdmin)
+admin.site.register(Image, ImageAdmin)
 #admin.site.register(Node, NodeAdmin)
 admin.site.register(Sliver, SliverAdmin)
 admin.site.register(Key, KeyAdmin)
diff --git a/planetstack/core/api/deployment_networks.py b/planetstack/core/api/deployment_networks.py
index 51fa03e..fcd2145 100644
--- a/planetstack/core/api/deployment_networks.py
+++ b/planetstack/core/api/deployment_networks.py
@@ -1,8 +1,6 @@
 from types import StringTypes
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
 from core.models import DeploymentNetwork
+from django.contrib.auth import authenticate
 
 def _get_deployment_networks(filter):
     if isinstance(filter, StringTypes) and filter.isdigit():
@@ -18,20 +16,23 @@
     return deployment_networks 
 
 def add_deployment_network(auth, name):
-    auth_check(auth)    
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     deployment = DeploymentNetwork(name=name)
     deployment.save()
     return deployment
 
 def delete_deployment_network(auth, filter={}):
-    auth_check(auth)   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     deployments = _get_deployment_networks(filter)
     for deployment in deployments:
         deployment.delete()
     return 1
 
 def get_deployment_networks(auth, filter={}):
-    auth_check(auth)   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     deployments = _get_deployment_networks(filter)
     return deployments             
         
diff --git a/planetstack/core/api/images.py b/planetstack/core/api/images.py
index c080a55..933216f 100644
--- a/planetstack/core/api/images.py
+++ b/planetstack/core/api/images.py
@@ -1,7 +1,5 @@
 from types import StringTypes
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
+from django.contrib.auth import authenticate
 from core.models import Image
  
 def _get_images(filter):
@@ -26,7 +24,8 @@
     return 1
 
 def get_images(auth, filter={}):
-    auth_check(auth)   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     images = _get_images(filter)
     return images             
         
diff --git a/planetstack/core/api/keys.py b/planetstack/core/api/keys.py
index e653690..3528cd3 100644
--- a/planetstack/core/api/keys.py
+++ b/planetstack/core/api/keys.py
@@ -1,8 +1,7 @@
 from types import StringTypes
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
+from django.contrib.auth import authenticate
+from openstack.manager import OpenStackManager
 from core.models import Key
-from core.api.auth import auth_check
 from core.api.users import _get_users
 
 
@@ -20,14 +19,17 @@
     return keys 
 
 def add_key(auth, fields):
-    driver = OpenStackDriver(client = auth_check(auth))
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+    manager = OpenStackManager(auth=auth, caller = user)
+
+    # look up user object
     users = _get_users(fields.get('user')) 
     if users: fields['user'] = users[0]    
+    # save
     key = Key(**fields)
-    nova_fields = {'name': key.name,
-                   'key': key.key} 
-    nova_key = driver.create_keypair(**nova_fields)
-    key.nkey_id = nova_key.id
+    key.os_manager = manager
     key.save()
     return key
 
@@ -35,15 +37,20 @@
     return  
 
 def delete_key(auth, filter={}):
-    driver = OpenStackDriver(client = auth_check(auth))   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+    manager = OpenStackManager(auth=auth, caller = user)
+
     keys = _get_keys(filter)
     for key in keys:
-        driver.delete_keypair(id=key.nkey_id) 
+        key.os_manager = manager
         key.delete()
     return 1
 
 def get_keys(auth, filter={}):
-    client = auth_check(auth)
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     keys = _get_keys(filter)
     return keys             
         
diff --git a/planetstack/core/api/nodes.py b/planetstack/core/api/nodes.py
index 6514e54..4f7ceeb 100644
--- a/planetstack/core/api/nodes.py
+++ b/planetstack/core/api/nodes.py
@@ -1,7 +1,5 @@
 from types import StringTypes
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
+from django.contrib.auth import authenticate
 from core.models import Node
  
 def _get_nodes(filter):
@@ -29,7 +27,8 @@
     return 
 
 def get_nodes(auth, filter={}):
-    auth_check(auth)   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     nodes = _get_nodes(filter)
     return nodes             
         
diff --git a/planetstack/core/api/roles.py b/planetstack/core/api/roles.py
index a799c01..4ea05c9 100644
--- a/planetstack/core/api/roles.py
+++ b/planetstack/core/api/roles.py
@@ -1,7 +1,6 @@
 from types import StringTypes
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
+from django.contrib.auth import authenticate
+from openstack.manager import OpenStackManager
 from core.models import Role
  
 
@@ -19,21 +18,27 @@
     return roles
 
 def add_role(auth, name):
-    driver = OpenStackDriver(client = auth_check(auth))    
-    keystone_role = driver.create_role(name=name)
-    role = Role(role_type=name, role_id=keystone_role.id)
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+
+    role = Role(role_type=name)
+    role.os_manager = OpenStackManager(auth=auth, caller = user) 
     role.save()
     return role
 
 def delete_role(auth, filter={}):
-    driver = OpenStackDriver(client = auth_check(auth))   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     roles = _get_roles(filter) 
     for role in roles:
-        driver.delete_role({'id': role.role_id}) 
+        auth['tenant'] = user.site.login_base
+        role.os_manager = OpenStackManager(auth=auth, caller = user)
         role.delete()
     return 1
 
 def get_roles(auth, filter={}):
-    client = auth_check(auth)
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     return _get_roles(filter)             
         
diff --git a/planetstack/core/api/site_privileges.py b/planetstack/core/api/site_privileges.py
index 85a8a83..6d79701 100644
--- a/planetstack/core/api/site_privileges.py
+++ b/planetstack/core/api/site_privileges.py
@@ -1,8 +1,7 @@
 from types import StringTypes
 import re
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
+from django.contrib.auth import authenticate
+from openstack.manager import OpenStackManager
 from core.models import SitePrivilege
 from core.api.users import _get_users
 from core.api.sites import _get_sites
@@ -23,7 +22,9 @@
     return site_privileges
  
 def add_site_privilege(auth, fields):
-    driver = OpenStackDriver(client = auth_check(auth))
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+
     users = _get_user(fields.get('user')) 
     sites = _get_slice(fields.get('site')) 
     roles = _get_role(fields.get('role'))
@@ -32,13 +33,9 @@
     if slices: fields['site'] = sites[0] 
     if roles: fields['role'] = roles[0]
  
+    auth['tenant'] = sites[0].login_base
     site_privilege = SitePrivilege(**fields)
-
-    # update nova role
-    driver.add_user_role(site_privilege.user.kuser_id, 
-                         site_privilege.site.tenant_id, 
-                         site_privilege.role.name)
-    
+    site_privilege.os_manager = OpenStackManager(auth=auth, caller = user) 
     site_privilege.save()
     return site_privilege
 
@@ -46,17 +43,21 @@
     return  
 
 def delete_site_privilege(auth, filter={}):
-    driver = OpenStackDriver(client = auth_check(auth))   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+    manager = OpenStackManager(auth=auth, caller = user)
+
     site_privileges = _get_site_privileges(filter)
     for site_privilege in site_privileges:
-        driver.delete_user_role(kuser_id=site_privilege.user.id,
-                                tenant_id = site_privilege.site.tenant_id,
-                                role_name = site_privilege.role.name) 
+        auth['tenant'] = user.site.login_base
+        site_privilege.os_manager = OpenStackManager(auth=auth, caller = user)
         site_privilege.delete()
     return 1
 
 def get_site_privileges(auth, filter={}):
-    client = auth_check(auth)
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     users = _get_users(filter.get('user'))
     sites = _get_slices(filter.get('site'))
     roles = _get_roles(filter.get('role'))
diff --git a/planetstack/core/api/sites.py b/planetstack/core/api/sites.py
index cfca6cf..123f139 100644
--- a/planetstack/core/api/sites.py
+++ b/planetstack/core/api/sites.py
@@ -1,10 +1,8 @@
 from types import StringTypes
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
+from django.contrib.auth import authenticate
+from openstack.manager import OpenStackManager    
 from core.models import Site
 
-
 def _get_sites(filter):
     if isinstance(filter, StringTypes) and filter.isdigit():
         filter = int(filter)
@@ -19,42 +17,42 @@
     return sites 
 
 def add_site(auth, fields):
-    driver = OpenStackDriver(client = auth_check(auth))
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+
     site = Site(**fields)
-    nova_fields = {'tenant_name': site.login_base,
-                   'description': site.name,
-                   'enabled': site.enabled}    
-    tenant = driver.create_tenant(**nova_fields)
-    site.tenant_id=tenant.id
+    site.os_manager = OpenStackManager(auth=auth, caller = user)
     site.save()
     return site
 
 def update_site(auth, id, **fields):
-    driver = OpenStackDriver(client = auth_check(auth))
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+
     sites = _get_sites(id)
     if not sites:
         return
 
     site = Site[0]
-    nova_fields = {}
-    if 'description' in fields:
-        nova_fields['description'] = fields['name']
-    if 'enabled' in fields:
-        nova_fields['enabled'] = fields['enabled']
-    driver.update_tenant(site.tenant_id, **nova_fields)
+    site.os_manager = OpenStackManager(auth=auth, caller = user)
     site.update(**fields)
     return site 
 
 def delete_site(auth, filter={}):
-    driver = OpenStackDriver(client = auth_check(auth))   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
     sites = _get_sites(id)
     for site in sites:
-        driver.delete_tenant(id=site.tenant_id) 
+        site.os_manager = OpenStackManager(auth=auth, caller = user)
         site.delete()
     return 1
 
 def get_sites(auth, filter={}):
-    client = auth_check(auth)
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     sites = _get_sites(filter)
     return sites             
         
diff --git a/planetstack/core/api/slice_memberships.py b/planetstack/core/api/slice_memberships.py
index 77d79bf..3e25ae7 100644
--- a/planetstack/core/api/slice_memberships.py
+++ b/planetstack/core/api/slice_memberships.py
@@ -1,7 +1,6 @@
 from types import StringTypes
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
+from django.contrib.auth import authenticate
+from openstack.manager import OpenStackManager
 from core.models import SliceMembership
 from core.api.users import _get_users
 from core.api.slices import _get_slices
@@ -22,7 +21,9 @@
 
  
 def add_slice_membership(auth, fields):
-    driver = OpenStackDriver(client = auth_check(auth))
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+
     users = _get_users(fields.get('user')) 
     slices = _get_slices(fields.get('slice')) 
     roles = _get_roles(fields.get('role'))
@@ -32,12 +33,8 @@
     if roles: fields['role'] = roles[0]
  
     slice_membership = SliceMembership(**fields)
-
-    # update nova role
-    driver.add_user_role(slice_membership.user.user_id, 
-                         slice_membership.slice.tenant_id, 
-                         slice_membership.role.name)
-    
+    auth['tenant'] = sites[0].login_base
+    slice_membership.os_manager = OpenStackManager(auth=auth, caller = user) 
     slice_membership.save()
     return slice_membership
 
@@ -45,17 +42,19 @@
     return  
 
 def delete_slice_membership(auth, filter={}):
-    driver = OpenStackDriver(client = auth_check(auth))   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+
     slice_memberships = _get_slice_memberships(filter)
     for slice_membership in slice_memberships:
-        driver.delete_user_role(kuser_id=slice_membership.user.id,
-                                tenant_id = slice_membership.slice.tenant_id,
-                                role_name = slice_membership.role.name) 
+        slice_membership.os_manager = OpenStackManager(auth=auth, caller = user)
         slice_membership.delete()
     return 1
 
 def get_slice_memberships(auth, filter={}):
-    client = auth_check(auth)
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     users = _get_users(fields.get('user'))
     slices = _get_slices(fields.get('slice'))
     roles = _get_roles(fields.get('role'))
diff --git a/planetstack/core/api/slices.py b/planetstack/core/api/slices.py
index f03dd6f..c9e94a2 100644
--- a/planetstack/core/api/slices.py
+++ b/planetstack/core/api/slices.py
@@ -1,9 +1,7 @@
 import re
 from types import StringTypes
 from django.contrib.auth import authenticate
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
+from openstack.manager import OpenStackManager
 from core.models import Slice
 from core.api.sites import _get_sites
 
@@ -22,61 +20,44 @@
     
  
 def add_slice(auth, fields):
-    driver = OpenStackDriver(client = auth_check(auth))
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+
     login_base = fields['name'][:fields['name'].find('_')]
     sites = _get_sites(login_base) 
     if sites: fields['site'] = sites[0]     
     slice = Slice(**fields)
-   
-    # create tenant
-    nova_fields = {'tenant_name': slice.name,
-                   'description': slice.description,
-                   'enabled': slice.enabled}
-    tenant = driver.create_tenant(**nova_fields)
-    slice.tenant_id=tenant.id
-    
-    # create network
-    network = driver.create_network(slice.name)
-    slice.network_id = network['id']
-
-    # create router
-    router = driver.create_router(slice.name)
-    slice.router_id = router['id']    
-
+    slice.os_manager = OpenStackManager(auth=auth, caller = user) 
     slice.save()
     return slice
 
 def update_slice(auth, id, **fields):
-    driver = OpenStackDriver(client = auth_check(auth))
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+
     slices = _get_slices(id)
     if not slices:
         return
-
-    # update tenant
     slice = slices[0]
-    nova_fields = {}
-    if 'name' in fields:
-        nova_fields['tenant_name'] = fields['name']
-    if 'description' in fields:
-        nova_fields['description'] = fields['description']
-    if 'enabled' in fields:
-        nova_fields['enabled'] = fields['enabled']
-    driver.update_tenant(slice.tenant_id, **nova_fields)
-
-    # update db record 
     sites = _get_sites(fields.get('site'))
     if sites: fields['site'] = sites[0]
-    slice.update(**fields)
+
+    slice.os_manager = OpenStackManager(auth=auth, caller = user)
+    for (k,v) in fields.items():
+        setattr(slice, k, v)
+    slice.save()
 
     return slice 
 
 def delete_slice(auth, filter={}):
-    driver = OpenStackDriver(client = auth_check(auth))   
-    slices = _get_slices(id)
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+    slices = _get_slices(filter)
     for slice in slices:
-        driver.delete_network(slice.network_id)
-        driver.delete_router(slice.router_id)
-        driver.delete_slice(id=slice.tenant_id) 
+        slice.os_manager = OpenStackManager(auth=auth, caller = user) 
         slice.delete()
     return 1
 
diff --git a/planetstack/core/api/slivers.py b/planetstack/core/api/slivers.py
index e3244a4..16a7e0b 100644
--- a/planetstack/core/api/slivers.py
+++ b/planetstack/core/api/slivers.py
@@ -1,15 +1,12 @@
 from types import StringTypes
 from django.contrib.auth import authenticate
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
+from openstack.manager import OpenStackManager
 from core.models import Sliver, Slice
 from core.api.images import _get_images
 from core.api.keys import _get_keys
 from core.api.slices import _get_slices
 from core.api.deployment_networks import _get_deployment_networks
 from core.api.nodes import _get_nodes
- 
 
 def _get_slivers(filter):
     if isinstance(filter, StringTypes) and filter.isdigit():
@@ -25,21 +22,23 @@
     return slivers
  
 def add_sliver(auth, fields):
-    driver = OpenStackDriver(client = auth_check(auth))
-        
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    
     images = _get_images(fields.get('image'))
-    if images: fields['image'] = images[0]     
     keys = _get_keys(fields.get('key'))
-    if keys: fields['key'] = keys[0]     
     slices = _get_slices(fields.get('slice'))
-    if slices: 
-        fields['slice'] = slices[0]     
     deployment_networks = _get_deployment_networks(fields.get('deploymentNetwork'))
-    if deployment_networks: fields['deploymentNetwork'] = deployment_networks[0]     
     nodes = _get_nodes(fields.get('node'))
+    if images: fields['image'] = images[0]     
+    if keys: fields['key'] = keys[0]     
+    if slices: fields['slice'] = slices[0]     
+    if deployment_networks: fields['deploymentNetwork'] = deployment_networks[0]     
     if nodes: fields['node'] = nodes[0]     
+
     sliver = Sliver(**fields)
-    sliver.driver = driver    
+    auth['tenant'] = sliver.slice.name
+    sliver.os_manager = OpenStackManager(auth=auth, caller = user)    
     sliver.save()
     return sliver
 
@@ -47,10 +46,12 @@
     return  
 
 def delete_sliver(auth, filter={}):
-    driver = OpenStackDriver(client = auth_check(auth))   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     slivers = _get_slivers(filter)
     for sliver in slivers:
-        sliver.driver = driver
+        auth['tenant'] = sliver.slice.name 
+        slice.os_manager = OpenStackManager(auth=auth, caller = user)
         sliver.delete()
     return 1
 
diff --git a/planetstack/core/api/users.py b/planetstack/core/api/users.py
index 3b157ac..08e851c 100644
--- a/planetstack/core/api/users.py
+++ b/planetstack/core/api/users.py
@@ -1,7 +1,6 @@
 from types import StringTypes
-from openstack.client import OpenStackClient
-from openstack.driver import OpenStackDriver
-from core.api.auth import auth_check
+from django.contrib.auth import authenticate
+from openstack.manager import OpenStackManager    
 from core.models import User, Site
 from core.api.sites import _get_sites
 
@@ -19,22 +18,22 @@
     return users 
 
 def add_user(auth, fields):
-    driver = OpenStackDriver(client = auth_check(auth))
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+
     sites = _get_sites(fields.get('site')) 
     if sites: fields['site'] = sites[0]     
     user = User(**fields)
-    nova_fields = {'name': user.email[:user.email.find('@')],
-                   'email': user.email, 
-                   'password': fields.get('password'),
-                   'enabled': user.enabled}    
-    nova_user = driver.create_user(**nova_fields)
-    #driver.add_user_user(user.id, user.site.tenant_id, 'user')
-    user.kuser_id=nova_user.id
+    user.os_manager = OpenStackManager(auth=auth, caller = user)
     user.save()
     return user
 
 def update_user(auth, id, **fields):
-    driver = OpenStackDriver(client = auth_check(auth))
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
+
     users = User.objects.filter(id=id)
     if not users:
         return
@@ -48,22 +47,27 @@
         nova_fields['password'] = fields['password']
     if 'enabled' in fields:
         nova_fields['enabled'] = fields['enabled']
-    driver.update_user(user.kuser_id, **nova_fields)
     sites = _get_sites(fields.get('site'))
     if sites: fields['site'] = sites[0]
-    user.update(**fields)
+    user.os_manager = OpenStackManager(auth=auth, caller = user)
+    for (k,v) in fields.items():
+        setattr(user, k, v)    
+    user.save()
     return user 
 
 def delete_user(auth, filter={}):
-    driver = OpenStackDriver(client = auth_check(auth))   
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
+    auth['tenant'] = user.site.login_base
     users = _get_users(filter)
     for user in users:
-        driver.delete_user(id=user.kuser_id) 
+        user.os_manager = OpenStackManager(auth=auth, caller = user) 
         user.delete()
     return 1
 
 def get_users(auth, filter={}):
-    client = auth_check(auth)
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     users = _get_users(filter)
     return users             
         
diff --git a/planetstack/core/models/key.py b/planetstack/core/models/key.py
index 98cfb9b..7a8b322 100644
--- a/planetstack/core/models/key.py
+++ b/planetstack/core/models/key.py
@@ -1,23 +1,29 @@
 import os
 from django.db import models
 from core.models import PlCoreBase
+from openstack.manager import OpenStackManager
+
 
 # Create your models here.
 
 class Key(PlCoreBase):
-    name = models.CharField(max_length=256, unique=True)
-    nkey_id = models.CharField(max_length=256, unique=True)
+    name = models.CharField(max_length=256)
+    nkey_id = models.CharField(null=True, blank=True, max_length=256, unique=True)
     key = models.CharField(max_length=512)
     type = models.CharField(max_length=256)
     blacklisted = models.BooleanField(default=False)
 
-    def __unicode__(self):  return u'%s' % (self.name)
+    def __unicode__(self):  return u'%s' % (self.key)
 
     def save(self, *args, **kwds):
-        self.os_manager.save_key(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.save_key(self)
         super(Key, self).save(*args, **kwds)
 
     def delete(self, *args, **kwds):
-        self.os_manager.delete_key(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.delete_key(self)
         super(Key, self).delete(*args, **kwds) 
     
diff --git a/planetstack/core/models/plcorebase.py b/planetstack/core/models/plcorebase.py
index 52aa0f7..ed7c3ff 100644
--- a/planetstack/core/models/plcorebase.py
+++ b/planetstack/core/models/plcorebase.py
@@ -1,5 +1,6 @@
 import os
 from django.db import models
+from django.forms.models import model_to_dict
 
 class PlCoreBase(models.Model):
 
@@ -10,5 +11,36 @@
         abstract = True
         app_label = "core"
 
+    def __init__(self, *args, **kwargs):
+        super(PlCoreBase, self).__init__(*args, **kwargs)
+        self.__initial = self._dict
+
+    @property
+    def diff(self):
+        d1 = self.__initial
+        d2 = self._dict
+        diffs = [(k, (v, d2[k])) for k, v in d1.items() if 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 get_field_diff(self, field_name):
+        return self.diff.get(field_name, None)
+
+    def save(self, *args, **kwargs):
+        super(PlCoreBase, self).save(*args, **kwargs)
+        self.__initial = self._dict
+
+    @property
+    def _dict(self):
+        return model_to_dict(self, fields=[field.name for field in
+                             self._meta.fields])
+
 
 
diff --git a/planetstack/core/models/role.py b/planetstack/core/models/role.py
index b3611c1..e7d31b9 100644
--- a/planetstack/core/models/role.py
+++ b/planetstack/core/models/role.py
@@ -2,6 +2,7 @@
 import datetime
 from django.db import models
 from core.models import PlCoreBase
+from openstack.manager import OpenStackManager
 
 class Role(PlCoreBase):
 
@@ -13,10 +14,14 @@
 
 
     def save(self, *args, **kwds):
-        self.os_manager.save_role(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.save_role(self)
         super(Role, self).save(*args, **kwds)
     
     def delete(self, *args, **kwds):
-        self.os_manager.delete_role(self)   
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.delete_role(self)   
         super(Role, self).delete(*args, **kwds)
             
diff --git a/planetstack/core/models/site.py b/planetstack/core/models/site.py
index ebf2ab9..11e6a28 100644
--- a/planetstack/core/models/site.py
+++ b/planetstack/core/models/site.py
@@ -2,11 +2,11 @@
 from django.db import models
 from core.models import PlCoreBase
 from core.models import DeploymentNetwork
-
+from openstack.manager import OpenStackManager
 
 class Site(PlCoreBase):
 
-    tenant_id = models.CharField(max_length=200, help_text="Keystone tenant id")
+    tenant_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")
     name = models.CharField(max_length=200, help_text="Name for this Site")
     site_url = models.URLField(null=True, blank=True, max_length=512, help_text="Site's Home URL Page")
     enabled = models.BooleanField(default=True, help_text="Status for this Site")
@@ -21,12 +21,16 @@
     def __unicode__(self):  return u'%s' % (self.name)
 
     def save(self, *args, **kwds):
-        self.os_manager.save_site(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.save_site(self)
         super(Site, self).save(*args, **kwds)               
 
 
     def delete(self, *args, **kwds):
-        self.os_manager.delete_site(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.delete_site(self)
         super(Site, self).delete(*args, **kwds)         
         
 
@@ -39,11 +43,15 @@
     def __unicode__(self):  return u'%s %s %s' % (self.site, self.user, self.role)
 
     def save(self, *args, **kwds):
-        self.os_manager.driver.add_user_role(self.user.kuser_id, self.site.tenant_id, self.role.role_type)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.driver.add_user_role(self.user.kuser_id, self.site.tenant_id, self.role.role_type)
         super(SitePrivilege, self).save(*args, **kwds)
 
     def delete(self, *args, **kwds):
-        self.os_manager.driver.delete_user_role(self.user.kuser_id, self.site.tenant_id, self.role.role_type)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.driver.delete_user_role(self.user.kuser_id, self.site.tenant_id, self.role.role_type)
         super(SitePrivilege, self).delete(*args, **kwds)
 
 
diff --git a/planetstack/core/models/slice.py b/planetstack/core/models/slice.py
index 539be24..a4eb3a4 100644
--- a/planetstack/core/models/slice.py
+++ b/planetstack/core/models/slice.py
@@ -5,6 +5,7 @@
 from core.models import User
 from core.models import Role
 from core.models import DeploymentNetwork
+from openstack.manager import OpenStackManager
 
 # Create your models here.
 
@@ -12,14 +13,13 @@
     tenant_id = models.CharField(max_length=200, help_text="Keystone tenant id")
     name = models.CharField(unique=True, help_text="The Name of the Slice", max_length=80)
     enabled = models.BooleanField(default=True, help_text="Status for this Slice")
-    SLICE_CHOICES = (('plc', 'PLC'), ('delegated', 'Delegated'), ('controller','Controller'), ('none','None'))
-    instantiation = models.CharField(help_text="The instantiation type of the slice", max_length=80, choices=SLICE_CHOICES)
     omf_friendly = models.BooleanField()
     description=models.TextField(blank=True,help_text="High level description of the slice and expected activities", max_length=1024)
     slice_url = models.URLField(blank=True, max_length=512)
     site = models.ForeignKey(Site, related_name='slices', help_text="The Site this Node belongs too")
-    network_id = models.CharField(max_length=256, help_text="Quantum network")
-    router_id = models.CharField(max_length=256, help_text="Quantum router id")
+    network_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network")
+    router_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum router id")
+    subnet_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum subnet id")
 
     SVC_CLASS_CHOICES = (('besteffort', 'Best Effort'), ('silver', 'Silver'), ('gold','Gold'))
     serviceClass = models.CharField(verbose_name="Service Class",default="besteffort",help_text="The Service Class of this slice", max_length=30, choices=SVC_CLASS_CHOICES)
@@ -28,11 +28,15 @@
     def __unicode__(self):  return u'%s' % (self.name)
 
     def save(self, *args, **kwds):
-        self.os_manager.save_slice(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.save_slice(self)
         super(Slice, self).save(*args, **kwds)
 
     def delete(self, *args, **kwds):
-        self.os_manager.delete_slice(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.delete_slice(self)
         super(Slice, self).delete(*args, **kwds)    
 
 class SliceMembership(PlCoreBase):
@@ -43,9 +47,13 @@
     def __unicode__(self):  return u'%s %s %s' % (self.slice, self.user, self.role)
 
     def save(self, *args, **kwds):
-        self.os_manager.driver.add_user_role(self.user.kuser_id, self.slice.tenant_id, self.role.role_type)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.driver.add_user_role(self.user.kuser_id, self.slice.tenant_id, self.role.role_type)
         super(SliceMembership, self).save(*args, **kwds)
 
     def delete(self, *args, **kwds):
-        self.os_manager.driver.delete_user_role(self.user.kuser_id, self.slice.tenant_id, self.role.role_type)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.driver.delete_user_role(self.user.kuser_id, self.slice.tenant_id, self.role.role_type)
         super(SliceMembership, self).delete(*args, **kwds)
diff --git a/planetstack/core/models/sliver.py b/planetstack/core/models/sliver.py
index 580c2af..8ebcbd4 100644
--- a/planetstack/core/models/sliver.py
+++ b/planetstack/core/models/sliver.py
@@ -8,10 +8,11 @@
 from core.models import Node
 from core.models import Site
 from core.models import DeploymentNetwork
+from openstack.manager import OpenStackManager
 
 # Create your models here.
 class Sliver(PlCoreBase):
-    instance_id = models.CharField(max_length=200, help_text="Nova instance id")    
+    instance_id = models.CharField(null=True, blank=True, max_length=200, help_text="Nova instance id")    
     name = models.CharField(max_length=200, help_text="Sliver name")
     instance_name = models.CharField(blank=True, null=True, max_length=200, help_text="OpenStack generated name")
     ip = models.GenericIPAddressField(help_text="Sliver ip address", blank=True, null=True)
@@ -20,18 +21,21 @@
     slice = models.ForeignKey(Slice, related_name='slivers')
     node = models.ForeignKey(Node, related_name='slivers')
     deploymentNetwork = models.ForeignKey(DeploymentNetwork, verbose_name='deployment', related_name='sliver_deploymentNetwork')
-    numberCores = models.IntegerField(verbose_name="Number of Cores", help_text="Number of cores for sliver", default=2)
+    numberCores = models.IntegerField(verbose_name="Number of Cores", help_text="Number of cores for sliver", default=0)
 
 
     def __unicode__(self):  return u'%s' % (self.instance_name)
 
     def save(self, *args, **kwds):
-        if not self.slice.subnet.exists():
-            raise exceptions.ValidationError, "Slice %s has no subnet" % self.slice.name
-
-        self.os_manager.save_sliver(self)
+        if not self.name:
+            self.name = self.slice.name
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.save_sliver(self)
         super(Sliver, self).save(*args, **kwds)
 
     def delete(self, *args, **kwds):
-        self.os_manager.delete_sliver(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.delete_sliver(self)
         super(Sliver, self).delete(*args, **kwds)
diff --git a/planetstack/core/models/subnet.py b/planetstack/core/models/subnet.py
index cad9fea..37175ec 100644
--- a/planetstack/core/models/subnet.py
+++ b/planetstack/core/models/subnet.py
@@ -3,6 +3,7 @@
 from django.db import models
 from core.models import PlCoreBase
 from core.models import Slice
+from openstack.manager import OpenStackManager
 
 # Create your models here.
 
@@ -17,9 +18,13 @@
     def __unicode__(self):  return u'%s' % (self.slice.name)
 
     def save(self, *args, **kwds):
-        self.os_manager.save_subnet(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.save_subnet(self)
         super(Subnet, self).save(*args, **kwds)
 
     def delete(self, *args, **kwds):
-        self.os_manager.delete_subnet(self)
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
+            self.os_manager.delete_subnet(self)
         super(Subnet, self).delete(*args, **kwds)
diff --git a/planetstack/core/models/user.py b/planetstack/core/models/user.py
index 6c776b1..38c0d89 100644
--- a/planetstack/core/models/user.py
+++ b/planetstack/core/models/user.py
@@ -1,5 +1,6 @@
 import os
 import datetime
+from collections import defaultdict
 from django.db import models
 from core.models import PlCoreBase
 from core.models import Site
@@ -8,8 +9,6 @@
 from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
 
 # Create your models here.
-has_openstack = False
-
 class UserManager(BaseUserManager):
     def create_user(self, email, firstname, lastname, password=None):
         """
@@ -57,7 +56,7 @@
         db_index=True,
     )
 
-    kuser_id = models.CharField(help_text="keystone user id", max_length=200) 
+    kuser_id = models.CharField(null=True, blank=True, help_text="keystone user id", max_length=200) 
     firstname = models.CharField(help_text="person's given name", max_length=200)
     lastname = models.CharField(help_text="person's surname", max_length=200)
 
@@ -96,27 +95,31 @@
         # Simplest possible answer: Yes, always
         return True
 
-    @property
-    def is_staff(self):
-        "Is the user a member of staff?"
-        # Simplest possible answer: All admins are staff
-        return self.is_admin
+    def get_roles(self):
+        from plstackapi.core.models.site import SitePrivilege
+        from plstackapi.core.models.slice import SliceMembership
 
+        site_privileges = SitePrivilege.objects.filter(user=self)
+        slice_memberships = SliceMembership.objects.filter(user=self)
+        roles = defaultdict(list)
+        for site_privilege in site_privileges:
+            roles[site_privilege.role.role_type].append(site_privilege.site.login_base)
+        for slice_membership in slice_memberships:
+            roles[slice_membership.role.role_type].append(slice_membership.slice.name)
+        return roles   
 
     def save(self, *args, **kwds):
-        if has_openstack:
-            if not hasattr(self, 'os_manager'):
-                setattr(self, 'os_manager', OpenStackManager())
-
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
             self.os_manager.save_user(self)
+
         if not self.id:
             self.set_password(self.password)    
         super(User, self).save(*args, **kwds)   
 
     def delete(self, *args, **kwds):
-        if has_openstack:
-            if not hasattr(self, 'os_manager'):
-                setattr(self, 'os_manager', OpenStackManager())
-
+        if not hasattr(self, 'os_manager'):
+            setattr(self, 'os_manager', OpenStackManager())
             self.os_manager.delete_user(self)
+
         super(User, self).delete(*args, **kwds)    
diff --git a/planetstack/core/serializers.py b/planetstack/core/serializers.py
index 55cf7c8..7c5dca9 100644
--- a/planetstack/core/serializers.py
+++ b/planetstack/core/serializers.py
@@ -53,7 +53,6 @@
     id = serializers.Field()
     site = serializers.HyperlinkedRelatedField(view_name='site-detail')
     slivers = serializers.HyperlinkedRelatedField(view_name='sliver-detail')
-    subnet= serializers.HyperlinkedRelatedField(view_name='subnet-detail')
     class Meta:
         model = Slice
         fields = ('id',
@@ -61,12 +60,12 @@
                   'enabled',
                   'name',
                   'url',
-                  'instantiation',
                   'omf_friendly',
                   'description',
                   'slice_url',
                   'network_id',
                   'router_id',
+                  'subnet_id',
                   'site',
                   'slivers',
                   'updated',
@@ -84,19 +83,6 @@
                   'slice',
                   'role')
 
-class SubnetSerializer(serializers.HyperlinkedModelSerializer):
-    id = serializers.Field()
-    slice = serializers.HyperlinkedRelatedField(view_name='slice-detail')
-    class Meta:
-        model = Subnet
-        fields = ('id',
-                  'subnet_id',
-                  'cidr',
-                  'ip_version',
-                  'start',
-                  'end',
-                  'slice')  
-
 class SiteSerializer(serializers.HyperlinkedModelSerializer):
 
     #Experimenting with whether to use ids, hyperlinks, or nested includes
@@ -200,7 +186,6 @@
                  SitePrivilege: SitePrivilegeSerializer,
                  Slice: SliceSerializer,
                  SliceMembership: SliceMembershipSerializer,
-                 Subnet: SubnetSerializer,
                  Node: NodeSerializer,
                  Sliver: SliverSerializer,
                  DeploymentNetwork: DeploymentNetworkSerializer,
diff --git a/planetstack/importer/plclassic/slice_importer.py b/planetstack/importer/plclassic/slice_importer.py
index b25b483..b2dd84f 100644
--- a/planetstack/importer/plclassic/slice_importer.py
+++ b/planetstack/importer/plclassic/slice_importer.py
@@ -33,7 +33,6 @@
             if slice['name'] not in self.local_slices:
                 site = local_sites[remote_sites[slice['site_id']]['login_base']]
                 new_slice = Slice(name=slice['name'],
-                                   instantiation=slice['instantiation'],
                                    omf_friendly = False,
                                    description = slice['description'],
                                    slice_url = slice['url'],
diff --git a/planetstack/openstack/driver.py b/planetstack/openstack/driver.py
index 6b04b5d..eba424a 100644
--- a/planetstack/openstack/driver.py
+++ b/planetstack/openstack/driver.py
@@ -1,3 +1,4 @@
+import commands
 from planetstack.config import Config
 from openstack.client import OpenStackClient
 
@@ -206,7 +207,7 @@
                                  'dns_nameservers': ['8.8.8.8', '8.8.4.4'],
                                  'allocation_pools': allocation_pools}}          
             subnet = self.shell.quantum.create_subnet(subnet)['subnet']
-
+            self.add_external_route(subnet)
         # TODO: Add route to external network
         # e.g. #  route add -net 10.0.3.0/24 dev br-ex gw 10.100.0.5 
         return subnet
@@ -222,7 +223,64 @@
             if subnet['id'] == id:
                 self.delete_subnet_ports(subnet['id'])
                 self.shell.quantum.delete_subnet(id)
-        return
+                self.delete_external_route(subnet)
+        return 1
+
+    def add_external_route(self, subnet):
+        ports = self.shell.quantum.list_ports()['ports']
+
+        gw_ip = subnet['gateway_ip']
+        subnet_id = subnet['id']
+
+        # 1. Find the port associated with the subnet's gateway
+        # 2. Find the router associated with that port
+        # 3. Find the port associated with this router and on the external net
+        # 4. Set up route to the subnet through the port from step 3
+        ip_address = None
+        for port in ports:
+            for fixed_ip in port['fixed_ips']:
+                if fixed_ip['subnet_id'] == subnet_id and fixed_ip['ip_address'] == gw_ip:
+                    gw_port = port
+                    router_id = gw_port['device_id']
+                    router = self.shell.quantum.show_router(router_id)['router']
+                    ext_net = router['external_gateway_info']['network_id']
+                    for port in ports:
+                        if port['device_id'] == router_id and port['network_id'] == ext_net:
+                            ip_address = port['fixed_ips'][0]['ip_address']
+
+        if ip_address:
+            cmd = "route add -net %s dev br-ex gw %s" % (subnet['cidr'], ip_address)
+            commands.getstatusoutput(cmd)
+
+        return 1
+
+    def delete_external_route(self, subnet):
+        ports = self.shell.quantum.list_ports()['ports']
+
+        gw_ip = subnet['gateway_ip']
+        subnet_id = subnet['id']
+
+        # 1. Find the port associated with the subnet's gateway
+        # 2. Find the router associated with that port
+        # 3. Find the port associated with this router and on the external net
+        # 4. Set up route to the subnet through the port from step 3
+        ip_address = None
+        for port in ports:
+            for fixed_ip in port['fixed_ips']:
+                if fixed_ip['subnet_id'] == subnet_id and fixed_ip['ip_address'] == gw_ip:
+                    gw_port = port
+                    router_id = gw_port['device_id']
+                    router = self.shell.quantum.show_router(router_id)['router']
+                    ext_net = router['external_gateway_info']['network_id']
+                    for port in ports:
+                        if port['device_id'] == router_id and port['network_id'] == ext_net:
+                            ip_address = port['fixed_ips'][0]['ip_address']
+
+        if ip_address:
+            cmd = "route delete -net %s" % (subnet['cidr'])
+            commands.getstatusoutput(cmd)
+             
+        return 1
     
     def create_keypair(self, name, key):
         keys = self.shell.nova.keypairs.findall(name=name)
diff --git a/planetstack/openstack/manager.py b/planetstack/openstack/manager.py
index 788a621..166ad19 100644
--- a/planetstack/openstack/manager.py
+++ b/planetstack/openstack/manager.py
@@ -1,13 +1,10 @@
+from netaddr import IPAddress, IPNetwork
 from planetstack import settings
-#from django.core import management
-#management.setup_environ(settings)
-import os
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "planetstack.settings")
-
+from django.core import management
+from planetstack.config import Config
 try:
     from openstack.client import OpenStackClient
     from openstack.driver import OpenStackDriver
-    from planetstack.config import Config
     from core.models import * 
     has_openstack = True
 except:
@@ -28,17 +25,39 @@
 class OpenStackManager:
 
     def __init__(self, auth={}, caller=None):
-        if auth:
-            self.client = OpenStackClient(**auth)
-        else:
-            self.client = OpenStackClient()   
+        self.client = None
+        self.driver = None
+        self.caller = None
         self.has_openstack = has_openstack       
-        self.enabled = manager_enabled 
-        self.driver = OpenStackDriver(client=self.client) 
-        self.caller=caller
-        if not self.caller:
-            self.caller = self.driver.admin_user
-            self.caller.kuser_id = self.caller.id 
+        self.enabled = manager_enabled
+
+        if has_openstack and manager_enabled:
+            if auth:
+                try:
+                    self.init_user(auth, caller)
+                except:
+                    # if this fails then it meanse the caller doesn't have a
+                    # role at the slice's tenant. if the caller is an admin
+                    # just use the admin client/manager.
+                    if caller and caller.is_admin: 
+                        self.init_admin()
+                    else: raise
+            else:
+                self.init_admin()
+
+    @require_enabled 
+    def init_user(self, auth, caller):
+        self.client = OpenStackClient(**auth)
+        self.driver = OpenStackDriver(client=self.client)
+        self.caller = caller                 
+    
+    @require_enabled
+    def init_admin(self):
+        # use the admin credentials 
+        self.client = OpenStackClient()
+        self.driver = OpenStackDriver(client=self.client)
+        self.caller = self.driver.admin_user
+        self.caller.kuser_id = self.caller.id 
 
     @require_enabled
     def save_role(self, role):
@@ -54,7 +73,7 @@
     @require_enabled
     def save_key(self, key):
         if not key.key_id:
-            key_fields = {'name': key.name,
+            key_fields = {'name': key.user.email[:key.user.email.find('@')],
                           'key': key.key}
             nova_key = self.driver.create_keypair(**key_fields)
             key.key_id = nova_key.id        
@@ -74,14 +93,19 @@
                            'enabled': True}
             keystone_user = self.driver.create_user(**user_fields)
             user.kuser_id = keystone_user.id
-    
+        if user.site:
+            self.driver.add_user_role(user.kuser_id, user.site.tenant_id, 'user')
+            if user.is_admin:
+                self.driver.add_user_role(user.kuser_id, user.site.tenant_id, 'admin')
+            else:
+                # may have admin role so attempt to remove it
+                self.driver.delete_user_role(user.kuser_id, user.site.tenant_id, 'admin')
+  
     @require_enabled
     def delete_user(self, user):
         if user.kuser_id:
             self.driver.delete_user(user.kuser_id)        
     
-
-    
     @require_enabled
     def save_site(self, site, add_role=True):
         if not site.tenant_id:
@@ -128,6 +152,23 @@
             router = self.driver.create_router(slice.name)
             slice.router_id = router['id']
 
+            # create subnet
+            next_subnet = self.get_next_subnet()
+            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=slice.name,
+                                               network_id = network['id'],
+                                               cidr_ip = cidr,
+                                               ip_version = ip_version,
+                                               start = start,
+                                               end = end)
+            slice.subnet_id = subnet['id']
+            # add subnet as interface to slice's router
+            self.driver.add_router_interface(router['id'], subnet['id'])
+ 
+
         if slice.id and slice.tenant_id:
             self.driver.update_tenant(slice.tenant_id,
                                       description=slice.description,
@@ -136,10 +177,26 @@
     @require_enabled
     def delete_slice(self, slice):
         if slice.tenant_id:
+            self.driver.delete_router_interface(slice.router_id, slice.subnet_id)
+            self.driver.delete_subnet(slice.subnet_id)
             self.driver.delete_router(slice.router_id)
             self.driver.delete_network(slice.network_id)
             self.driver.delete_tenant(slice.tenant_id)
 
+    
+
+    def get_next_subnet(self):
+        # limit ourself to 10.0.x.x for now
+        valid_subnet = lambda net: net.startswith('10.0')  
+        subnets = self.driver.shell.quantum.list_subnets()['subnets']
+        ints = [int(IPNetwork(subnet['cidr']).ip) for subnet in subnets \
+                if valid_subnet(subnet['cidr'])] 
+        ints.sort()
+        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
+
     @require_enabled
     def save_subnet(self, subnet):    
         if not subnet.subnet_id:
@@ -163,7 +220,7 @@
             self.driver.delete_subnet(subnet.subnet_id)
             #del_route = 'route del -net %s' % self.cidr
             #commands.getstatusoutput(del_route)
-    
+
     @require_enabled
     def save_sliver(self, sliver):
         if not sliver.instance_id:
@@ -174,6 +231,9 @@
             sliver.instance_id = instance.id
             sliver.instance_name = getattr(instance, 'OS-EXT-SRV-ATTR:instance_name')
 
+        if sliver.instance_id and ("numberCores" in sliver.changed_fields):
+            self.driver.update_instance_metadata(sliver.instance_id, {"cpu_cores": str(sliver.numberCores)})
+
     @require_enabled
     def delete_sliver(self, sliver):
         if sliver.instance_id:
diff --git a/planetstack/planetstack/urls.py b/planetstack/planetstack/urls.py
index 58d9ce7..dbe9f49 100644
--- a/planetstack/planetstack/urls.py
+++ b/planetstack/planetstack/urls.py
@@ -8,7 +8,6 @@
 from core.views.users import UserListCreate, UserRetrieveUpdateDestroy
 from core.views.slices import SliceListCreate, SliceRetrieveUpdateDestroy
 from core.views.slice_memberships import SliceMembershipListCreate, SliceMembershipRetrieveUpdateDestroy
-from core.views.subnets import SubnetListCreate, SubnetRetrieveUpdateDestroy
 from core.views.slivers import SliverListCreate, SliverRetrieveUpdateDestroy
 from core.views.keys import KeyListCreate, KeyRetrieveUpdateDestroy
 from core.views.deployment_networks import DeploymentNetworkListCreate, DeploymentNetworkRetrieveUpdateDestroy
@@ -54,9 +53,6 @@
     url(r'^plstackapi/slice_memberships/$', SliceMembershipListCreate.as_view(), name='slice_membership-list'),
     url(r'^plstackapi/slice_memberships/(?P<pk>[0-9]+)/$', SliceMembershipRetrieveUpdateDestroy.as_view(), name='slice_membership-detail'),
     
-    url(r'^plstackapi/subnets/$', SubnetListCreate.as_view(), name='subnet-list'),
-    url(r'^plstackapi/subnets/(?P<pk>[a-zA-Z0-9_\-]+)/$', SubnetRetrieveUpdateDestroy.as_view(), name='subnet-detail'),
-
     url(r'^plstackapi/slivers/$', SliverListCreate.as_view(), name='sliver-list'),
     url(r'^plstackapi/slivers/(?P<pk>[a-zA-Z0-9_\-]+)/$', SliverRetrieveUpdateDestroy.as_view(), name='sliver-detail'),
 
diff --git a/setup.py b/setup.py
index cfc60f9..c8a1089 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@
 setup(name='plstackapi',
       version='0.1',
       description='PlanetStack API',
-      packages=['plstackapi', 'plstackapi/planetstack', 'plstackapi/core', 'plstackapi/core/views', 'plstackapi/core/api', 'plstackapi/core/fixtures', 'plstackapi/openstack' ,'plstackapi/util', 'plstackapi/importer', 'plstackapi/importer/plclassic'],
+      packages=['plstackapi', 'plstackapi/planetstack', 'plstackapi/core','plstackapi/core/models' , 'plstackapi/core/views', 'plstackapi/core/api', 'plstackapi/core/fixtures', 'plstackapi/openstack' ,'plstackapi/util', 'plstackapi/importer', 'plstackapi/importer/plclassic'],
       scripts=['plstackapi/plstackapi-debug-server.py'],
       data_files=[
         ('/etc/planetstack/', ['config/plstackapi_config']),