Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi
diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py
index f2679ff..0469005 100644
--- a/planetstack/core/admin.py
+++ b/planetstack/core/admin.py
@@ -944,7 +944,7 @@
     def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
         deployment_nodes = []
         for node in Node.objects.all():
-            deployment_nodes.append( (node.deployment.id, node.id, node.name) )
+            deployment_nodes.append( (node.site_deployment.id, node.id, node.name) )
 
         deployment_flavors = []
         for flavor in Flavor.objects.all():
diff --git a/planetstack/dependency_walker.py b/planetstack/dependency_walker.py
index 93e1847..bc75b0c 100755
--- a/planetstack/dependency_walker.py
+++ b/planetstack/dependency_walker.py
@@ -55,7 +55,6 @@
 
 def __walk_deps(fn, object, deps):
 	model = object.__class__.__name__
-
 	for dep in deps:
 		#print "Checking dep %s"%dep
 		peer=None
@@ -74,8 +73,10 @@
 		if (peer):
 			try:
 				peer_objects = peer.all()
-			except:
+			except AttributeError:
 				peer_objects = [peer]
+			except:
+				peer_objects = []
 
 			for o in peer_objects:
 				fn(o, object)
diff --git a/planetstack/model-deps b/planetstack/model-deps
index d5d0e4c..33cb695 100644
--- a/planetstack/model-deps
+++ b/planetstack/model-deps
@@ -96,7 +96,8 @@
     ], 
     "ControllerSlices": [
         "Controller", 
-        "Slice"
+        "Slice",
+        "ControllerUsers"
     ], 
     "SiteDeployments": [
         "Site", 
diff --git a/planetstack/model_policies/model_policy_Slice.py b/planetstack/model_policies/model_policy_Slice.py
index 46ca9b8..659c139 100644
--- a/planetstack/model_policies/model_policy_Slice.py
+++ b/planetstack/model_policies/model_policy_Slice.py
@@ -1,5 +1,7 @@
 
 def handle(slice):
+        import pdb
+        pdb.set_trace()
 	from core.models import Controller, ControllerSiteDeployments, ControllerSlices,Controller,Network,NetworkSlice,NetworkTemplate
 	from collections import defaultdict
 	ctrl_site_deployments = ControllerSiteDeployments.objects.all()
@@ -14,7 +16,7 @@
 	
 	#expected_controllers = site_deploy_lookup[slice.site]
         all_controllers = Controller.objects.all() 
-	for expected_controller in controllers:
+	for expected_controller in all_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_policy.py b/planetstack/model_policy.py
index 38cc4df..de6f73d 100644
--- a/planetstack/model_policy.py
+++ b/planetstack/model_policy.py
@@ -12,8 +12,12 @@
     modelPolicyEnabled = x
 
 def update_dep(d, o):
-	if (d.updated < o.updated):
-		d.save(update_fields=['updated'])
+	try:
+		if (d.updated < o.updated):
+			d.save(update_fields=['updated'])
+	except AttributeError,e:
+		pdb.set_trace()
+		raise e
 	
 def delete_if_inactive(d, o):
 	#print "Deleting %s (%s)"%(d,d.__class__.__name__)
diff --git a/planetstack/openstack/client.py b/planetstack/openstack/client.py
index 6974dad..d776ec9 100644
--- a/planetstack/openstack/client.py
+++ b/planetstack/openstack/client.py
@@ -38,8 +38,10 @@
     return opts
 
 class Client:
-    def __init__(self, username=None, password=None, tenant=None, url=None, token=None, endpoint=None, deployment=None, admin=True, *args, **kwds):
+    def __init__(self, username=None, password=None, tenant=None, url=None, token=None, endpoint=None, controller=None, admin=True, *args, **kwds):
        
+        deployment = controller
+
         self.has_openstack = has_openstack
         self.url = deployment.auth_url
         if admin:
diff --git a/planetstack/openstack_observer/ansible.py b/planetstack/openstack_observer/ansible.py
index 8570c17..5761327 100755
--- a/planetstack/openstack_observer/ansible.py
+++ b/planetstack/openstack_observer/ansible.py
@@ -46,7 +46,6 @@
     template = os_template_env.get_template(name)
     buffer = template.render(opts)
 
-    import pdb
 
     #f = open('/tmp/obsans','w')
     try:
@@ -61,7 +60,6 @@
     f.write(buffer)
     f.flush()
 
-    #os.system('cp %s %s-backup'%(fqp,fqp))
     run = os.popen('/opt/planetstack/observer/run_ansible '+fqp)
     msg = run.read()
     status = run.close()
@@ -69,8 +67,17 @@
     try:
         ok_results = parse_output(msg)
     except ValueError,e:
-        print str(e)
-        raise e
+        all_fatal = re.findall(r'^msg: (.*)',msg,re.MULTILINE)
+        all_fatal2 = re.findall(r'^ERROR: (.*)',msg,re.MULTILINE)
+	
+	
+	all_fatal.extend(all_fatal2)
+        try:
+            error = ' // '.join(all_fatal)
+        except:
+            pass
+        raise Exception(error)
+
     return ok_results
 
 def main():
diff --git a/planetstack/openstack_observer/steps/sync_controller_images.py b/planetstack/openstack_observer/steps/sync_controller_images.py
index 4446d9a..0a0910e 100644
--- a/planetstack/openstack_observer/steps/sync_controller_images.py
+++ b/planetstack/openstack_observer/steps/sync_controller_images.py
@@ -7,6 +7,7 @@
 from core.models import Controller
 from core.models import Image, ControllerImages
 from util.logger import Logger, logging
+from observer.ansible import *
 

 logger = Logger(level=logging.INFO)
 
@@ -23,15 +24,18 @@
 
     def sync_record(self, controller_image):
         logger.info("Working on image %s on controller %s" % (controller_image.image.name, controller_image.controller))
+        import pdb
+        pdb.set_trace()
 
 	image_fields = {'endpoint':controller_image.controller.auth_url,
 			'admin_user':controller_image.controller.admin_user,
 			'admin_password':controller_image.controller.admin_password,
 			'name':controller_image.image.name,
-			'filepath':controller_image.image.path
+			'filepath':controller_image.image.path,
+	                'ansible_tag': '%s@%s'%(controller_image.image.name,controller_image.controller.name), # name of ansible playbook
 			}
 
-	res = run_template('sync_controller_images.yaml', image_fields)
+	res = run_template('sync_controller_images.yaml', image_fields, path='controller_images')
 
 	if (len(res)!=1):
 	    raise Exception('Could not sync image %s'%controller_image.image.name)
diff --git a/planetstack/openstack_observer/steps/sync_controller_images.yaml b/planetstack/openstack_observer/steps/sync_controller_images.yaml
index 55ad36a..aca7171 100644
--- a/planetstack/openstack_observer/steps/sync_controller_images.yaml
+++ b/planetstack/openstack_observer/steps/sync_controller_images.yaml
@@ -2,12 +2,12 @@
 - hosts: 127.0.0.1
   connection: local 
   tasks:
-  - glance:
+  - glance_image:
         auth_url: {{ endpoint }} 
-	username: {{ admin_user }}
-	tenant_name: 'admin'
-	password: {{ admin_password }}
-	name: {{ name }}
+        login_username: {{ admin_user }}
+        login_tenant_name: 'admin'
+        login_password: {{ admin_password }}
+        name: {{ name }}
         file: {{ filepath }}
-        format: 'raw'
+        disk_format: 'raw'
         is_public: true
diff --git a/planetstack/openstack_observer/steps/sync_controller_networks.py b/planetstack/openstack_observer/steps/sync_controller_networks.py
index 43769a7..3cff7c2 100644
--- a/planetstack/openstack_observer/steps/sync_controller_networks.py
+++ b/planetstack/openstack_observer/steps/sync_controller_networks.py
@@ -9,6 +9,7 @@
 from core.models.slice import *
 from core.models.sliver import Sliver
 from util.logger import Logger, logging
+from observer.ansible import *
 
 logger = Logger(level=logging.INFO)
 
@@ -37,16 +38,19 @@
             network_name = controller_network.network.name
             subnet_name = '%s-%d'%(network_name,controller_network.pk)
 	    cidr = self.alloc_subnet(controller_network.pk)
+	    slice = controller_network.network.slices.all()[0] # XXX: FIXME!!
+
 	    network_fields = {'endpoint':controller_network.controller.auth_url,
-			'admin_user':controller_network.network.slice.creator.email,
-			'tenant_name':controller_network.network.slice.slicename,
+			'admin_user':slice.creator.email, # XXX: FIXME
+			'tenant_name':slice.slicename, # XXX: FIXME
 			'admin_password':controller_network.controller.admin_password,
 			'name':network_name,
 			'subnet_name':subnet_name,
+			'ansible_tag':'%s-%s@%s'%(network_name,slice.slicename,controller_network.controller.name),
 			'cidr':cidr
 			}
 
-	    res = run_template('sync_controller_networks.yaml', network_fields)
+	    res = run_template('sync_controller_networks.yaml', network_fields, path = 'controller_networks')
 
 	    if (len(res)!=2):
 		raise Exception('Could not sync network %s'%controller_network.network.name)
@@ -68,7 +72,6 @@
             logger.info("controller %r has no admin_user, skipping" % controller_network.controller)
             return
 
-        self.driver = self.driver.admin_driver(controller=controller_network.controller,tenant='admin')
         if controller_network.network.owner and controller_network.network.owner.creator:
             try:
                 # update manager context
diff --git a/planetstack/openstack_observer/steps/sync_controller_networks.yaml b/planetstack/openstack_observer/steps/sync_controller_networks.yaml
index 4f2daf4..c85ec55 100644
--- a/planetstack/openstack_observer/steps/sync_controller_networks.yaml
+++ b/planetstack/openstack_observer/steps/sync_controller_networks.yaml
@@ -3,28 +3,27 @@
   connection: local 
   tasks:
   - quantum_network:
-	auth_url: {{ endpoint }} 
-	username: {{ admin_user }}
-	tenant_name: {{ tenant_name }}
-	password: {{ admin_password }}
-	name: {{ name }}
-	{% if delete %}
-	state: absent
-	{% else %}
-	state: present
-	{% endif %}
-        
+        auth_url={{ endpoint }} 
+        login_username={{ admin_user }}
+        tenant_name={{ tenant_name }}
+        login_password={{ admin_password }}
+        name={{ name }}
+        {% if delete %}
+        state=absent
+        {% else %}
+        state=present
+        {% endif %}
         shared: true
   - quantum_subnet:
-	auth_url: {{ endpoint }} 
-	username: {{ admin_user }}
-	tenant_name: {{ tenant_name }}
-	password: {{ admin_password }}
-	name={{ subnet_name }} 
+        auth_url={{ endpoint }} 
+        login_username={{ admin_user }}
+        tenant_name={{ tenant_name }}
+        login_password={{ admin_password }}
+        name={{ subnet_name }} 
         network_name={{ name }} 
-	{% if delete %}
-	state: absent
-	{% else %}
-	state=present 
-	cidr = {{ cidr }}
-	{% endif %}
+        {% if delete %}
+        state=absent
+        {% else %}
+        state=present 
+        cidr = {{ cidr }}
+        {% endif %}
diff --git a/planetstack/openstack_observer/steps/sync_controller_site_deployments.py b/planetstack/openstack_observer/steps/sync_controller_site_deployments.py
index 32ca19b..fb257f1 100644
--- a/planetstack/openstack_observer/steps/sync_controller_site_deployments.py
+++ b/planetstack/openstack_observer/steps/sync_controller_site_deployments.py
@@ -17,11 +17,12 @@
 		         'admin_user': controller_site_deployment.controller.admin_user,
 		         'admin_password': controller_site_deployment.controller.admin_password,
 		         'admin_tenant': 'admin',
+	                 'ansible_tag': '%s@%s'%(controller_site_deployment.site_deployment.site.login_base,controller_site_deployment.site_deployment.deployment.name), # name of ansible playbook
 		         'tenant': controller_site_deployment.site_deployment.site.login_base,
 		         'tenant_description': controller_site_deployment.site_deployment.site.name}
 
 	rendered = template.render(tenant_fields)
-	res = run_template('sync_controller_site_deployments.yaml', tenant_fields)
+	res = run_template('sync_controller_site_deployments.yaml', tenant_fields, path='site_deployments')
 
 	if (len(res)==1):
 		controller_site_deployment.tenant_id = res[0]['id']
@@ -32,6 +33,27 @@
 		raise Exception('Could not create or update user %s'%tenant_fields['tenant'])
             
     def delete_record(self, controller_site_deployment):
-        if controller_site_deployment.tenant_id:
+	if controller_site_deployment.tenant_id:
             driver = self.driver.admin_driver(controller=controller_site_deployment.controller)
             driver.delete_tenant(controller_site_deployment.tenant_id)
+
+	"""
+        Ansible does not support tenant deletion yet
+
+	import pdb
+	pdb.set_trace()
+        template = os_template_env.get_template('delete_controller_site_deployments.yaml')
+	tenant_fields = {'endpoint':controller_site_deployment.controller.auth_url,
+		         'admin_user': controller_site_deployment.controller.admin_user,
+		         'admin_password': controller_site_deployment.controller.admin_password,
+		         'admin_tenant': 'admin',
+	                 'ansible_tag': 'site_deployments/%s@%s'%(controller_site_deployment.site_deployment.site.login_base,controller_site_deployment.site_deployment.deployment.name), # name of ansible playbook
+		         'tenant': controller_site_deployment.site_deployment.site.login_base,
+		         'delete': True}
+
+	rendered = template.render(tenant_fields)
+	res = run_template('sync_controller_site_deployments.yaml', tenant_fields)
+
+	if (len(res)!=1):
+		raise Exception('Could not assign roles for user %s'%tenant_fields['tenant'])
+	"""
diff --git a/planetstack/openstack_observer/steps/sync_controller_slices.py b/planetstack/openstack_observer/steps/sync_controller_slices.py
index 636d007..c6021ba 100644
--- a/planetstack/openstack_observer/steps/sync_controller_slices.py
+++ b/planetstack/openstack_observer/steps/sync_controller_slices.py
@@ -9,6 +9,7 @@
 from core.models.controllerusers import ControllerUsers
 from util.logger import Logger, logging
 from observer.ansible import *
+import pdb
 
 logger = Logger(level=logging.INFO)
 
@@ -29,41 +30,46 @@
             logger.info("controller %r has no admin_user, skipping" % controller_slice.controller)
             return
 
-	controller_users = ControllerUsers.objects.filter(user=controller_slice.slice.creator,
-                                                             controller=controller_slice.controller)            
-    	if not controller_users:
-	    logger.info("slice createor %s has not accout at controller %s" % (controller_slice.slice.creator, controller_slice.controller.name))
-	    roles = []
-    	else:
-	    controller_user = controller_users[0]
-	    roles = ['admin']
-	    
-	max_instances=int(controller_slice.slice.max_slivers)
-	tenant_fields = {'endpoint':controller_slice.controller.auth_url,
-		         'admin_user': controller_slice.controller.admin_user,
-		         'admin_password': controller_slice.controller.admin_password,
-		         'admin_tenant': 'admin',
-		         'tenant': controller_slice.slice.name,
-		         'tenant_description': controller_slice.slice.description,
-			 'roles':roles,
-			 'name':controller_user.user.email,
-			 'max_instances':max_instances}
+        controller_users = ControllerUsers.objects.filter(user=controller_slice.slice.creator,
+                                                             controller=controller_slice.controller)
+        if not controller_users:
+            raise Exception("slice createor %s has not accout at controller %s" % (controller_slice.slice.creator, controller_slice.controller.name))
+        else:
+            controller_user = controller_users[0]
+            roles = ['admin']
 
-	res = run_template('sync_controller_slices.yaml', tenant_fields)
-	expected_num = len(roles)+1
-	if (len(res)!=expected_num):
-	    raise Exception('Could not sync tenants for slice %s'%controller_slice.slice.name)
-	else:
-	    tenant_id = res[0]['id']
-	    if (not controller_slice.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'%controller_slice.slice.name)
-		controller_slice.tenant_id = tenant_id
-		controller_slice.save()
-			
+        pdb.set_trace()
+        max_instances=int(controller_slice.slice.max_slivers)
+        tenant_fields = {'endpoint':controller_slice.controller.auth_url,
+                         'admin_user': controller_slice.controller.admin_user,
+                         'admin_password': controller_slice.controller.admin_password,
+                         'admin_tenant': 'admin',
+                         'tenant': controller_slice.slice.name,
+                         'tenant_description': controller_slice.slice.description,
+                         'roles':roles,
+                         'name':controller_user.user.email,
+                         'ansible_tag':'%s@%s'%(controller_slice.slice.name,controller_slice.controller.name),
+                         'max_instances':max_instances}
+
+        res = run_template('sync_controller_slices.yaml', tenant_fields, path='controller_slices')
+        expected_num = len(roles)+1
+        if (len(res)!=expected_num):
+            raise Exception('Could not sync tenants for slice %s'%controller_slice.slice.name)
+        else:
+            tenant_id = res[0]['id']
+            if (not controller_slice.tenant_id):
+                try:
+                        driver = OpenStackDriver().client_driver(caller=controller_slice.controller.admin_user,
+                                                         tenant=controller_slice.controller.admin_tenant,
+                                                         controller=controller_network.controller)
+                        driver.shell.nova.quotas.update(tenant_id=controller_slice.slice.name, instances=int(controller_slice.slice.max_slivers))
+                except:
+                        logging.info('Could not update quota for %s'%controller_slice.slice.name)
+                        raise Exception('Could not update quota for %s'%controller_slice.slice.name)
+
+                controller_slice.tenant_id = tenant_id
+                controller_slice.save()
+
 
 
     def delete_record(self, controller_slice):
@@ -77,10 +83,9 @@
             client_driver.delete_router_interface(controller_slice.router_id, controller_slice.subnet_id)
         if controller_slice.subnet_id:
             client_driver.delete_subnet(controller_slice.subnet_id)
-        if controller_slice.router_id:    
+        if controller_slice.router_id:
             client_driver.delete_router(controller_slice.router_id)
         if controller_slice.network_id:
             client_driver.delete_network(controller_slice.network_id)
         if controller_slice.tenant_id:
             driver.delete_tenant(controller_slice.tenant_id)
-        
diff --git a/planetstack/openstack_observer/steps/sync_controller_users.py b/planetstack/openstack_observer/steps/sync_controller_users.py
index b9e7b03..8f7e508 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 Controller, SiteDeployments
+from core.models.site import Controller, SiteDeployments, ControllerSiteDeployments
 from core.models.user import User
 from core.models.controllerusers import ControllerUsers
 from util.logger import Logger, logging
@@ -36,6 +36,8 @@
 	
         name = controller_user.user.email[:controller_user.user.email.find('@')]
 
+        import pdb
+        pdb.set_trace()
 	roles = ['user']
         if controller_user.user.is_admin:
             roles.append('admin')
@@ -54,7 +56,7 @@
             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
+		tenant_name = ctrl_site_deployments[0].site_deployment.site.login_base
 
                 user_fields = {'endpoint':controller_user.controller.auth_url,
 		       'name': controller_user.user.email,
@@ -62,12 +64,13 @@
                        'password': hashlib.md5(controller_user.user.password).hexdigest()[:6],
                        'admin_user': controller_user.controller.admin_user,
 		       'admin_password': controller_user.controller.admin_password,
+	               'ansible_tag':'%s@%s'%(controller_user.user.email.replace('@','-at-'),controller_user.controller.name),
 		       'admin_tenant': 'admin',
 		       'roles':roles,
 		       'tenant':tenant_name}    
 	
 	        rendered = template.render(user_fields)
-	        res = run_template('sync_controller_users.yaml', user_fields)
+	        res = run_template('sync_controller_users.yaml', user_fields,path='controller_users')
 
 	        # results is an array in which each element corresponds to an 
 	        # "ok" string received per operation. If we get as many oks as
diff --git a/planetstack/openstack_observer/steps/sync_nodes.py b/planetstack/openstack_observer/steps/sync_nodes.py
index d5edb02..8702a21 100644
--- a/planetstack/openstack_observer/steps/sync_nodes.py
+++ b/planetstack/openstack_observer/steps/sync_nodes.py
@@ -6,7 +6,7 @@
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models.node import Node
-from core.models.site import SiteDeployments, Controller
+from core.models.site import SiteDeployments, Controller, ControllerSiteDeployments
 from util.logger import Logger, logging
 
 logger = Logger(level=logging.INFO)
@@ -22,16 +22,24 @@
             return []
 
         # collect local nodes
-        site_deployments = SiteDeployments.objects.all()
+        controllers = Controller.objects.all()
         nodes = Node.objects.all()
         node_hostnames = [node.name for node in nodes]
 
         # fetch all nodes from each controller
-        controllers = Controller.objects.all()
         new_nodes = []
         for controller in controllers:
             try:
-                driver = self.driver.admin_driver(controller=controller)
+            	controller_site_deployments = ControllerSiteDeployments.objects.filter(controller=controller)[0]
+	    except IndexError:
+                raise Exception("Controller %s not bound to any site deployments"%controller.name)
+
+            site_deployment = controller_site_deployments.site_deployment
+            if (not site_deployment):
+                raise Exception('Controller without Site Deployment: %s'%controller.name)
+
+            try:
+                driver = self.driver.admin_driver(controller=controller,tenant='admin')
                 compute_nodes = driver.shell.nova.hypervisors.list()
             except:
                 logger.log_exc("Failed to get nodes from controller %s" % str(controller))
@@ -40,10 +48,9 @@
             for compute_node in compute_nodes:
                 if compute_node.hypervisor_hostname not in node_hostnames:
                     # XX TODO:figure out how to correctly identify a node's site.
-                    # XX pick a random site to add the node to for now
-                    site_index = random.randint(0, len(site_deployments))
+                    # XX pick the first one
                     node = Node(name=compute_node.hypervisor_hostname,
-                                site_deployment=site_deployments[site_index])
+                                site_deployment=site_deployment)
                     new_nodes.append(node)
 
         return new_nodes    
diff --git a/planetstack/openstack_observer/steps/sync_roles.py b/planetstack/openstack_observer/steps/sync_roles.py
index 91c0abb..f08a693 100644
--- a/planetstack/openstack_observer/steps/sync_roles.py
+++ b/planetstack/openstack_observer/steps/sync_roles.py
@@ -35,7 +35,7 @@
         if not role.enacted:
             controllers = Controller.objects.all()
        	    for controller in controllers:
-                driver = self.driver.admin_driver(controller=controller.name)
+                driver = self.driver.admin_driver(controller=controller)
                 driver.create_role(role.role)
             role.save()