Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi
diff --git a/planetstack/core/models/__init__.py b/planetstack/core/models/__init__.py
index 7c10fc8..bf0015a 100644
--- a/planetstack/core/models/__init__.py
+++ b/planetstack/core/models/__init__.py
@@ -27,5 +27,5 @@
 from .sliver import Sliver
 from .reservation import ReservedResource
 from .reservation import Reservation
-from .network import Network, NetworkParameterType, NetworkParameter, NetworkSliver, NetworkTemplate, Router, NetworkSlice
+from .network import Network, NetworkParameterType, NetworkParameter, NetworkSliver, NetworkTemplate, Router, NetworkSlice, NetworkDeployments
 from .billing import Account, Invoice, Charge, UsableObject, Payment
diff --git a/planetstack/observer/deleters/network_deleter.py b/planetstack/observer/deleters/network_deleter.py
index 880b91c..0d21fda 100644
--- a/planetstack/observer/deleters/network_deleter.py
+++ b/planetstack/observer/deleters/network_deleter.py
@@ -1,17 +1,19 @@
-from core.models import Network
+from core.models import Network, NetworkDeployments
 from observer.deleter import Deleter
+from observer.deleters.network_deployment_deleter import NetworkDeploymentDeleter
+from util.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
 
 class NetworkDeleter(Deleter):
     model='Network'
 
     def call(self, pk):
         network = Network.objects.get(pk=pk) 
-        if (network.router_id) and (network.subnet_id):
-            self.driver.delete_router_interface(network.router_id, network.subnet_id)
-        if network.subnet_id:
-            self.driver.delete_subnet(network.subnet_id)
-        if network.router_id:
-            self.driver.delete_router(network.router_id)
-        if network.network_id:
-            self.driver.delete_network(network.network_id)
+        network_deployment_deleter = NetworkDeploymentDeleter()
+        for network_deployment in NetworkDeployments.objects.filter(network=network):
+            try:
+                network_deployment_deleter(network_deployment.id)    
+            except:
+                logger.log_exc("Failed to delte network deployment %s" % network_deployment)
         network.delete()
diff --git a/planetstack/observer/deleters/network_deployment_deleter.py b/planetstack/observer/deleters/network_deployment_deleter.py
new file mode 100644
index 0000000..72b10b2
--- /dev/null
+++ b/planetstack/observer/deleters/network_deployment_deleter.py
@@ -0,0 +1,21 @@
+from core.models import Network, NetworkDeployments
+from observer.deleter import Deleter
+from openstack.driver import OpenStackDriver
+
+class NetworkDeploymentDeleter(Deleter):
+    model='NetworkDeployment'
+
+    def call(self, pk):
+        network_deployment = NetworkDeployments.objects.get(pk=pk)
+        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)
+        network_deployment.delete()
diff --git a/planetstack/observer/deleters/site_deleter.py b/planetstack/observer/deleters/site_deleter.py
index 17619c5..c97dee1 100644
--- a/planetstack/observer/deleters/site_deleter.py
+++ b/planetstack/observer/deleters/site_deleter.py
@@ -1,5 +1,6 @@
 from core.models import Site, SiteDeployments
 from observer.deleter import Deleter
+from observer.deleters.site_deployment_deleter import SiteDeploymentDeleter
 
 class SiteDeleter(Deleter):
     model='Site'
@@ -7,9 +8,7 @@
     def call(self, pk):
         site = Site.objects.get(pk=pk)
         site_deployments = SiteDeployments.objects.filter(site=site)
+        site_deployment_deleter = SiteDeploymentDeleter()
         for site_deployment in site_deployments:
-            if site_deployment.tenant_id:
-                driver = self.driver.admin_driver(deployment=site_deployment.deployment.name) 
-                driver.delete_tenant(site_deployment.tenant_id)
-            site_deployment.delete()
+            site_deployment_deleter(site_deployment.id)
         site.delete() 
diff --git a/planetstack/observer/deleters/site_deployment_deleter.py b/planetstack/observer/deleters/site_deployment_deleter.py
new file mode 100644
index 0000000..fa97be2
--- /dev/null
+++ b/planetstack/observer/deleters/site_deployment_deleter.py
@@ -0,0 +1,12 @@
+from core.models import Site, SiteDeployments
+from observer.deleter import Deleter
+
+class SiteDeploymentDeleter(Deleter):
+    model='SiteDeployments'
+
+    def call(self, pk):
+        site_deployment = SiteDeployments.objects.get(pk=pk)
+        if site_deployment.tenant_id:
+            driver = self.driver.admin_driver(deployment=site_deployment.deployment.name)
+            driver.delete_tenant(site_deployment.tenant_id)
+        site_deployment.delete()
diff --git a/planetstack/observer/deleters/slice_deleter.py b/planetstack/observer/deleters/slice_deleter.py
index 33985fb..90b58c3 100644
--- a/planetstack/observer/deleters/slice_deleter.py
+++ b/planetstack/observer/deleters/slice_deleter.py
@@ -1,31 +1,19 @@
 from core.models import Slice, SliceDeployments, User
 from observer.deleter import Deleter
+from observer.deleters.slice_deployment_deleter import SliceDeploymentDeleter
+from util.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
 
 class SliceDeleter(Deleter):
     model='Slice'
 
     def call(self, pk):
         slice = Slice.objects.get(pk=pk)
-        slice_deployments = SliceDeployments.objects.filter(slice=slice)
-        for slice_deployment in slice_deployments:
-            user = User.get(user=slice.creator)
-            driver = self.driver.admin_driver(deployment=slice_deployment.deployment.name)
-            client_driver = self.driver.client_driver(caller=user,
-                                                      tenant=slice.name,
-                                                      deployment=slice_deployment.deployment.name) 
-
-            client_driver.delete_router_interface(slice.router_id, slice.subnet_id)
-            client_driver.delete_subnet(slice.subnet_id)
-            client_driver.delete_router(slice.router_id)
-            client_driver.delete_network(slice.network_id)
-            driver.delete_tenant(slice.tenant_id)
-            # delete external route
-            subnet = None
-            subnets = client_driver.shell.quantum.list_subnets()['subnets']
-            for snet in subnets:
-                if snet['id'] == slice.subnet_id:
-                    subnet = snet
-            if subnet:
-                driver.delete_external_route(subnet)
-            slice_deployment.delete()
+        slice_deployment_deleter = SliceDeploymentDeleter()
+        for slice_deployment in SliceDeployments.objects.filter(slice=slice):
+            try:
+                slice_deployment_deleter(slice_deployment.id)
+            except:
+                logger.log_exc("Failed to delete slice_deployment %s" % slice_deployment) 
         slice.delete()
diff --git a/planetstack/observer/deleters/slice_deployment_deleter.py b/planetstack/observer/deleters/slice_deployment_deleter.py
new file mode 100644
index 0000000..33e0836
--- /dev/null
+++ b/planetstack/observer/deleters/slice_deployment_deleter.py
@@ -0,0 +1,34 @@
+from core.models import Slice, SliceDeployments, User
+from observer.deleter import Deleter
+from openstack.driver import OpenStackDriver
+
+class SliceDeploymentDeleter(Deleter):
+    model='SliceDeployments'
+
+    def call(self, pk):
+        slice_deployment = SliceDeployments.objects.get(pk=pk)
+        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)
+        # delete external route
+        #subnet = None
+        #subnets = client_driver.shell.quantum.list_subnets()['subnets']
+        #for snet in subnets:
+        #    if snet['id'] == slice_deployment.subnet_id:
+        #        subnet = snet
+        #if subnet:
+        #    driver.delete_external_route(subnet)
+        slice_deployment.delete()
diff --git a/planetstack/observer/deleters/user_deleter.py b/planetstack/observer/deleters/user_deleter.py
index b82ea4a..3573f8d 100644
--- a/planetstack/observer/deleters/user_deleter.py
+++ b/planetstack/observer/deleters/user_deleter.py
@@ -1,15 +1,13 @@
 from core.models import User, UserDeployments
 from observer.deleter import Deleter
+from observer.deleters.user_deployment_deleter import UserDeploymentDeleter
 
 class UserDeleter(Deleter):
     model='User'
 
     def call(self, pk):
         user = User.objects.get(pk=pk)
-        user_deployments = UserDeployments.objects.filter(user=user)
-        for user_deployment in user_deployments:
-            if user_deployment.user.kuser_id:
-                driver = self.driver.admin_driver(deployment=user_deployment.deployment.name)
-                driver.delete_user(user_deployment.user.kuser_id)
-            user_deployment.delete()
+        user_deployment_deleter = UserDeploymentDeleter()
+        for user_deployment in UserDeployments.objects.filter(user=user):
+            user_deployment_deleter(user_deployment.id)
         user.delete()
diff --git a/planetstack/observer/deleters/user_deployment_deleter.py b/planetstack/observer/deleters/user_deployment_deleter.py
new file mode 100644
index 0000000..49d349b
--- /dev/null
+++ b/planetstack/observer/deleters/user_deployment_deleter.py
@@ -0,0 +1,12 @@
+from core.models import User, UserDeployments
+from observer.deleter import Deleter
+
+class UserDeploymentDeleter(Deleter):
+    model='UserDeployment'
+
+    def call(self, pk):
+        user_deployment = UserDeployments.objects.get(pk=pk)
+        if user_deployment.user.kuser_id:
+            driver = self.driver.admin_driver(deployment=user_deployment.deployment.name)
+            driver.delete_user(user_deployment.user.kuser_id)
+        user_deployment.delete()
diff --git a/planetstack/observer/steps/sync_network_deployments.py b/planetstack/observer/steps/sync_network_deployments.py
index 3bfa103..e0e3eac 100644
--- a/planetstack/observer/steps/sync_network_deployments.py
+++ b/planetstack/observer/steps/sync_network_deployments.py
@@ -12,8 +12,8 @@
 logger = Logger(level=logging.INFO)
 
 class SyncNetworkDeployments(OpenStackSyncStep):
+    requested_interval = 0 
     provides=[NetworkDeployments]
-    request_interval = 0 
     
     def fetch_pending(self):
         # network deployments are not visible to users. We must ensure
@@ -48,7 +48,7 @@
         if ints:
             last_ip = IPAddress(ints[-1])
         else:
-            last_ip = IPAddress('10.0.0.1')
+            last_ip = IPAddress('10.0.0.0')
         last_ip = IPAddress(ints[-1])
         last_network = IPNetwork(str(last_ip) + "/24")
         next_network = IPNetwork(str(IPAddress(last_network) + last_network.size) + "/24")
diff --git a/planetstack/observer/steps/sync_networks.py b/planetstack/observer/steps/sync_networks.py
index cb1d52a..fd42f4e 100644
--- a/planetstack/observer/steps/sync_networks.py
+++ b/planetstack/observer/steps/sync_networks.py
@@ -15,55 +15,6 @@
     def fetch_pending(self):
         return Network.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
 
-    def save_network(self, network):
-        if not network.network_id and network.template.sharedNetworkName:
-                network.network_id = network.template.sharedNetworkId
-
-        if not network.network_id:
-            network_name = network.name
-
-            # create network
-            os_network = self.driver.create_network(network_name, shared=True)
-            network.network_id = os_network['id']
-
-            # create router
-            router = self.driver.create_router(network_name)
-            network.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=network_name,
-                                               network_id = network.network_id,
-                                               cidr_ip = cidr,
-                                               ip_version = ip_version,
-                                               start = start,
-                                               end = end)
-            network.subnet = cidr
-            network.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))
-        else:
-            (network.subnet_id, network.subnet) = self.driver.get_network_subnet(network.network_id)
-            logger.info("sync'ed subnet (%s) for network: %s" % (network.subnet, network))
-            network.save()
-
     def sync_record(self, network):
-        if network.owner and network.owner.creator:
-            try:
-                # update manager context
-                real_driver = self.driver
-                self.driver = self.driver.client_driver(network.owner.creator, network.owner.name)
-                self.save_network(network)
-                self.driver = real_driver
-                logger.info("saved network: %s" % (network))
-            except Exception,e:
-                logger.log_exc("save network failed: %s" % network)    
-                raise e
+        network.save()
 
diff --git a/planetstack/observer/steps/sync_slice_deployments.py b/planetstack/observer/steps/sync_slice_deployments.py
index 2254e7b..01a10dd 100644
--- a/planetstack/observer/steps/sync_slice_deployments.py
+++ b/planetstack/observer/steps/sync_slice_deployments.py
@@ -5,6 +5,7 @@
 from django.db.models import F, Q
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
+from core.models.deployment import Deployment
 from core.models.site import SiteDeployments
 from core.models.slice import Slice, SliceDeployments
 from core.models.user import UserDeployments
@@ -13,7 +14,7 @@
 logger = Logger(level=logging.INFO)
 
 class SyncSliceDeployments(OpenStackSyncStep):
-    provides=[Slice, SliceDeployments]
+    provides=[SliceDeployments]
     requested_interval=0
 
     def fetch_pending(self):
@@ -29,7 +30,7 @@
         for slice_deployment in slice_deployments:
             slice_deploy_lookup[slice_deployment.slice].append(slice_deployment.deployment)
         
-        all_deployments = Deployment.objects.filter() 
+        all_deployments = Deployment.objects.all() 
         for slice in Slice.objects.all():
             # slices are added to all deployments for now
             expected_deployments = all_deployments
@@ -98,30 +99,30 @@
                     client_driver.create_keypair(**key_fields)
 
                 # create network
-                network = client_driver.create_network(slice_deployment.slice.name)
-                slice_deployment.network_id = network['id']
+                #network = client_driver.create_network(slice_deployment.slice.name)
+                #slice_deployment.network_id = network['id']
 
                 # create router
-                router = client_driver.create_router(slice_deployment.slice.name)
-                slice_deployment.router_id = router['id']
+                #router = client_driver.create_router(slice_deployment.slice.name)
+                #slice_deployment.router_id = router['id']
 
                 # create subnet for slice's private network
-                next_subnet = self.get_next_subnet(deployment=slice_deployment.deployment.name)
-                cidr = str(next_subnet.cidr)
-                ip_version = next_subnet.version
-                start = str(next_subnet[2])
-                end = str(next_subnet[-2]) 
-                subnet = client_driver.create_subnet(name=slice_deployment.slice.name,
-                                                   network_id = network['id'],
-                                                   cidr_ip = cidr,
-                                                   ip_version = ip_version,
-                                                   start = start,
-                                                   end = end)
-                slice_deployment.subnet_id = subnet['id']
+                #next_subnet = self.get_next_subnet(deployment=slice_deployment.deployment.name)
+                #cidr = str(next_subnet.cidr)
+                #ip_version = next_subnet.version
+                #start = str(next_subnet[2])
+                #end = str(next_subnet[-2]) 
+                #subnet = client_driver.create_subnet(name=slice_deployment.slice.name,
+                #                                   network_id = network['id'],
+                #                                   cidr_ip = cidr,
+                #                                   ip_version = ip_version,
+                #                                   start = start,
+                #                                   end = end)
+                #slice_deployment.subnet_id = subnet['id']
                 # add subnet as interface to slice's router
-                client_driver.add_router_interface(router['id'], subnet['id'])
+                #client_driver.add_router_interface(router['id'], subnet['id'])
                 # add external route
-                client_driver.add_external_route(subnet)
+                #client_driver.add_external_route(subnet)
 
 
         if slice_deployment.id and slice_deployment.tenant_id:
diff --git a/planetstack/observer/steps/sync_slice_memberships.py b/planetstack/observer/steps/sync_slice_memberships.py
index 08b7b6a..6a4f75f 100644
--- a/planetstack/observer/steps/sync_slice_memberships.py
+++ b/planetstack/observer/steps/sync_slice_memberships.py
@@ -14,14 +14,11 @@
         return SlicePrivilege.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
 
     def sync_record(self, slice_memb):
-        if slice_memb.user.kuser_id and slice_memb.slice.tenant_id:
-                self.driver.add_user_role(slice_memb.user.kuser_id,
-                                          slice_memb.slice.tenant_id,
-                                          slice_memb.role.role)
-
         # sync slice memberships at all slice deployments 
         slice_deployments = SliceDeployments.objects.filter(slice=slice_memb.slice)
         for slice_deployment in slice_deployments:
+            if not slice_deployment.tenant_id:
+                continue
             user_deployments = UserDeployments.objects.filter(deployment=slice_deployment.deployment)
             if user_deployments:
                 kuser_id  = user_deployments[0].kuser_id
diff --git a/planetstack/observer/steps/sync_user_deployments.py b/planetstack/observer/steps/sync_user_deployments.py
index 2d6fc2f..cbbcb17 100644
--- a/planetstack/observer/steps/sync_user_deployments.py
+++ b/planetstack/observer/steps/sync_user_deployments.py
@@ -29,14 +29,17 @@
         for user_deployment in UserDeployments.objects.all():
             user_deploy_lookup[user_deployment.user].append(user_deployment.deployment)
        
-        user_deployments = [] 
+        user_deployments = []
+        all_deployments = Deployment.objects.filter() 
         for user in User.objects.all():
             if user.is_admin:
                 # admins should have an account at all deployments
                 expected_deployments = deployments
             else:
                 # normal users should have an account at their site's deployments
-                expected_deployments = site_deploy_lookup[user.site]
+                #expected_deployments = site_deploy_lookup[user.site]
+                # users are added to all deployments for now
+                expected_deployments = deployments        
             for expected_deployment in expected_deployments:
                 if not user in user_deploy_lookup or \
                   expected_deployment not in user_deploy_lookup[user]: 
diff --git a/planetstack/openstack/driver.py b/planetstack/openstack/driver.py
index d467dc1..80dd489 100644
--- a/planetstack/openstack/driver.py
+++ b/planetstack/openstack/driver.py
@@ -111,7 +111,16 @@
             for key in keys:
                 self.shell.nova.keypairs.delete(key)
             self.shell.keystone.users.delete(user)
-        return 1 
+        return 1
+
+    def get_admin_role(self):
+        role = None
+        for admin_role_name in ['admin', 'Admin']:
+            roles = self.shell.keystone.roles.findall(name=admin_role_name)
+            if roles:
+                role = roles[0]
+                break
+        return role 
 
     def add_user_role(self, kuser_id, tenant_id, role_name):
         user = self.shell.keystone.users.find(id=kuser_id)
@@ -119,13 +128,8 @@
         # admin role can be lowercase or title. Look for both
         role = None
         if role_name.lower() == 'admin':
-            for admin_role_name in ['admin', 'Admin']:
-                roles = self.shell.keystone.roles.findall(name=admin_role_name)
-                if roles:
-                    role = roles[0]
-                    break
-        
-        if not role:
+            role = self.get_admin_role()
+        else:
             # look up non admin role or force exception when admin role isnt found 
             role = self.shell.keystone.roles.find(name=role_name)                   
 
@@ -142,7 +146,13 @@
     def delete_user_role(self, kuser_id, tenant_id, role_name):
         user = self.shell.keystone.users.find(id=kuser_id)
         tenant = self.shell.keystone.tenants.find(id=tenant_id)
-        role = self.shell.keystone.roles.find(name=role_name)
+        # admin role can be lowercase or title. Look for both
+        role = None
+        if role_name.lower() == 'admin':
+            role = self.get_admin_role()
+        else:
+            # look up non admin role or force exception when admin role isnt found
+            role = self.shell.keystone.roles.find(name=role_name)
 
         role_found = False
         user_roles = user.list_roles(tenant.id)