Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi
diff --git a/opencloud.spec b/opencloud.spec
index 56de9d9..5831006 100644
--- a/opencloud.spec
+++ b/opencloud.spec
@@ -1,7 +1,7 @@
 Summary: OpenCloud core services
 Name: opencloud
-Version: 1.0.23
-Release: 0
+Version: 1.0.26
+Release: 7
 License: GPL+
 Group: Development/Tools
 Source0: %{_tmppath}/%{name}-%{version}.tar.gz
@@ -29,7 +29,7 @@
 # Empty section.
 
 %pre
-#pip-python install django==1.5
+pip-python install django==1.7
 pip-python install djangorestframework
 pip-python install markdown  # Markdown support for the browseable API.
 pip-python install pyyaml    # YAML content-type support.
@@ -46,12 +46,16 @@
 pip-python install django-evolution
 pip-python install django-bitfield
 pip-python install django-ipware
+pip-python install django-encrypted-fields
+pip-python install python-keyczar
 
 easy_install django_evolution
 easy_install python_gflags
 easy_install google_api_python_client
 
-wget -P /usr/lib/python2.7/site-packages/suit/static/suit/js http://code.jquery.com/jquery-1.9.1.min.js
+if [ ! -f /usr/lib/python2.7/site-packages/suit/static/suit/js/jquery-1.9.1.min.js ]; then
+    wget -P /usr/lib/python2.7/site-packages/suit/static/suit/js http://code.jquery.com/jquery-1.9.1.min.js
+fi
 
 if [ ! -f /usr/share/GeoIP/GeoLiteCity.dat ]; then
    rm -f /usr/share/GeoIP/GeoLiteCity.*
@@ -106,13 +110,20 @@
 ln -s ec2_observer /opt/planetstack/observer
 ln -s config-opencloud.py /opt/planetstack/syndicate_observer/syndicatelib_config/config.py
 
+if [ ! -e /opt/planetstack/public_keys ]; then
+    cd /opt/planetstack
+    scripts/opencloud genkeys
+fi
+
 if [ "$1" == 1 ] ; then
     echo "NEW INSTALL - initializing database"
     /opt/planetstack/scripts/opencloud initdb
 else
-    echo "UPGRADE - doing evolution"
+    # scripts/opencloud will choose evolve or migrate depending on django version
+    echo "UPGRADE - doing evolution/migration"
     /opt/planetstack/scripts/opencloud evolvedb
 fi
+
 # start the server
 /opt/planetstack/scripts/opencloud runserver
 
diff --git a/planetstack/cassandra/migrations/0001_initial.py b/planetstack/cassandra/migrations/0001_initial.py
new file mode 100644
index 0000000..370e245
--- /dev/null
+++ b/planetstack/cassandra/migrations/0001_initial.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0002_omf_friendly_default_false'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='CassandraService',
+            fields=[
+                ('service_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='core.Service')),
+                ('clusterSize', models.PositiveIntegerField(default=1)),
+                ('replicationFactor', models.PositiveIntegerField(default=1)),
+            ],
+            options={
+                'verbose_name': 'Cassandra Service',
+            },
+            bases=('core.service', models.Model),
+        ),
+    ]
diff --git a/planetstack/cassandra/migrations/__init__.py b/planetstack/cassandra/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/cassandra/migrations/__init__.py
diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py
index 62aa96a..1d64d9c 100644
--- a/planetstack/core/admin.py
+++ b/planetstack/core/admin.py
@@ -21,12 +21,12 @@
 def backend_icon(obj): # backend_status, enacted, updated):
     #return "%s %s %s" % (str(obj.updated), str(obj.enacted), str(obj.backend_status))
     if (obj.enacted is not None) and obj.enacted >= obj.updated:
-        return '<img src="/static/admin/img/icon_success.gif">'
+        return '<span style="min-width:16px;"><img src="/static/admin/img/icon_success.gif"></span>'
     else:
         if obj.backend_status == "Provisioning in progress" or obj.backend_status=="":
-            return '<span title="%s"><img src="/static/admin/img/icon_clock.gif"></span>' % obj.backend_status
+            return '<span style="min-width:16px;" title="%s"><img src="/static/admin/img/icon_clock.gif"></span>' % obj.backend_status
         else:
-            return '<span title="%s"><img src="/static/admin/img/icon_error.gif"></span>' % obj.backend_status
+            return '<span style="min-width:16px;" title="%s"><img src="/static/admin/img/icon_error.gif"></span>' % obj.backend_status
 
 def backend_text(obj):
     icon = backend_icon(obj)
@@ -266,7 +266,7 @@
 
 class SliverInline(PlStackTabularInline):
     model = Sliver
-    fields = ['backend_status_icon', 'all_ips_string', 'instance_name', 'slice', 'numberCores', 'deploymentNetwork', 'image', 'node']
+    fields = ['backend_status_icon', 'all_ips_string', 'instance_name', 'slice', 'deploymentNetwork', 'flavor', 'image', 'node']
     extra = 0
     readonly_fields = ['backend_status_icon', 'all_ips_string', 'instance_name']
     suit_classes = 'suit-tab suit-tab-slivers'
@@ -277,53 +277,14 @@
     def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
         if db_field.name == 'deploymentNetwork':
            kwargs['queryset'] = Deployment.select_by_acl(request.user)
-           # the inscrutable jquery selector below says:
-           #     find the closest parent "tr" to the current element
-           #     then find the child with class "field-node"
-           #     then find the child with that is a select
-           #     then return its id
-           kwargs['widget'] = forms.Select(attrs={'onChange': "update_nodes(this, $($(this).closest('tr')[0]).find('.field-node select')[0].id)"})
-           #kwargs['widget'] = forms.Select(attrs={'onChange': "console.log($($($(this).closest('tr')[0]).children('.field-node')[0]).children('select')[0].id);"})
+           kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_deployment_changed(this);"})
+        elif db_field.name == 'flavor':
+           kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_flavor_changed(this);"})
 
         field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
 
         return field
 
-"""
-    SMBAKER: This is the old code that implemented each network type as a
-    separate column in the sliver table.
-
-    def _declared_fieldsets(self):
-        # Return None so django will call get_fieldsets and we can insert our
-        # dynamic fields
-        return None
-
-    def get_readonly_fields(self, request, obj=None):
-        readonly_fields = list(super(SliverInline, self).get_readonly_fields(request, obj))
-
-        # Lookup the networks that are bound to the slivers, and add those
-        # network names to the list of readonly fields.
-
-        for sliver in obj.slivers.all():
-            for nbs in sliver.networksliver_set.all():
-                if nbs.ip:
-                    network_name = nbs.network.name
-                    if network_name not in [str(x) for x in readonly_fields]:
-                        readonly_fields.append(NetworkLookerUpper.get(network_name))
-
-        return readonly_fields
-
-    def get_fieldsets(self, request, obj=None):
-        form = self.get_formset(request, obj).form
-        # fields = the read/write files + the read-only fields
-        fields = list(self.fields)
-        for fieldName in self.get_readonly_fields(request,obj):
-            if not fieldName in fields:
-                fields.append(fieldName)
-
-        return [(None, {'fields': fields})]
-"""
-
 class SiteInline(PlStackTabularInline):
     model = Site
     extra = 0
@@ -485,8 +446,17 @@
             verbose_name=('Images'), is_stacked=False
         )
     )
+    flavors = forms.ModelMultipleChoiceField(
+        queryset=Flavor.objects.all(),
+        required=False,
+        help_text="Select which flavors should be usable on this deployment",
+        widget=FilteredSelectMultiple(
+            verbose_name=('Flavors'), is_stacked=False
+        )
+    )
     class Meta:
         model = Deployment
+        many_to_many = ["flavors",]
 
     def __init__(self, *args, **kwargs):
       request = kwargs.pop('request', None)
@@ -497,6 +467,7 @@
       if self.instance and self.instance.pk:
         self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
         self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
+        self.fields['flavors'].initial = self.instance.flavors.all()
 
     def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
         """ helper function for handling m2m relations from the MultipleChoiceField
@@ -536,6 +507,8 @@
     def save(self, commit=True):
       deployment = super(DeploymentAdminForm, self).save(commit=False)
 
+      deployment.flavors = self.cleaned_data['flavors']
+
       if commit:
         deployment.save()
 
@@ -547,7 +520,7 @@
         self.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
         self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
 
-        self.save_m2m()
+      self.save_m2m()
 
       return deployment
 
@@ -562,7 +535,7 @@
 
 class DeploymentAdmin(PlanetStackBaseAdmin):
     model = Deployment
-    fieldList = ['backend_status_text', 'name', 'sites', 'images', 'accessControl']
+    fieldList = ['backend_status_text', 'name', 'sites', 'images', 'flavors', 'accessControl']
     fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
     inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
     list_display = ['backend_status_icon', 'name']
@@ -729,11 +702,11 @@
 
 class SliceAdmin(PlanetStackBaseAdmin):
     form = SliceForm
-    fieldList = ['backend_status_text', 'name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
+    fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
     fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
     readonly_fields = ('backend_status_text', )
-    list_display = ('backend_status_icon', 'slicename', 'site','serviceClass', 'slice_url', 'max_slivers')
-    list_display_links = ('backend_status_icon', 'slicename', )
+    list_display = ('backend_status_icon', 'name', 'site','serviceClass', 'slice_url', 'max_slivers')
+    list_display_links = ('backend_status_icon', 'name', )
     inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
 
     user_readonly_fields = fieldList
@@ -747,21 +720,34 @@
     )
 
     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[node.deployment.id] = get(deployment_nodes, node.deployment.id, []).append( (node.id, node.name) )
-
         deployment_nodes = []
         for node in Node.objects.all():
             deployment_nodes.append( (node.deployment.id, node.id, node.name) )
 
-        context["deployment_nodes"] = deployment_nodes
+        deployment_flavors = []
+        for flavor in Flavor.objects.all():
+            for deployment in flavor.deployments.all():
+                deployment_flavors.append( (deployment.id, flavor.id, flavor.name) )
 
+        deployment_images = []
+        for image in Image.objects.all():
+            for imageDeployment in image.imagedeployments_set.all():
+                deployment_images.append( (imageDeployment.deployment.id, image.id, image.name) )
+
+        site_login_bases = []
+        for site in Site.objects.all():
+            site_login_bases.append((site.id, site.login_base))
+
+        context["deployment_nodes"] = deployment_nodes
+        context["deployment_flavors"] = deployment_flavors
+        context["deployment_images"] = deployment_images
+        context["site_login_bases"] = site_login_bases
         return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
 
     def formfield_for_foreignkey(self, db_field, request, **kwargs):
         if db_field.name == 'site':
             kwargs['queryset'] = Site.select_by_user(request.user)
+            kwargs['widget'] = forms.Select(attrs={'onChange': "update_slice_prefix(this, $($(this).closest('fieldset')[0]).find('.field-name input')[0].id)"})
 
         return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
 
@@ -882,10 +868,10 @@
 class SliverAdmin(PlanetStackBaseAdmin):
     form = SliverForm
     fieldsets = [
-        ('Sliver Details', {'fields': ['backend_status_text', 'slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
+        ('Sliver Details', {'fields': ['backend_status_text', 'slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
     ]
     readonly_fields = ('backend_status_text', )
-    list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
+    list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deploymentNetwork']
     list_display_links = ('backend_status_icon', 'ip',)
 
     suit_form_tabs =(('general', 'Sliver Details'),
@@ -894,7 +880,7 @@
 
     inlines = [TagInline]
 
-    user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
+    user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image']
 
     def formfield_for_foreignkey(self, db_field, request, **kwargs):
         if db_field.name == 'slice':
@@ -1332,6 +1318,12 @@
     user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
     user_readonly_inlines = []
 
+class FlavorAdmin(PlanetStackBaseAdmin):
+    list_display = ("backend_status_icon", "name", "flavor", "order", "default")
+    list_display_links = ("backend_status_icon", "name")
+    user_readonly_fields = ("name", "flavor")
+    fields = ("name", "description", "flavor", "order", "default")
+
 # register a signal that caches the user's credentials when they log in
 def cache_credentials(sender, user, request, **kwds):
     auth = {'username': request.POST['username'],
@@ -1450,7 +1442,6 @@
     dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
     dollar_total_payments = dollar_field("total_payments", "Total Payments")
 
-
 # Now register the new UserAdmin...
 admin.site.register(User, UserAdmin)
 # ... and, since we're not using Django's builtin permissions,
@@ -1493,4 +1484,5 @@
     admin.site.register(Sliver, SliverAdmin)
     admin.site.register(Image, ImageAdmin)
     admin.site.register(DashboardView, DashboardViewAdmin)
+    admin.site.register(Flavor, FlavorAdmin)
 
diff --git a/planetstack/core/dashboard/sites.py b/planetstack/core/dashboard/sites.py
index 7200035..a100117 100644
--- a/planetstack/core/dashboard/sites.py
+++ b/planetstack/core/dashboard/sites.py
@@ -14,8 +14,8 @@
         from django.conf.urls import patterns, url
         from views import DashboardCustomize, DashboardDynamicView, DashboardWelcomeView, DashboardAjaxView, SimulatorView, \
                           DashboardSummaryAjaxView, DashboardAddOrRemoveSliverView, DashboardUserSiteView, DashboardAnalyticsAjaxView, \
-                          TenantViewData,TenantCreateSlice, TenantAddOrRemoveSliverView, TenantPickSitesView, TenantDeleteSliceView, \
-                          TenantUpdateSlice, DashboardSliceInteractions
+                          TenantViewData,TenantCreateSlice, TenantAddUser,TenantAddOrRemoveSliverView, TenantPickSitesView, TenantDeleteSliceView, \
+                          TenantUpdateSlice, DashboardSliceInteractions, RequestAccessView
 
         from views import view_urls
 
@@ -37,6 +37,8 @@
                     name="customize"),
                url(r'^hpcdashuserslices/', self.admin_view(DashboardUserSiteView.as_view()),
                     name="hpcdashuserslices"),
+               url(r'^welcome/$', self.admin_view(DashboardWelcomeView.as_view()),
+                    name="welcome"),
                url(r'^hpcdashboard/', self.admin_view(DashboardAjaxView.as_view()),        # DEPRECATED
                     name="hpcdashboard"),
                url(r'^simulator/', self.admin_view(SimulatorView.as_view()),
@@ -53,6 +55,10 @@
                     name="tenantview"),
                url(r'^createnewslice/$', self.admin_view(TenantCreateSlice.as_view()),
                     name="createnewslice"),
+               url(r'^adduser/$', self.admin_view(TenantAddUser.as_view()),
+                      name="adduser"),

+               url(r'^requestaccess/$', RequestAccessView.as_view(),

+                      name="requestacces"),
 	       url(r'^updateslice/$', self.admin_view(TenantUpdateSlice.as_view()),
                     name="updateslice"),
                url(r'^picksites/$', self.admin_view(TenantPickSitesView.as_view()),
diff --git a/planetstack/core/dashboard/views/cdn.py b/planetstack/core/dashboard/views/cdn.py
index 4fb29cb..c276cca 100644
--- a/planetstack/core/dashboard/views/cdn.py
+++ b/planetstack/core/dashboard/views/cdn.py
@@ -36,7 +36,7 @@
 
         if (actionToDo == "add"):
             user_ip = request.GET.get("ip", get_ip(request))
-            slice_increase_slivers(request.user, user_ip, siteList, slice, 1)
+            slice_increase_slivers(request.user, user_ip, siteList, slice, image.objects.all()[0], 1)
         elif (actionToDo == "rem"):
             slice_decrease_slivers(request.user, siteList, slice, 1)
 
diff --git a/planetstack/core/dashboard/views/tenant.py b/planetstack/core/dashboard/views/tenant.py
index 930ccf6..0555867 100644
--- a/planetstack/core/dashboard/views/tenant.py
+++ b/planetstack/core/dashboard/views/tenant.py
@@ -1,7 +1,39 @@
 from view_common import *
+from core.models import *
 import functools
+from django.contrib.auth.models import BaseUserManager
+from django.core import serializers
+from django.core.mail import EmailMultiAlternatives
 
-BLESSED_SITES = ["Stanford", "Washington", "Princeton", "GeorgiaTech", "MaxPlanck"]
+BLESSED_DEPLOYMENTS = ["US-MaxPlanck", "US-GeorgiaTech", "US-Princeton", "US-Washington", "US-Stanford"]
+
+class RequestAccessView(View):
+    def post(self, request, *args, **kwargs):
+	email = request.POST.get("email", "0")
+	firstname = request.POST.get("firstname", "0")
+	lastname = request.POST.get("lastname", "0")
+	site = request.POST.get("site","0")
+	user = User(
+            email=BaseUserManager.normalize_email(email),
+            firstname=firstname,
+            lastname=lastname,
+	    is_active=False
+        )
+        user.save()
+	user.site=Site.objects.get(name=site)
+	user.save(update_fields=['site'])
+	sitePriv = SitePrivilege.objects.filter(site=user.site)
+	userId = user.id
+	userUrl = "http://"+request.get_host()+"/admin/core/user/"+str(userId)
+	for sp in sitePriv:
+		subject, from_email, to = 'Authorize OpenCloud User Account', 'support@opencloud.us', str(sp.user)
+		text_content = 'This is an important message.'
+		html_content = """<p>Please authorize the following user on site """+site+""": <br><br>User: """+firstname+""" """+lastname+"""<br>Email: """+email+"""<br><br>
+Check the checkbox next to Is Active property at <a href="""+userUrl+"""> this link</a> to authorize the user. If you do not recognize this individual, or otherwise do not want to approve this account, please ignore this email. If you do not approve this request in 48 hours, the account will automatically be deleted.</p>"""
+		msg = EmailMultiAlternatives(subject,text_content, from_email, [to])
+		msg.attach_alternative(html_content, "text/html")
+		msg.send()
+        return HttpResponse(serializers.serialize("json",[user,]), content_type='application/javascript')
 
 class TenantCreateSlice(View):
     def post(self, request, *args, **kwargs):
@@ -15,6 +47,7 @@
         networkPorts = request.POST.get("network","0")
         mountDataSets = request.POST.get("mountDataSets","0")
         privateVolume = request.POST.get("privateVolume","0")
+        userEmail = request.POST.get("userEmail","0")
         if (actionToDo == "add"):
            serviceClass = ServiceClass.objects.get(name=serviceClass)
            site = request.user.site
@@ -31,6 +64,19 @@
 	   addOrModifyPorts(networkPorts,sliceName)

 	   if privateVolume=="true":

 	   	privateVolForSlice(request.user,sliceName)
+	   slicePrivs=SlicePrivilege(user=User.objects.get(email=userEmail),slice=Slice.objects.get(name=sliceName),role=SliceRole.objects.get(role="admin"))
+           slicePrivs.save()
+        return HttpResponse(json.dumps("Slice created"), content_type='application/javascript')
+
+class TenantAddUser(View):
+    def post(self, request, *args, **kwargs):
+        if request.user.isReadOnlyUser():
+            return HttpResponseForbidden("User is in read-only mode")
+
+        sliceName = request.POST.get("sliceName", "0")
+        userEmail = request.POST.get("userEmail","0")
+        slicePrivs=SlicePrivilege(user=User.objects.get(email=userEmail),slice=Slice.objects.get(name=sliceName),role=SliceRole.objects.get(role="admin"))
+        slicePrivs.save()
         return HttpResponse(json.dumps("Slice created"), content_type='application/javascript')
 
 def privateVolForSlice(user,sliceName):
@@ -103,41 +149,61 @@
     tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
     tenantSliceDetails['image']=userSliceTableFormatter(getImageInfo(user))
     tenantSliceDetails['deploymentSites']=userSliceTableFormatter(getDeploymentSites())
-    tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo())
+    #tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo())
     tenantSliceDetails['mountDataSets'] = userSliceTableFormatter(getMountDataSets())
     tenantSliceDetails['publicKey'] = getPublicKey(user)
+    tenantSliceDetails['availableSites']=userSliceTableFormatter(getAvailableSites())
+    tenantSliceDetails['role']=getUserRole(user)
+    tenantSliceDetails['siteUsers']=getSiteUsers(user)
     return tenantSliceDetails
 
+def getSiteUsers(user):
+	users = User.objects.filter(site=user.site)
+	siteUsers=[]
+        for entry in users:
+		siteUsers.append(str(entry))
+	return siteUsers
+
+
+def getUserRole(user):
+	sp=SitePrivilege.objects.filter(user=user)
+	for entry in sp:
+		return str(entry.role)
+
+
 def getTenantInfo(user):
     slices =Slice.objects.all()
     userSliceInfo = []
     for entry in slices:
-       sliceName = Slice.objects.get(id=entry.id).name
-       slice = Slice.objects.get(name=Slice.objects.get(id=entry.id).name)
-       sliceServiceClass = entry.serviceClass.name
-       preferredImage =  entry.imagePreference
-       #sliceDataSet = entry.mountDataSets
-       sliceNetwork = {}
-       numSliver = 0
-       sliceImage=""
-       sliceSite = {}
-       sliceNode = {}
-       sliceInstance= {}
-       #createPrivateVolume(user,sliceName)
-       for sliver in slice.slivers.all():
-	    if sliver.node.site.name in BLESSED_SITES:
-                sliceSite[sliver.node.site.name] = sliceSite.get(sliver.node.site.name,0) + 1
-                sliceImage = sliver.image.name
-                sliceNode[str(sliver)] = sliver.node.name
-       numSliver = sum(sliceSite.values())
-       numSites = len(sliceSite)
-       userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'instanceNodePair':sliceNode})
+       if (entry.site == user.site):
+           sliceName = Slice.objects.get(id=entry.id).name
+           slice = Slice.objects.get(name=Slice.objects.get(id=entry.id).name)
+           sliceServiceClass = entry.serviceClass.name
+           preferredImage =  entry.imagePreference
+           #sliceDataSet = entry.mountDataSets
+           sliceNetwork = {}
+           numSliver = 0
+           sliceImage=""
+           sliceSite = {}
+           sliceNode = {}
+           sliceInstance= {}
+           #createPrivateVolume(user,sliceName)
+           available_sites = getAvailableSites()
+           for sliver in slice.slivers.all():
+                if sliver.node.site.name in available_sites:
+                    sliceSite[sliver.node.site.name] = sliceSite.get(sliver.node.site.name,0) + 1
+                    sliceImage = sliver.image.name
+                    sliceNode[str(sliver)] = sliver.node.name
+           numSliver = sum(sliceSite.values())
+           numSites = len(sliceSite)
+           userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'instanceNodePair':sliceNode})
     return userSliceInfo
 
 def getTenantSitesInfo():
+        availableSites=getAvailableSites()
 	tenantSiteInfo=[]
         for entry in Site.objects.all():
-            if entry.name in BLESSED_SITES:
+            if entry.name in availableSites:
 		 tenantSiteInfo.append({'siteName':entry.name})
 	return tenantSiteInfo
 
@@ -156,12 +222,23 @@
     return sliceInfo
 
 def getImageInfo(user):
-    imageList = Image.objects.all()
-    #imageList = ['Fedora 16 LXC rev 1.3','Hadoop','MPI']
+    #imageList = Image.objects.all()
+    #imageInfo = []
+    #for imageEntry in imageList:
+          #imageInfo.append({'Image':imageEntry.name})
     imageInfo = []
-    for imageEntry in imageList:
-          imageInfo.append({'Image':imageEntry.name})
-          #imageInfo.append({'Image':imageEntry})
+    tempImageInfo = []
+    length = len(BLESSED_DEPLOYMENTS)
+    for deployment in Deployment.objects.all():
+        if deployment.name in BLESSED_DEPLOYMENTS:
+            for x in deployment.imagedeployments_set.all():
+                tempImageInfo.append(x.image.name)
+    temp = {}
+    for i in set(tempImageInfo):
+    	temp[i] = tempImageInfo.count(i)
+    for key in temp:
+	if temp[key]>1:
+		imageInfo.append(key)
     return imageInfo
 
 def createPrivateVolume(user, sliceName):
@@ -228,6 +305,15 @@
         deploymentInfo.append({'DeploymentSite':entry.name})
     return deploymentInfo
 
+def getAvailableSites():
+    available_sites = []
+    for deployment in Deployment.objects.all():
+        if deployment.name in BLESSED_DEPLOYMENTS:
+            for x in deployment.sitedeployments_set.all():
+		if x.site.nodes.all():
+                	available_sites.append(x.site.name)
+    return list(set(available_sites))
+
 class TenantDeleteSliceView(View):
         def post(self,request):

                 if request.user.isReadOnlyUser():

@@ -260,12 +346,14 @@
         actionToDo = request.POST.get("actionToDo", None)
         count = int(request.POST.get("count","0"))
 	sliceName = request.POST.get("slice", None)
+	imageName = request.POST.get("image",None)
         noAct = request.POST.get("noAct", False)
 
         if not sliceName:
             return HttpResponseServerError("No slice name given")
 
         slice = Slice.objects.get(name=sliceName)
+	image = Image.objects.get(name=imageName)
 
         if siteName:
             siteList = [Site.objects.get(name=siteName)]
@@ -277,7 +365,7 @@
             if (siteList is None):
                 siteList = tenant_pick_sites(user, user_ip, slice, count)
 
-            sitesChanged = slice_increase_slivers(request.user, user_ip, siteList, slice, count, noAct)
+            sitesChanged = slice_increase_slivers(request.user, user_ip, siteList, slice, image, count, noAct)
         elif (actionToDo == "rem"):
             sitesChanged = slice_decrease_slivers(request.user, siteList, slice, count, noAct)
         else:
@@ -328,8 +416,9 @@
         print "exception in geo code"
         traceback.print_exc()
 
+    available_sites = getAvailableSites()
     sites = Site.objects.all()
-    sites = [x for x in sites if x.name in BLESSED_SITES]
+    sites = [x for x in sites if x.name in available_sites]
     sites = sorted(sites, key=functools.partial(siteSortKey, slice=slice, count=count, lat=lat, lon=lon))
 
     return sites
@@ -337,3 +426,7 @@
 class TenantViewData(View):
     def get(self, request, **kwargs):
         return HttpResponse(json.dumps(getTenantSliceInfo(request.user, True)), content_type='application/javascript')
+
+class RequestAccountView(View):
+    def get(self, request, **kwargs):
+        return HttpResponse()
diff --git a/planetstack/core/dashboard/views/view_common.py b/planetstack/core/dashboard/views/view_common.py
index b3c0a52..7d51435 100644
--- a/planetstack/core/dashboard/views/view_common.py
+++ b/planetstack/core/dashboard/views/view_common.py
@@ -68,7 +68,7 @@
         for sliver in slice.slivers.all():
              #sites_used['deploymentSites'] = sliver.node.deployment.name
              # sites_used[sliver.image.name] = sliver.image.name
-             sites_used[sliver.node.site.name] = sliver.numberCores
+             sites_used[sliver.node.site.name] = 1 #sliver.numberCores
         sliceid = Slice.objects.get(id=entry.slice.id).id
         try:
             sliverList = Sliver.objects.filter(slice=entry.slice.id)
@@ -175,7 +175,7 @@
 
     return new_rows
 
-def slice_increase_slivers(user, user_ip, siteList, slice, count, noAct=False):
+def slice_increase_slivers(user, user_ip, siteList, slice, image, count, noAct=False):
     sitesChanged = {}
 
     # let's compute how many slivers are in use in each node of each site
@@ -202,10 +202,9 @@
             sliver = Sliver(name=node.name,
                         slice=slice,
                         node=node,
-                        image = Image.objects.all()[0],
+                        image = image,
                         creator = User.objects.get(email=user),
-                        deploymentNetwork=node.deployment,
-                        numberCores =1 )
+                        deploymentNetwork=node.deployment)
             sliver.save()
 
         node.sliverCount = node.sliverCount + 1
diff --git a/planetstack/core/fixtures/demo_data.json b/planetstack/core/fixtures/demo_data.json
index 4ae8ea5..400148f 100644
--- a/planetstack/core/fixtures/demo_data.json
+++ b/planetstack/core/fixtures/demo_data.json
@@ -9603,6 +9603,187 @@
     }
 },
 {
+    "pk": 1, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T20:38:23.122Z", 
+        "name": "m1.tiny", 
+        "created": "2014-09-02T20:38:23.122Z", 
+        "deleted": false, 
+        "description": "openstack tiny instance", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5
+        ], 
+        "default": false, 
+        "flavor": "m1.tiny", 
+        "backend_status": "Provisioning in progress", 
+        "order": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T20:59:40.518Z", 
+        "name": "m1.small", 
+        "created": "2014-09-02T20:59:40.518Z", 
+        "deleted": false, 
+        "description": "small openstack instance", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5, 
+            11
+        ], 
+        "default": true, 
+        "flavor": "m1.small", 
+        "backend_status": "Provisioning in progress", 
+        "order": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T21:00:28.795Z", 
+        "name": "m1.medium", 
+        "created": "2014-09-02T21:00:28.795Z", 
+        "deleted": false, 
+        "description": "medium openstack flavor", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5, 
+            11
+        ], 
+        "default": false, 
+        "flavor": "m1.medium", 
+        "backend_status": "Provisioning in progress", 
+        "order": 2, 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T21:00:57.360Z", 
+        "name": "m1.large", 
+        "created": "2014-09-02T21:00:49.945Z", 
+        "deleted": false, 
+        "description": "large openstack flavor", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5, 
+            11
+        ], 
+        "default": false, 
+        "flavor": "m1.large", 
+        "backend_status": "Provisioning in progress", 
+        "order": 3, 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T21:01:15.285Z", 
+        "name": "m1.xlarge", 
+        "created": "2014-09-02T21:01:15.285Z", 
+        "deleted": false, 
+        "description": "extra large openstack flavor", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5, 
+            11
+        ], 
+        "default": false, 
+        "flavor": "m1.xlarge", 
+        "backend_status": "Provisioning in progress", 
+        "order": 4, 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-03T00:25:30.120Z", 
+        "name": "m3.medium", 
+        "created": "2014-09-03T00:25:30.120Z", 
+        "deleted": false, 
+        "description": "ec2 flavor m3.medium", 
+        "deployments": [
+            11
+        ], 
+        "default": false, 
+        "flavor": "m3.medium", 
+        "backend_status": "Provisioning in progress", 
+        "order": 33, 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-03T00:25:50.419Z", 
+        "name": "m3.large", 
+        "created": "2014-09-03T00:25:50.419Z", 
+        "deleted": false, 
+        "description": "ec2 flavor m3.large", 
+        "deployments": [
+            11
+        ], 
+        "default": false, 
+        "flavor": "m3.large", 
+        "backend_status": "Provisioning in progress", 
+        "order": 34, 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-03T00:26:11.770Z", 
+        "name": "m3.2xlarge", 
+        "created": "2014-09-03T00:26:11.770Z", 
+        "deleted": false, 
+        "description": "ec2 flavor m3.2xlarge", 
+        "deployments": [
+            11
+        ], 
+        "default": false, 
+        "flavor": "m3.2xlarge", 
+        "backend_status": "Provisioning in progress", 
+        "order": 35, 
+        "enacted": null
+    }
+},
+{
     "pk": 40, 
     "model": "core.sliver", 
     "fields": {
diff --git a/planetstack/core/fixtures/initial_data.json b/planetstack/core/fixtures/initial_data.json
index d51a35b..ad86b97 100644
--- a/planetstack/core/fixtures/initial_data.json
+++ b/planetstack/core/fixtures/initial_data.json
@@ -8025,6 +8025,180 @@
     }
 },
 {
+    "pk": 1, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T20:38:23.122Z", 
+        "name": "m1.tiny", 
+        "created": "2014-09-02T20:38:23.122Z", 
+        "deleted": false, 
+        "description": "openstack tiny instance", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5
+        ], 
+        "default": false, 
+        "flavor": "m1.tiny", 
+        "backend_status": "Provisioning in progress", 
+        "order": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T20:59:40.518Z", 
+        "name": "m1.small", 
+        "created": "2014-09-02T20:59:40.518Z", 
+        "deleted": false, 
+        "description": "small openstack instance", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5 
+        ], 
+        "default": true, 
+        "flavor": "m1.small", 
+        "backend_status": "Provisioning in progress", 
+        "order": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T21:00:28.795Z", 
+        "name": "m1.medium", 
+        "created": "2014-09-02T21:00:28.795Z", 
+        "deleted": false, 
+        "description": "medium openstack flavor", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5 
+        ], 
+        "default": false, 
+        "flavor": "m1.medium", 
+        "backend_status": "Provisioning in progress", 
+        "order": 2, 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T21:00:57.360Z", 
+        "name": "m1.large", 
+        "created": "2014-09-02T21:00:49.945Z", 
+        "deleted": false, 
+        "description": "large openstack flavor", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5 
+        ], 
+        "default": false, 
+        "flavor": "m1.large", 
+        "backend_status": "Provisioning in progress", 
+        "order": 3, 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T21:01:15.285Z", 
+        "name": "m1.xlarge", 
+        "created": "2014-09-02T21:01:15.285Z", 
+        "deleted": false, 
+        "description": "extra large openstack flavor", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5 
+        ], 
+        "default": false, 
+        "flavor": "m1.xlarge", 
+        "backend_status": "Provisioning in progress", 
+        "order": 4, 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-03T00:25:30.120Z", 
+        "name": "m3.medium", 
+        "created": "2014-09-03T00:25:30.120Z", 
+        "deleted": false, 
+        "description": "ec2 flavor m3.medium", 
+        "deployments": [
+        ], 
+        "default": false, 
+        "flavor": "m3.medium", 
+        "backend_status": "Provisioning in progress", 
+        "order": 33, 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-03T00:25:50.419Z", 
+        "name": "m3.large", 
+        "created": "2014-09-03T00:25:50.419Z", 
+        "deleted": false, 
+        "description": "ec2 flavor m3.large", 
+        "deployments": [
+        ], 
+        "default": false, 
+        "flavor": "m3.large", 
+        "backend_status": "Provisioning in progress", 
+        "order": 34, 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-03T00:26:11.770Z", 
+        "name": "m3.2xlarge", 
+        "created": "2014-09-03T00:26:11.770Z", 
+        "deleted": false, 
+        "description": "ec2 flavor m3.2xlarge", 
+        "deployments": [
+        ], 
+        "default": false, 
+        "flavor": "m3.2xlarge", 
+        "backend_status": "Provisioning in progress", 
+        "order": 35, 
+        "enacted": null
+    }
+},
+{
     "pk": 40, 
     "model": "core.sliver", 
     "fields": {
diff --git a/planetstack/core/migrations/0001_initial.py b/planetstack/core/migrations/0001_initial.py
new file mode 100644
index 0000000..58c0dc3
--- /dev/null
+++ b/planetstack/core/migrations/0001_initial.py
@@ -0,0 +1,1154 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import datetime
+import timezones.fields
+import core.models.sliver
+import geoposition.fields
+import encrypted_fields.fields
+import core.models.serviceclass
+import django.utils.timezone
+from django.conf import settings
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='User',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('password', models.CharField(max_length=128, verbose_name='password')),
+                ('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')),
+                ('email', models.EmailField(unique=True, max_length=255, verbose_name=b'email address', db_index=True)),
+                ('username', models.CharField(default=b'Something', max_length=255)),
+                ('firstname', models.CharField(help_text=b"person's given name", max_length=200)),
+                ('lastname', models.CharField(help_text=b"person's surname", max_length=200)),
+                ('phone', models.CharField(help_text=b'phone number contact', max_length=100, null=True, blank=True)),
+                ('user_url', models.URLField(null=True, blank=True)),
+                ('public_key', models.TextField(help_text=b'Public key string', max_length=1024, null=True, blank=True)),
+                ('is_active', models.BooleanField(default=True)),
+                ('is_admin', models.BooleanField(default=True)),
+                ('is_staff', models.BooleanField(default=True)),
+                ('is_readonly', models.BooleanField(default=False)),
+                ('created', models.DateTimeField(auto_now_add=True)),
+                ('updated', models.DateTimeField(auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('timezone', timezones.fields.TimeZoneField(default=b'America/New_York', max_length=100, choices=[(b'Pacific/Midway', b'(GMT-1100) Pacific/Midway'), (b'Pacific/Niue', b'(GMT-1100) Pacific/Niue'), (b'Pacific/Pago_Pago', b'(GMT-1100) Pacific/Pago_Pago'), (b'Pacific/Honolulu', b'(GMT-1000) Pacific/Honolulu'), (b'Pacific/Johnston', b'(GMT-1000) Pacific/Johnston'), (b'Pacific/Rarotonga', b'(GMT-1000) Pacific/Rarotonga'), (b'Pacific/Tahiti', b'(GMT-1000) Pacific/Tahiti'), (b'US/Hawaii', b'(GMT-1000) US/Hawaii'), (b'Pacific/Marquesas', b'(GMT-0930) Pacific/Marquesas'), (b'America/Adak', b'(GMT-0900) America/Adak'), (b'Pacific/Gambier', b'(GMT-0900) Pacific/Gambier'), (b'America/Anchorage', b'(GMT-0800) America/Anchorage'), (b'America/Juneau', b'(GMT-0800) America/Juneau'), (b'America/Metlakatla', b'(GMT-0800) America/Metlakatla'), (b'America/Nome', b'(GMT-0800) America/Nome'), (b'America/Sitka', b'(GMT-0800) America/Sitka'), (b'America/Yakutat', b'(GMT-0800) America/Yakutat'), (b'Pacific/Pitcairn', b'(GMT-0800) Pacific/Pitcairn'), (b'US/Alaska', b'(GMT-0800) US/Alaska'), (b'America/Creston', b'(GMT-0700) America/Creston'), (b'America/Dawson', b'(GMT-0700) America/Dawson'), (b'America/Dawson_Creek', b'(GMT-0700) America/Dawson_Creek'), (b'America/Hermosillo', b'(GMT-0700) America/Hermosillo'), (b'America/Los_Angeles', b'(GMT-0700) America/Los_Angeles'), (b'America/Phoenix', b'(GMT-0700) America/Phoenix'), (b'America/Santa_Isabel', b'(GMT-0700) America/Santa_Isabel'), (b'America/Tijuana', b'(GMT-0700) America/Tijuana'), (b'America/Vancouver', b'(GMT-0700) America/Vancouver'), (b'America/Whitehorse', b'(GMT-0700) America/Whitehorse'), (b'Canada/Pacific', b'(GMT-0700) Canada/Pacific'), (b'US/Arizona', b'(GMT-0700) US/Arizona'), (b'US/Pacific', b'(GMT-0700) US/Pacific'), (b'America/Belize', b'(GMT-0600) America/Belize'), (b'America/Boise', b'(GMT-0600) America/Boise'), (b'America/Cambridge_Bay', b'(GMT-0600) America/Cambridge_Bay'), (b'America/Chihuahua', b'(GMT-0600) America/Chihuahua'), (b'America/Costa_Rica', b'(GMT-0600) America/Costa_Rica'), (b'America/Denver', b'(GMT-0600) America/Denver'), (b'America/Edmonton', b'(GMT-0600) America/Edmonton'), (b'America/El_Salvador', b'(GMT-0600) America/El_Salvador'), (b'America/Guatemala', b'(GMT-0600) America/Guatemala'), (b'America/Inuvik', b'(GMT-0600) America/Inuvik'), (b'America/Managua', b'(GMT-0600) America/Managua'), (b'America/Mazatlan', b'(GMT-0600) America/Mazatlan'), (b'America/Ojinaga', b'(GMT-0600) America/Ojinaga'), (b'America/Regina', b'(GMT-0600) America/Regina'), (b'America/Swift_Current', b'(GMT-0600) America/Swift_Current'), (b'America/Tegucigalpa', b'(GMT-0600) America/Tegucigalpa'), (b'America/Yellowknife', b'(GMT-0600) America/Yellowknife'), (b'Canada/Mountain', b'(GMT-0600) Canada/Mountain'), (b'Pacific/Galapagos', b'(GMT-0600) Pacific/Galapagos'), (b'US/Mountain', b'(GMT-0600) US/Mountain'), (b'America/Atikokan', b'(GMT-0500) America/Atikokan'), (b'America/Bahia_Banderas', b'(GMT-0500) America/Bahia_Banderas'), (b'America/Bogota', b'(GMT-0500) America/Bogota'), (b'America/Cancun', b'(GMT-0500) America/Cancun'), (b'America/Cayman', b'(GMT-0500) America/Cayman'), (b'America/Chicago', b'(GMT-0500) America/Chicago'), (b'America/Eirunepe', b'(GMT-0500) America/Eirunepe'), (b'America/Guayaquil', b'(GMT-0500) America/Guayaquil'), (b'America/Indiana/Knox', b'(GMT-0500) America/Indiana/Knox'), (b'America/Indiana/Tell_City', b'(GMT-0500) America/Indiana/Tell_City'), (b'America/Jamaica', b'(GMT-0500) America/Jamaica'), (b'America/Lima', b'(GMT-0500) America/Lima'), (b'America/Matamoros', b'(GMT-0500) America/Matamoros'), (b'America/Menominee', b'(GMT-0500) America/Menominee'), (b'America/Merida', b'(GMT-0500) America/Merida'), (b'America/Mexico_City', b'(GMT-0500) America/Mexico_City'), (b'America/Monterrey', b'(GMT-0500) America/Monterrey'), (b'America/North_Dakota/Beulah', b'(GMT-0500) America/North_Dakota/Beulah'), (b'America/North_Dakota/Center', b'(GMT-0500) America/North_Dakota/Center'), (b'America/North_Dakota/New_Salem', b'(GMT-0500) America/North_Dakota/New_Salem'), (b'America/Panama', b'(GMT-0500) America/Panama'), (b'America/Rainy_River', b'(GMT-0500) America/Rainy_River'), (b'America/Rankin_Inlet', b'(GMT-0500) America/Rankin_Inlet'), (b'America/Resolute', b'(GMT-0500) America/Resolute'), (b'America/Rio_Branco', b'(GMT-0500) America/Rio_Branco'), (b'America/Winnipeg', b'(GMT-0500) America/Winnipeg'), (b'Canada/Central', b'(GMT-0500) Canada/Central'), (b'Pacific/Easter', b'(GMT-0500) Pacific/Easter'), (b'US/Central', b'(GMT-0500) US/Central'), (b'America/Caracas', b'(GMT-0430) America/Caracas'), (b'America/Anguilla', b'(GMT-0400) America/Anguilla'), (b'America/Antigua', b'(GMT-0400) America/Antigua'), (b'America/Aruba', b'(GMT-0400) America/Aruba'), (b'America/Asuncion', b'(GMT-0400) America/Asuncion'), (b'America/Barbados', b'(GMT-0400) America/Barbados'), (b'America/Blanc-Sablon', b'(GMT-0400) America/Blanc-Sablon'), (b'America/Boa_Vista', b'(GMT-0400) America/Boa_Vista'), (b'America/Campo_Grande', b'(GMT-0400) America/Campo_Grande'), (b'America/Cuiaba', b'(GMT-0400) America/Cuiaba'), (b'America/Curacao', b'(GMT-0400) America/Curacao'), (b'America/Detroit', b'(GMT-0400) America/Detroit'), (b'America/Dominica', b'(GMT-0400) America/Dominica'), (b'America/Grand_Turk', b'(GMT-0400) America/Grand_Turk'), (b'America/Grenada', b'(GMT-0400) America/Grenada'), (b'America/Guadeloupe', b'(GMT-0400) America/Guadeloupe'), (b'America/Guyana', b'(GMT-0400) America/Guyana'), (b'America/Havana', b'(GMT-0400) America/Havana'), (b'America/Indiana/Indianapolis', b'(GMT-0400) America/Indiana/Indianapolis'), (b'America/Indiana/Marengo', b'(GMT-0400) America/Indiana/Marengo'), (b'America/Indiana/Petersburg', b'(GMT-0400) America/Indiana/Petersburg'), (b'America/Indiana/Vevay', b'(GMT-0400) America/Indiana/Vevay'), (b'America/Indiana/Vincennes', b'(GMT-0400) America/Indiana/Vincennes'), (b'America/Indiana/Winamac', b'(GMT-0400) America/Indiana/Winamac'), (b'America/Iqaluit', b'(GMT-0400) America/Iqaluit'), (b'America/Kentucky/Louisville', b'(GMT-0400) America/Kentucky/Louisville'), (b'America/Kentucky/Monticello', b'(GMT-0400) America/Kentucky/Monticello'), (b'America/Kralendijk', b'(GMT-0400) America/Kralendijk'), (b'America/La_Paz', b'(GMT-0400) America/La_Paz'), (b'America/Lower_Princes', b'(GMT-0400) America/Lower_Princes'), (b'America/Manaus', b'(GMT-0400) America/Manaus'), (b'America/Marigot', b'(GMT-0400) America/Marigot'), (b'America/Martinique', b'(GMT-0400) America/Martinique'), (b'America/Montreal', b'(GMT-0400) America/Montreal'), (b'America/Montserrat', b'(GMT-0400) America/Montserrat'), (b'America/Nassau', b'(GMT-0400) America/Nassau'), (b'America/New_York', b'(GMT-0400) America/New_York'), (b'America/Nipigon', b'(GMT-0400) America/Nipigon'), (b'America/Pangnirtung', b'(GMT-0400) America/Pangnirtung'), (b'America/Port-au-Prince', b'(GMT-0400) America/Port-au-Prince'), (b'America/Port_of_Spain', b'(GMT-0400) America/Port_of_Spain'), (b'America/Porto_Velho', b'(GMT-0400) America/Porto_Velho'), (b'America/Puerto_Rico', b'(GMT-0400) America/Puerto_Rico'), (b'America/Santo_Domingo', b'(GMT-0400) America/Santo_Domingo'), (b'America/St_Barthelemy', b'(GMT-0400) America/St_Barthelemy'), (b'America/St_Kitts', b'(GMT-0400) America/St_Kitts'), (b'America/St_Lucia', b'(GMT-0400) America/St_Lucia'), (b'America/St_Thomas', b'(GMT-0400) America/St_Thomas'), (b'America/St_Vincent', b'(GMT-0400) America/St_Vincent'), (b'America/Thunder_Bay', b'(GMT-0400) America/Thunder_Bay'), (b'America/Toronto', b'(GMT-0400) America/Toronto'), (b'America/Tortola', b'(GMT-0400) America/Tortola'), (b'Canada/Eastern', b'(GMT-0400) Canada/Eastern'), (b'US/Eastern', b'(GMT-0400) US/Eastern'), (b'America/Araguaina', b'(GMT-0300) America/Araguaina'), (b'America/Argentina/Buenos_Aires', b'(GMT-0300) America/Argentina/Buenos_Aires'), (b'America/Argentina/Catamarca', b'(GMT-0300) America/Argentina/Catamarca'), (b'America/Argentina/Cordoba', b'(GMT-0300) America/Argentina/Cordoba'), (b'America/Argentina/Jujuy', b'(GMT-0300) America/Argentina/Jujuy'), (b'America/Argentina/La_Rioja', b'(GMT-0300) America/Argentina/La_Rioja'), (b'America/Argentina/Mendoza', b'(GMT-0300) America/Argentina/Mendoza'), (b'America/Argentina/Rio_Gallegos', b'(GMT-0300) America/Argentina/Rio_Gallegos'), (b'America/Argentina/Salta', b'(GMT-0300) America/Argentina/Salta'), (b'America/Argentina/San_Juan', b'(GMT-0300) America/Argentina/San_Juan'), (b'America/Argentina/San_Luis', b'(GMT-0300) America/Argentina/San_Luis'), (b'America/Argentina/Tucuman', b'(GMT-0300) America/Argentina/Tucuman'), (b'America/Argentina/Ushuaia', b'(GMT-0300) America/Argentina/Ushuaia'), (b'America/Bahia', b'(GMT-0300) America/Bahia'), (b'America/Belem', b'(GMT-0300) America/Belem'), (b'America/Cayenne', b'(GMT-0300) America/Cayenne'), (b'America/Fortaleza', b'(GMT-0300) America/Fortaleza'), (b'America/Glace_Bay', b'(GMT-0300) America/Glace_Bay'), (b'America/Goose_Bay', b'(GMT-0300) America/Goose_Bay'), (b'America/Halifax', b'(GMT-0300) America/Halifax'), (b'America/Maceio', b'(GMT-0300) America/Maceio'), (b'America/Moncton', b'(GMT-0300) America/Moncton'), (b'America/Montevideo', b'(GMT-0300) America/Montevideo'), (b'America/Paramaribo', b'(GMT-0300) America/Paramaribo'), (b'America/Recife', b'(GMT-0300) America/Recife'), (b'America/Santarem', b'(GMT-0300) America/Santarem'), (b'America/Santiago', b'(GMT-0300) America/Santiago'), (b'America/Sao_Paulo', b'(GMT-0300) America/Sao_Paulo'), (b'America/Thule', b'(GMT-0300) America/Thule'), (b'Antarctica/Palmer', b'(GMT-0300) Antarctica/Palmer'), (b'Antarctica/Rothera', b'(GMT-0300) Antarctica/Rothera'), (b'Atlantic/Bermuda', b'(GMT-0300) Atlantic/Bermuda'), (b'Atlantic/Stanley', b'(GMT-0300) Atlantic/Stanley'), (b'Canada/Atlantic', b'(GMT-0300) Canada/Atlantic'), (b'America/St_Johns', b'(GMT-0230) America/St_Johns'), (b'Canada/Newfoundland', b'(GMT-0230) Canada/Newfoundland'), (b'America/Godthab', b'(GMT-0200) America/Godthab'), (b'America/Miquelon', b'(GMT-0200) America/Miquelon'), (b'America/Noronha', b'(GMT-0200) America/Noronha'), (b'Atlantic/South_Georgia', b'(GMT-0200) Atlantic/South_Georgia'), (b'Atlantic/Cape_Verde', b'(GMT-0100) Atlantic/Cape_Verde'), (b'Africa/Abidjan', b'(GMT+0000) Africa/Abidjan'), (b'Africa/Accra', b'(GMT+0000) Africa/Accra'), (b'Africa/Bamako', b'(GMT+0000) Africa/Bamako'), (b'Africa/Banjul', b'(GMT+0000) Africa/Banjul'), (b'Africa/Bissau', b'(GMT+0000) Africa/Bissau'), (b'Africa/Conakry', b'(GMT+0000) Africa/Conakry'), (b'Africa/Dakar', b'(GMT+0000) Africa/Dakar'), (b'Africa/Freetown', b'(GMT+0000) Africa/Freetown'), (b'Africa/Lome', b'(GMT+0000) Africa/Lome'), (b'Africa/Monrovia', b'(GMT+0000) Africa/Monrovia'), (b'Africa/Nouakchott', b'(GMT+0000) Africa/Nouakchott'), (b'Africa/Ouagadougou', b'(GMT+0000) Africa/Ouagadougou'), (b'Africa/Sao_Tome', b'(GMT+0000) Africa/Sao_Tome'), (b'America/Danmarkshavn', b'(GMT+0000) America/Danmarkshavn'), (b'America/Scoresbysund', b'(GMT+0000) America/Scoresbysund'), (b'Atlantic/Azores', b'(GMT+0000) Atlantic/Azores'), (b'Atlantic/Reykjavik', b'(GMT+0000) Atlantic/Reykjavik'), (b'Atlantic/St_Helena', b'(GMT+0000) Atlantic/St_Helena'), (b'GMT', b'(GMT+0000) GMT'), (b'UTC', b'(GMT+0000) UTC'), (b'Africa/Algiers', b'(GMT+0100) Africa/Algiers'), (b'Africa/Bangui', b'(GMT+0100) Africa/Bangui'), (b'Africa/Brazzaville', b'(GMT+0100) Africa/Brazzaville'), (b'Africa/Casablanca', b'(GMT+0100) Africa/Casablanca'), (b'Africa/Douala', b'(GMT+0100) Africa/Douala'), (b'Africa/El_Aaiun', b'(GMT+0100) Africa/El_Aaiun'), (b'Africa/Kinshasa', b'(GMT+0100) Africa/Kinshasa'), (b'Africa/Lagos', b'(GMT+0100) Africa/Lagos'), (b'Africa/Libreville', b'(GMT+0100) Africa/Libreville'), (b'Africa/Luanda', b'(GMT+0100) Africa/Luanda'), (b'Africa/Malabo', b'(GMT+0100) Africa/Malabo'), (b'Africa/Ndjamena', b'(GMT+0100) Africa/Ndjamena'), (b'Africa/Niamey', b'(GMT+0100) Africa/Niamey'), (b'Africa/Porto-Novo', b'(GMT+0100) Africa/Porto-Novo'), (b'Africa/Tunis', b'(GMT+0100) Africa/Tunis'), (b'Atlantic/Canary', b'(GMT+0100) Atlantic/Canary'), (b'Atlantic/Faroe', b'(GMT+0100) Atlantic/Faroe'), (b'Atlantic/Madeira', b'(GMT+0100) Atlantic/Madeira'), (b'Europe/Dublin', b'(GMT+0100) Europe/Dublin'), (b'Europe/Guernsey', b'(GMT+0100) Europe/Guernsey'), (b'Europe/Isle_of_Man', b'(GMT+0100) Europe/Isle_of_Man'), (b'Europe/Jersey', b'(GMT+0100) Europe/Jersey'), (b'Europe/Lisbon', b'(GMT+0100) Europe/Lisbon'), (b'Europe/London', b'(GMT+0100) Europe/London'), (b'Africa/Blantyre', b'(GMT+0200) Africa/Blantyre'), (b'Africa/Bujumbura', b'(GMT+0200) Africa/Bujumbura'), (b'Africa/Ceuta', b'(GMT+0200) Africa/Ceuta'), (b'Africa/Gaborone', b'(GMT+0200) Africa/Gaborone'), (b'Africa/Harare', b'(GMT+0200) Africa/Harare'), (b'Africa/Johannesburg', b'(GMT+0200) Africa/Johannesburg'), (b'Africa/Kigali', b'(GMT+0200) Africa/Kigali'), (b'Africa/Lubumbashi', b'(GMT+0200) Africa/Lubumbashi'), (b'Africa/Lusaka', b'(GMT+0200) Africa/Lusaka'), (b'Africa/Maputo', b'(GMT+0200) Africa/Maputo'), (b'Africa/Maseru', b'(GMT+0200) Africa/Maseru'), (b'Africa/Mbabane', b'(GMT+0200) Africa/Mbabane'), (b'Africa/Tripoli', b'(GMT+0200) Africa/Tripoli'), (b'Africa/Windhoek', b'(GMT+0200) Africa/Windhoek'), (b'Antarctica/Troll', b'(GMT+0200) Antarctica/Troll'), (b'Arctic/Longyearbyen', b'(GMT+0200) Arctic/Longyearbyen'), (b'Europe/Amsterdam', b'(GMT+0200) Europe/Amsterdam'), (b'Europe/Andorra', b'(GMT+0200) Europe/Andorra'), (b'Europe/Belgrade', b'(GMT+0200) Europe/Belgrade'), (b'Europe/Berlin', b'(GMT+0200) Europe/Berlin'), (b'Europe/Bratislava', b'(GMT+0200) Europe/Bratislava'), (b'Europe/Brussels', b'(GMT+0200) Europe/Brussels'), (b'Europe/Budapest', b'(GMT+0200) Europe/Budapest'), (b'Europe/Busingen', b'(GMT+0200) Europe/Busingen'), (b'Europe/Copenhagen', b'(GMT+0200) Europe/Copenhagen'), (b'Europe/Gibraltar', b'(GMT+0200) Europe/Gibraltar'), (b'Europe/Ljubljana', b'(GMT+0200) Europe/Ljubljana'), (b'Europe/Luxembourg', b'(GMT+0200) Europe/Luxembourg'), (b'Europe/Madrid', b'(GMT+0200) Europe/Madrid'), (b'Europe/Malta', b'(GMT+0200) Europe/Malta'), (b'Europe/Monaco', b'(GMT+0200) Europe/Monaco'), (b'Europe/Oslo', b'(GMT+0200) Europe/Oslo'), (b'Europe/Paris', b'(GMT+0200) Europe/Paris'), (b'Europe/Podgorica', b'(GMT+0200) Europe/Podgorica'), (b'Europe/Prague', b'(GMT+0200) Europe/Prague'), (b'Europe/Rome', b'(GMT+0200) Europe/Rome'), (b'Europe/San_Marino', b'(GMT+0200) Europe/San_Marino'), (b'Europe/Sarajevo', b'(GMT+0200) Europe/Sarajevo'), (b'Europe/Skopje', b'(GMT+0200) Europe/Skopje'), (b'Europe/Stockholm', b'(GMT+0200) Europe/Stockholm'), (b'Europe/Tirane', b'(GMT+0200) Europe/Tirane'), (b'Europe/Vaduz', b'(GMT+0200) Europe/Vaduz'), (b'Europe/Vatican', b'(GMT+0200) Europe/Vatican'), (b'Europe/Vienna', b'(GMT+0200) Europe/Vienna'), (b'Europe/Warsaw', b'(GMT+0200) Europe/Warsaw'), (b'Europe/Zagreb', b'(GMT+0200) Europe/Zagreb'), (b'Europe/Zurich', b'(GMT+0200) Europe/Zurich'), (b'Africa/Addis_Ababa', b'(GMT+0300) Africa/Addis_Ababa'), (b'Africa/Asmara', b'(GMT+0300) Africa/Asmara'), (b'Africa/Cairo', b'(GMT+0300) Africa/Cairo'), (b'Africa/Dar_es_Salaam', b'(GMT+0300) Africa/Dar_es_Salaam'), (b'Africa/Djibouti', b'(GMT+0300) Africa/Djibouti'), (b'Africa/Juba', b'(GMT+0300) Africa/Juba'), (b'Africa/Kampala', b'(GMT+0300) Africa/Kampala'), (b'Africa/Khartoum', b'(GMT+0300) Africa/Khartoum'), (b'Africa/Mogadishu', b'(GMT+0300) Africa/Mogadishu'), (b'Africa/Nairobi', b'(GMT+0300) Africa/Nairobi'), (b'Antarctica/Syowa', b'(GMT+0300) Antarctica/Syowa'), (b'Asia/Aden', b'(GMT+0300) Asia/Aden'), (b'Asia/Amman', b'(GMT+0300) Asia/Amman'), (b'Asia/Baghdad', b'(GMT+0300) Asia/Baghdad'), (b'Asia/Bahrain', b'(GMT+0300) Asia/Bahrain'), (b'Asia/Beirut', b'(GMT+0300) Asia/Beirut'), (b'Asia/Damascus', b'(GMT+0300) Asia/Damascus'), (b'Asia/Gaza', b'(GMT+0300) Asia/Gaza'), (b'Asia/Hebron', b'(GMT+0300) Asia/Hebron'), (b'Asia/Jerusalem', b'(GMT+0300) Asia/Jerusalem'), (b'Asia/Kuwait', b'(GMT+0300) Asia/Kuwait'), (b'Asia/Nicosia', b'(GMT+0300) Asia/Nicosia'), (b'Asia/Qatar', b'(GMT+0300) Asia/Qatar'), (b'Asia/Riyadh', b'(GMT+0300) Asia/Riyadh'), (b'Europe/Athens', b'(GMT+0300) Europe/Athens'), (b'Europe/Bucharest', b'(GMT+0300) Europe/Bucharest'), (b'Europe/Chisinau', b'(GMT+0300) Europe/Chisinau'), (b'Europe/Helsinki', b'(GMT+0300) Europe/Helsinki'), (b'Europe/Istanbul', b'(GMT+0300) Europe/Istanbul'), (b'Europe/Kaliningrad', b'(GMT+0300) Europe/Kaliningrad'), (b'Europe/Kiev', b'(GMT+0300) Europe/Kiev'), (b'Europe/Mariehamn', b'(GMT+0300) Europe/Mariehamn'), (b'Europe/Minsk', b'(GMT+0300) Europe/Minsk'), (b'Europe/Riga', b'(GMT+0300) Europe/Riga'), (b'Europe/Sofia', b'(GMT+0300) Europe/Sofia'), (b'Europe/Tallinn', b'(GMT+0300) Europe/Tallinn'), (b'Europe/Uzhgorod', b'(GMT+0300) Europe/Uzhgorod'), (b'Europe/Vilnius', b'(GMT+0300) Europe/Vilnius'), (b'Europe/Zaporozhye', b'(GMT+0300) Europe/Zaporozhye'), (b'Indian/Antananarivo', b'(GMT+0300) Indian/Antananarivo'), (b'Indian/Comoro', b'(GMT+0300) Indian/Comoro'), (b'Indian/Mayotte', b'(GMT+0300) Indian/Mayotte'), (b'Asia/Dubai', b'(GMT+0400) Asia/Dubai'), (b'Asia/Muscat', b'(GMT+0400) Asia/Muscat'), (b'Asia/Tbilisi', b'(GMT+0400) Asia/Tbilisi'), (b'Asia/Yerevan', b'(GMT+0400) Asia/Yerevan'), (b'Europe/Moscow', b'(GMT+0400) Europe/Moscow'), (b'Europe/Samara', b'(GMT+0400) Europe/Samara'), (b'Europe/Simferopol', b'(GMT+0400) Europe/Simferopol'), (b'Europe/Volgograd', b'(GMT+0400) Europe/Volgograd'), (b'Indian/Mahe', b'(GMT+0400) Indian/Mahe'), (b'Indian/Mauritius', b'(GMT+0400) Indian/Mauritius'), (b'Indian/Reunion', b'(GMT+0400) Indian/Reunion'), (b'Asia/Kabul', b'(GMT+0430) Asia/Kabul'), (b'Asia/Tehran', b'(GMT+0430) Asia/Tehran'), (b'Antarctica/Mawson', b'(GMT+0500) Antarctica/Mawson'), (b'Asia/Aqtau', b'(GMT+0500) Asia/Aqtau'), (b'Asia/Aqtobe', b'(GMT+0500) Asia/Aqtobe'), (b'Asia/Ashgabat', b'(GMT+0500) Asia/Ashgabat'), (b'Asia/Baku', b'(GMT+0500) Asia/Baku'), (b'Asia/Dushanbe', b'(GMT+0500) Asia/Dushanbe'), (b'Asia/Karachi', b'(GMT+0500) Asia/Karachi'), (b'Asia/Oral', b'(GMT+0500) Asia/Oral'), (b'Asia/Samarkand', b'(GMT+0500) Asia/Samarkand'), (b'Asia/Tashkent', b'(GMT+0500) Asia/Tashkent'), (b'Indian/Kerguelen', b'(GMT+0500) Indian/Kerguelen'), (b'Indian/Maldives', b'(GMT+0500) Indian/Maldives'), (b'Asia/Colombo', b'(GMT+0530) Asia/Colombo'), (b'Asia/Kolkata', b'(GMT+0530) Asia/Kolkata'), (b'Asia/Kathmandu', b'(GMT+0545) Asia/Kathmandu'), (b'Antarctica/Vostok', b'(GMT+0600) Antarctica/Vostok'), (b'Asia/Almaty', b'(GMT+0600) Asia/Almaty'), (b'Asia/Bishkek', b'(GMT+0600) Asia/Bishkek'), (b'Asia/Dhaka', b'(GMT+0600) Asia/Dhaka'), (b'Asia/Qyzylorda', b'(GMT+0600) Asia/Qyzylorda'), (b'Asia/Thimphu', b'(GMT+0600) Asia/Thimphu'), (b'Asia/Urumqi', b'(GMT+0600) Asia/Urumqi'), (b'Asia/Yekaterinburg', b'(GMT+0600) Asia/Yekaterinburg'), (b'Indian/Chagos', b'(GMT+0600) Indian/Chagos'), (b'Asia/Rangoon', b'(GMT+0630) Asia/Rangoon'), (b'Indian/Cocos', b'(GMT+0630) Indian/Cocos'), (b'Antarctica/Davis', b'(GMT+0700) Antarctica/Davis'), (b'Asia/Bangkok', b'(GMT+0700) Asia/Bangkok'), (b'Asia/Ho_Chi_Minh', b'(GMT+0700) Asia/Ho_Chi_Minh'), (b'Asia/Hovd', b'(GMT+0700) Asia/Hovd'), (b'Asia/Jakarta', b'(GMT+0700) Asia/Jakarta'), (b'Asia/Novokuznetsk', b'(GMT+0700) Asia/Novokuznetsk'), (b'Asia/Novosibirsk', b'(GMT+0700) Asia/Novosibirsk'), (b'Asia/Omsk', b'(GMT+0700) Asia/Omsk'), (b'Asia/Phnom_Penh', b'(GMT+0700) Asia/Phnom_Penh'), (b'Asia/Pontianak', b'(GMT+0700) Asia/Pontianak'), (b'Asia/Vientiane', b'(GMT+0700) Asia/Vientiane'), (b'Indian/Christmas', b'(GMT+0700) Indian/Christmas'), (b'Antarctica/Casey', b'(GMT+0800) Antarctica/Casey'), (b'Asia/Brunei', b'(GMT+0800) Asia/Brunei'), (b'Asia/Choibalsan', b'(GMT+0800) Asia/Choibalsan'), (b'Asia/Hong_Kong', b'(GMT+0800) Asia/Hong_Kong'), (b'Asia/Krasnoyarsk', b'(GMT+0800) Asia/Krasnoyarsk'), (b'Asia/Kuala_Lumpur', b'(GMT+0800) Asia/Kuala_Lumpur'), (b'Asia/Kuching', b'(GMT+0800) Asia/Kuching'), (b'Asia/Macau', b'(GMT+0800) Asia/Macau'), (b'Asia/Makassar', b'(GMT+0800) Asia/Makassar'), (b'Asia/Manila', b'(GMT+0800) Asia/Manila'), (b'Asia/Shanghai', b'(GMT+0800) Asia/Shanghai'), (b'Asia/Singapore', b'(GMT+0800) Asia/Singapore'), (b'Asia/Taipei', b'(GMT+0800) Asia/Taipei'), (b'Asia/Ulaanbaatar', b'(GMT+0800) Asia/Ulaanbaatar'), (b'Australia/Perth', b'(GMT+0800) Australia/Perth'), (b'Australia/Eucla', b'(GMT+0845) Australia/Eucla'), (b'Asia/Dili', b'(GMT+0900) Asia/Dili'), (b'Asia/Irkutsk', b'(GMT+0900) Asia/Irkutsk'), (b'Asia/Jayapura', b'(GMT+0900) Asia/Jayapura'), (b'Asia/Pyongyang', b'(GMT+0900) Asia/Pyongyang'), (b'Asia/Seoul', b'(GMT+0900) Asia/Seoul'), (b'Asia/Tokyo', b'(GMT+0900) Asia/Tokyo'), (b'Pacific/Palau', b'(GMT+0900) Pacific/Palau'), (b'Australia/Adelaide', b'(GMT+0930) Australia/Adelaide'), (b'Australia/Broken_Hill', b'(GMT+0930) Australia/Broken_Hill'), (b'Australia/Darwin', b'(GMT+0930) Australia/Darwin'), (b'Antarctica/DumontDUrville', b'(GMT+1000) Antarctica/DumontDUrville'), (b'Asia/Chita', b'(GMT+1000) Asia/Chita'), (b'Asia/Khandyga', b'(GMT+1000) Asia/Khandyga'), (b'Asia/Yakutsk', b'(GMT+1000) Asia/Yakutsk'), (b'Australia/Brisbane', b'(GMT+1000) Australia/Brisbane'), (b'Australia/Currie', b'(GMT+1000) Australia/Currie'), (b'Australia/Hobart', b'(GMT+1000) Australia/Hobart'), (b'Australia/Lindeman', b'(GMT+1000) Australia/Lindeman'), (b'Australia/Melbourne', b'(GMT+1000) Australia/Melbourne'), (b'Australia/Sydney', b'(GMT+1000) Australia/Sydney'), (b'Pacific/Chuuk', b'(GMT+1000) Pacific/Chuuk'), (b'Pacific/Guam', b'(GMT+1000) Pacific/Guam'), (b'Pacific/Port_Moresby', b'(GMT+1000) Pacific/Port_Moresby'), (b'Pacific/Saipan', b'(GMT+1000) Pacific/Saipan'), (b'Australia/Lord_Howe', b'(GMT+1030) Australia/Lord_Howe'), (b'Antarctica/Macquarie', b'(GMT+1100) Antarctica/Macquarie'), (b'Asia/Sakhalin', b'(GMT+1100) Asia/Sakhalin'), (b'Asia/Ust-Nera', b'(GMT+1100) Asia/Ust-Nera'), (b'Asia/Vladivostok', b'(GMT+1100) Asia/Vladivostok'), (b'Pacific/Efate', b'(GMT+1100) Pacific/Efate'), (b'Pacific/Guadalcanal', b'(GMT+1100) Pacific/Guadalcanal'), (b'Pacific/Kosrae', b'(GMT+1100) Pacific/Kosrae'), (b'Pacific/Noumea', b'(GMT+1100) Pacific/Noumea'), (b'Pacific/Pohnpei', b'(GMT+1100) Pacific/Pohnpei'), (b'Pacific/Norfolk', b'(GMT+1130) Pacific/Norfolk'), (b'Antarctica/McMurdo', b'(GMT+1200) Antarctica/McMurdo'), (b'Asia/Anadyr', b'(GMT+1200) Asia/Anadyr'), (b'Asia/Kamchatka', b'(GMT+1200) Asia/Kamchatka'), (b'Asia/Magadan', b'(GMT+1200) Asia/Magadan'), (b'Asia/Srednekolymsk', b'(GMT+1200) Asia/Srednekolymsk'), (b'Pacific/Auckland', b'(GMT+1200) Pacific/Auckland'), (b'Pacific/Fiji', b'(GMT+1200) Pacific/Fiji'), (b'Pacific/Funafuti', b'(GMT+1200) Pacific/Funafuti'), (b'Pacific/Kwajalein', b'(GMT+1200) Pacific/Kwajalein'), (b'Pacific/Majuro', b'(GMT+1200) Pacific/Majuro'), (b'Pacific/Nauru', b'(GMT+1200) Pacific/Nauru'), (b'Pacific/Tarawa', b'(GMT+1200) Pacific/Tarawa'), (b'Pacific/Wake', b'(GMT+1200) Pacific/Wake'), (b'Pacific/Wallis', b'(GMT+1200) Pacific/Wallis'), (b'Pacific/Chatham', b'(GMT+1245) Pacific/Chatham'), (b'Pacific/Apia', b'(GMT+1300) Pacific/Apia'), (b'Pacific/Enderbury', b'(GMT+1300) Pacific/Enderbury'), (b'Pacific/Fakaofo', b'(GMT+1300) Pacific/Fakaofo'), (b'Pacific/Tongatapu', b'(GMT+1300) Pacific/Tongatapu'), (b'Pacific/Kiritimati', b'(GMT+1400) Pacific/Kiritimati')])),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Account',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Charge',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('kind', models.CharField(default=b'besteffort', max_length=30, choices=[(b'besteffort', b'besteffort'), (b'reservation', b'reservation'), (b'monthlyfee', b'monthlyfee')])),
+                ('state', models.CharField(default=b'pending', max_length=30, choices=[(b'pending', b'pending'), (b'invoiced', b'invoiced')])),
+                ('date', models.DateTimeField()),
+                ('amount', models.FloatField(default=0.0)),
+                ('coreHours', models.FloatField(default=0.0)),
+                ('account', models.ForeignKey(related_name=b'charges', to='core.Account')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='DashboardView',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'Name of the View', unique=True, max_length=200)),
+                ('url', models.CharField(help_text=b'URL of Dashboard', max_length=1024)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Deployment',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'Name of the Deployment', unique=True, max_length=200)),
+                ('admin_user', models.CharField(help_text=b'Username of an admin user at this deployment', max_length=200, null=True, blank=True)),
+                ('admin_password', models.CharField(help_text=b'Password of theadmin user at this deployment', max_length=200, null=True, blank=True)),
+                ('admin_tenant', models.CharField(help_text=b'Name of the tenant the admin user belongs to', max_length=200, null=True, blank=True)),
+                ('auth_url', models.CharField(help_text=b'Auth url for the deployment', max_length=200, null=True, blank=True)),
+                ('accessControl', models.TextField(default=b'allow all', help_text=b'Access control list that specifies which sites/users may use nodes in this deployment', max_length=200)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='DeploymentCredential',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(help_text=b'The credential type, e.g. ec2', max_length=128)),
+                ('key_id', models.CharField(help_text=b'The backend id of this credential', max_length=1024)),
+                ('enc_value', encrypted_fields.fields.EncryptedCharField(help_text=b'The key value of this credential', max_length=1024)),
+                ('deployment', models.ForeignKey(related_name=b'credentials', to='core.Deployment', help_text=b'The User this credential is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='DeploymentPrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('deployment', models.ForeignKey(related_name=b'deployment_privileges', to='core.Deployment')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='DeploymentRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True, max_length=30, choices=[(b'admin', b'Admin')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Flavor',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'name of this flavor, as displayed to users', max_length=32)),
+                ('description', models.CharField(max_length=1024, null=True, blank=True)),
+                ('flavor', models.CharField(help_text=b'flavor string used to configure deployments', max_length=32)),
+                ('order', models.IntegerField(default=0, help_text=b'used to order flavors when displayed in a list')),
+                ('default', models.BooleanField(default=False, help_text=b'make this a default flavor to use when creating new instances')),
+                ('deployments', models.ManyToManyField(related_name=b'flavors', to='core.Deployment', blank=True)),
+            ],
+            options={
+                'ordering': ('order', 'name'),
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Image',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(unique=True, max_length=256)),
+                ('disk_format', models.CharField(max_length=256)),
+                ('container_format', models.CharField(max_length=256)),
+                ('path', models.CharField(help_text=b'Path to image on local disk', max_length=256, null=True, blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ImageDeployments',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('glance_image_id', models.CharField(help_text=b'Glance image id', max_length=200, null=True, blank=True)),
+                ('deployment', models.ForeignKey(to='core.Deployment')),
+                ('image', models.ForeignKey(to='core.Image')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Invoice',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('date', models.DateTimeField()),
+                ('account', models.ForeignKey(related_name=b'invoices', to='core.Account')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Network',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('subnet', models.CharField(max_length=32, blank=True)),
+                ('ports', models.CharField(max_length=1024, null=True, blank=True)),
+                ('labels', models.CharField(max_length=1024, null=True, blank=True)),
+                ('guaranteedBandwidth', models.IntegerField(default=0)),
+                ('permitAllSlices', models.BooleanField(default=False)),
+                ('network_id', models.CharField(help_text=b'Quantum network', max_length=256, null=True, blank=True)),
+                ('router_id', models.CharField(help_text=b'Quantum router id', max_length=256, null=True, blank=True)),
+                ('subnet_id', models.CharField(help_text=b'Quantum subnet id', max_length=256, null=True, blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkDeployments',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('net_id', models.CharField(help_text=b'Quantum network', max_length=256, null=True, blank=True)),
+                ('router_id', models.CharField(help_text=b'Quantum router id', max_length=256, null=True, blank=True)),
+                ('subnet_id', models.CharField(help_text=b'Quantum subnet id', max_length=256, null=True, blank=True)),
+                ('subnet', models.CharField(max_length=32, blank=True)),
+                ('deployment', models.ForeignKey(to='core.Deployment')),
+                ('network', models.ForeignKey(to='core.Network')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkParameter',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('value', models.CharField(help_text=b'The value of this parameter', max_length=1024)),
+                ('object_id', models.PositiveIntegerField()),
+                ('content_type', models.ForeignKey(to='contenttypes.ContentType')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkParameterType',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(help_text=b'The name of this parameter', max_length=128)),
+                ('description', models.CharField(max_length=1024)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkSlice',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('network', models.ForeignKey(to='core.Network')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkSliver',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('ip', models.GenericIPAddressField(help_text=b'Sliver ip address', null=True, blank=True)),
+                ('port_id', models.CharField(help_text=b'Quantum port id', max_length=256, null=True, blank=True)),
+                ('network', models.ForeignKey(to='core.Network')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkTemplate',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('description', models.CharField(max_length=1024, null=True, blank=True)),
+                ('guaranteedBandwidth', models.IntegerField(default=0)),
+                ('visibility', models.CharField(default=b'private', max_length=30, choices=[(b'public', b'public'), (b'private', b'private')])),
+                ('translation', models.CharField(default=b'none', max_length=30, choices=[(b'none', b'none'), (b'NAT', b'NAT')])),
+                ('sharedNetworkName', models.CharField(max_length=30, null=True, blank=True)),
+                ('sharedNetworkId', models.CharField(help_text=b'Quantum network', max_length=256, null=True, blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Node',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'Name of the Node', unique=True, max_length=200)),
+                ('deployment', models.ForeignKey(related_name=b'nodes', to='core.Deployment')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Payment',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('amount', models.FloatField(default=0.0)),
+                ('date', models.DateTimeField(default=django.utils.timezone.now)),
+                ('account', models.ForeignKey(related_name=b'payments', to='core.Account')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='PlanetStack',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('description', models.CharField(default=b'PlanetStack', help_text=b'Used for scoping of roles at the PlanetStack Application level', unique=True, max_length=200)),
+            ],
+            options={
+                'verbose_name_plural': 'PlanetStack',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='PlanetStackPrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('planetstack', models.ForeignKey(related_name=b'planetstack_privileges', default=1, to='core.PlanetStack')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='PlanetStackRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True, max_length=30, choices=[(b'admin', b'Admin')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Project',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'Name of Project', unique=True, max_length=200)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Reservation',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('startTime', models.DateTimeField()),
+                ('duration', models.IntegerField(default=1)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ReservedResource',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('quantity', models.IntegerField(default=1)),
+                ('reservationSet', models.ForeignKey(related_name=b'reservedResources', to='core.Reservation')),
+            ],
+            options={
+                'abstract': False,
+                'verbose_name_plural': 'Reserved Resources',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Role',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role_type', models.CharField(max_length=80, verbose_name=b'Name')),
+                ('role', models.CharField(max_length=80, null=True, verbose_name=b'Keystone role id', blank=True)),
+                ('description', models.CharField(max_length=120, verbose_name=b'Description')),
+                ('content_type', models.ForeignKey(verbose_name=b'Role Scope', to='contenttypes.ContentType')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Router',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('networks', models.ManyToManyField(related_name=b'routers', to='core.Network', blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Service',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('description', models.TextField(help_text=b'Description of Service', max_length=254, null=True, blank=True)),
+                ('enabled', models.BooleanField(default=True)),
+                ('name', models.CharField(help_text=b'Service Name', max_length=30)),
+                ('versionNumber', models.CharField(help_text=b'Version of Service Definition', max_length=30)),
+                ('published', models.BooleanField(default=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ServiceAttribute',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(help_text=b'Attribute Name', max_length=128)),
+                ('value', models.CharField(help_text=b'Attribute Value', max_length=1024)),
+                ('service', models.ForeignKey(related_name=b'serviceattributes', to='core.Service', help_text=b'The Service this attribute is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ServiceClass',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('description', models.CharField(max_length=255)),
+                ('commitment', models.IntegerField(default=365)),
+                ('membershipFee', models.IntegerField(default=0)),
+                ('membershipFeeMonths', models.IntegerField(default=12)),
+                ('upgradeRequiresApproval', models.BooleanField(default=False)),
+                ('upgradeFrom', models.ManyToManyField(related_name='upgradeFrom_rel_+', null=True, to='core.ServiceClass', blank=True)),
+            ],
+            options={
+                'abstract': False,
+                'verbose_name_plural': 'Service classes',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ServiceResource',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('maxUnitsDeployment', models.IntegerField(default=1)),
+                ('maxUnitsNode', models.IntegerField(default=1)),
+                ('maxDuration', models.IntegerField(default=1)),
+                ('bucketInRate', models.IntegerField(default=0)),
+                ('bucketMaxSize', models.IntegerField(default=0)),
+                ('cost', models.IntegerField(default=0)),
+                ('calendarReservable', models.BooleanField(default=True)),
+                ('serviceClass', models.ForeignKey(related_name=b'resources', to='core.ServiceClass')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Site',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'Name for this Site', max_length=200)),
+                ('site_url', models.URLField(help_text=b"Site's Home URL Page", max_length=512, null=True, blank=True)),
+                ('enabled', models.BooleanField(default=True, help_text=b'Status for this Site')),
+                ('location', geoposition.fields.GeopositionField(max_length=42)),
+                ('longitude', models.FloatField(null=True, blank=True)),
+                ('latitude', models.FloatField(null=True, blank=True)),
+                ('login_base', models.CharField(help_text=b'Prefix for Slices associated with this Site', unique=True, max_length=50)),
+                ('is_public', models.BooleanField(default=True, help_text=b'Indicates the visibility of this site to other members')),
+                ('abbreviated_name', models.CharField(max_length=80)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SiteCredential',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(help_text=b'The credential type, e.g. ec2', max_length=128)),
+                ('key_id', models.CharField(help_text=b'The backend id of this credential', max_length=1024)),
+                ('enc_value', encrypted_fields.fields.EncryptedCharField(help_text=b'The key value of this credential', max_length=1024)),
+                ('site', models.ForeignKey(related_name=b'credentials', to='core.Site', help_text=b'The User this credential is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SiteDeployments',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('tenant_id', models.CharField(help_text=b'Keystone tenant id', max_length=200, null=True, blank=True)),
+                ('deployment', models.ForeignKey(to='core.Deployment')),
+                ('site', models.ForeignKey(to='core.Site')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SitePrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SiteRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True, max_length=30, choices=[(b'admin', b'Admin'), (b'pi', b'PI'), (b'tech', b'Tech'), (b'billing', b'Billing')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Slice',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'The Name of the Slice', unique=True, max_length=80)),
+                ('enabled', models.BooleanField(default=True, help_text=b'Status for this Slice')),
+                ('omf_friendly', models.BooleanField()),
+                ('description', models.TextField(help_text=b'High level description of the slice and expected activities', max_length=1024, blank=True)),
+                ('slice_url', models.URLField(max_length=512, blank=True)),
+                ('max_slivers', models.IntegerField(default=10)),
+                ('imagePreference', models.CharField(default=b'Ubuntu 12.04 LTS', max_length=256, null=True, blank=True)),
+                ('network', models.CharField(default=b'Private Only', max_length=256, null=True, blank=True)),
+                ('mountDataSets', models.CharField(default=b'GenBank', max_length=256, null=True, blank=True)),
+                ('creator', models.ForeignKey(related_name=b'slices', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
+                ('service', models.ForeignKey(related_name=b'service', blank=True, to='core.Service', null=True)),
+                ('serviceClass', models.ForeignKey(related_name=b'slices', default=core.models.serviceclass.get_default_serviceclass, to='core.ServiceClass', null=True)),
+                ('site', models.ForeignKey(related_name=b'slices', to='core.Site', help_text=b'The Site this Slice belongs to')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SliceCredential',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(help_text=b'The credential type, e.g. ec2', max_length=128)),
+                ('key_id', models.CharField(help_text=b'The backend id of this credential', max_length=1024)),
+                ('enc_value', encrypted_fields.fields.EncryptedCharField(help_text=b'The key value of this credential', max_length=1024)),
+                ('slice', models.ForeignKey(related_name=b'credentials', to='core.Slice', help_text=b'The User this credential is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SliceDeployments',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('tenant_id', models.CharField(help_text=b'Keystone tenant id', max_length=200, null=True, blank=True)),
+                ('network_id', models.CharField(help_text=b'Quantum network', max_length=256, null=True, blank=True)),
+                ('router_id', models.CharField(help_text=b'Quantum router id', max_length=256, null=True, blank=True)),
+                ('subnet_id', models.CharField(help_text=b'Quantum subnet id', max_length=256, null=True, blank=True)),
+                ('deployment', models.ForeignKey(to='core.Deployment')),
+                ('slice', models.ForeignKey(to='core.Slice')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SlicePrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SliceRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True, max_length=30, choices=[(b'admin', b'Admin'), (b'default', b'Default')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SliceTag',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'The name of this tag', max_length=30, choices=[(b'privatekey', b'Private Key'), (b'publickey', b'Public Key')])),
+                ('value', models.CharField(help_text=b'The value of this tag', max_length=1024)),
+                ('slice', models.ForeignKey(related_name=b'slicetags', to='core.Slice')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Sliver',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('instance_id', models.CharField(help_text=b'Nova instance id', max_length=200, null=True, blank=True)),
+                ('name', models.CharField(help_text=b'Sliver name', max_length=200)),
+                ('instance_name', models.CharField(help_text=b'OpenStack generated name', max_length=200, null=True, blank=True)),
+                ('ip', models.GenericIPAddressField(help_text=b'Sliver ip address', null=True, blank=True)),
+                ('numberCores', models.IntegerField(default=0, help_text=b'Number of cores for sliver', verbose_name=b'Number of Cores')),
+                ('userData', models.TextField(help_text=b'user_data passed to instance during creation', null=True, blank=True)),
+                ('creator', models.ForeignKey(related_name=b'slivers', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
+                ('deploymentNetwork', models.ForeignKey(related_name=b'sliver_deploymentNetwork', verbose_name=b'deployment', to='core.Deployment')),
+                ('flavor', models.ForeignKey(default=core.models.sliver.get_default_flavor, to='core.Flavor', help_text=b'Flavor of this instance')),
+                ('image', models.ForeignKey(related_name=b'slivers', to='core.Image')),
+                ('node', models.ForeignKey(related_name=b'slivers', to='core.Node')),
+                ('slice', models.ForeignKey(related_name=b'slivers', to='core.Slice')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Tag',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(help_text=b'The name of this tag', max_length=128)),
+                ('value', models.CharField(help_text=b'The value of this tag', max_length=1024)),
+                ('object_id', models.PositiveIntegerField()),
+                ('content_type', models.ForeignKey(to='contenttypes.ContentType')),
+                ('service', models.ForeignKey(related_name=b'tags', to='core.Service', help_text=b'The Service this Tag is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='UsableObject',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=1024)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='UserCredential',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(help_text=b'The credential type, e.g. ec2', max_length=128)),
+                ('key_id', models.CharField(help_text=b'The backend id of this credential', max_length=1024)),
+                ('enc_value', encrypted_fields.fields.EncryptedCharField(help_text=b'The key value of this credential', max_length=1024)),
+                ('user', models.ForeignKey(related_name=b'credentials', to=settings.AUTH_USER_MODEL, help_text=b'The User this credential is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='UserDashboardView',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('order', models.IntegerField(default=0)),
+                ('dashboardView', models.ForeignKey(related_name=b'dashboardViews', to='core.DashboardView')),
+                ('user', models.ForeignKey(related_name=b'dashboardViews', to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='UserDeployments',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('kuser_id', models.CharField(help_text=b'Keystone user id', max_length=200, null=True, blank=True)),
+                ('deployment', models.ForeignKey(to='core.Deployment')),
+                ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AddField(
+            model_name='sliceprivilege',
+            name='role',
+            field=models.ForeignKey(to='core.SliceRole'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='sliceprivilege',
+            name='slice',
+            field=models.ForeignKey(related_name=b'slice_privileges', to='core.Slice'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='sliceprivilege',
+            name='user',
+            field=models.ForeignKey(related_name=b'slice_privileges', to=settings.AUTH_USER_MODEL),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='siteprivilege',
+            name='role',
+            field=models.ForeignKey(to='core.SiteRole'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='siteprivilege',
+            name='site',
+            field=models.ForeignKey(related_name=b'site_privileges', to='core.Site'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='siteprivilege',
+            name='user',
+            field=models.ForeignKey(related_name=b'site_privileges', to=settings.AUTH_USER_MODEL),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='site',
+            name='deployments',
+            field=models.ManyToManyField(help_text=b'Select which sites are allowed to host nodes in this deployment', related_name=b'sites', through='core.SiteDeployments', to='core.Deployment', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='router',
+            name='owner',
+            field=models.ForeignKey(related_name=b'routers', to='core.Slice'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='router',
+            name='permittedNetworks',
+            field=models.ManyToManyField(related_name=b'availableRouters', to='core.Network', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='reservedresource',
+            name='resource',
+            field=models.ForeignKey(related_name=b'reservedResources', to='core.ServiceResource'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='reservedresource',
+            name='sliver',
+            field=models.ForeignKey(related_name=b'reservedResourrces', to='core.Sliver'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='reservation',
+            name='slice',
+            field=models.ForeignKey(related_name=b'reservations', to='core.Slice'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='planetstackprivilege',
+            name='role',
+            field=models.ForeignKey(to='core.PlanetStackRole'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='planetstackprivilege',
+            name='user',
+            field=models.ForeignKey(related_name=b'planetstack_privileges', to=settings.AUTH_USER_MODEL),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='node',
+            name='site',
+            field=models.ForeignKey(related_name=b'nodes', to='core.Site'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='networksliver',
+            name='sliver',
+            field=models.ForeignKey(to='core.Sliver'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='networkslice',
+            name='slice',
+            field=models.ForeignKey(to='core.Slice'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='networkparameter',
+            name='parameter',
+            field=models.ForeignKey(related_name=b'parameters', to='core.NetworkParameterType', help_text=b'The type of the parameter'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='owner',
+            field=models.ForeignKey(related_name=b'ownedNetworks', to='core.Slice', help_text=b'Slice that owns control of this Network'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='permittedSlices',
+            field=models.ManyToManyField(related_name=b'availableNetworks', to='core.Slice', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='slices',
+            field=models.ManyToManyField(related_name=b'networks', through='core.NetworkSlice', to='core.Slice', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='slivers',
+            field=models.ManyToManyField(related_name=b'networks', through='core.NetworkSliver', to='core.Sliver', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='template',
+            field=models.ForeignKey(to='core.NetworkTemplate'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='deploymentprivilege',
+            name='role',
+            field=models.ForeignKey(to='core.DeploymentRole'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='deploymentprivilege',
+            name='user',
+            field=models.ForeignKey(related_name=b'deployment_privileges', to=settings.AUTH_USER_MODEL),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='charge',
+            name='invoice',
+            field=models.ForeignKey(related_name=b'charges', blank=True, to='core.Invoice', null=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='charge',
+            name='object',
+            field=models.ForeignKey(to='core.UsableObject'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='charge',
+            name='slice',
+            field=models.ForeignKey(related_name=b'charges', blank=True, to='core.Slice', null=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='account',
+            name='site',
+            field=models.ForeignKey(related_name=b'accounts', to='core.Site', help_text=b'Site for this account'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='user',
+            name='dashboards',
+            field=models.ManyToManyField(to='core.DashboardView', through='core.UserDashboardView', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='user',
+            name='site',
+            field=models.ForeignKey(related_name=b'users', to='core.Site', help_text=b'Site this user will be homed too', null=True),
+            preserve_default=True,
+        ),
+    ]
diff --git a/planetstack/core/migrations/0002_omf_friendly_default_false.py b/planetstack/core/migrations/0002_omf_friendly_default_false.py
new file mode 100644
index 0000000..14fac6d
--- /dev/null
+++ b/planetstack/core/migrations/0002_omf_friendly_default_false.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='slice',
+            name='omf_friendly',
+            field=models.BooleanField(default=False),
+        ),
+    ]
diff --git a/planetstack/core/migrations/__init__.py b/planetstack/core/migrations/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/planetstack/core/migrations/__init__.py
@@ -0,0 +1 @@
+
diff --git a/planetstack/core/models/__init__.py b/planetstack/core/models/__init__.py
index 4e76958..169817f 100644
--- a/planetstack/core/models/__init__.py
+++ b/planetstack/core/models/__init__.py
@@ -18,11 +18,13 @@
 from .serviceresource import ServiceResource
 from .slice import SliceRole
 from .slice import SlicePrivilege
+from .credential import UserCredential,SiteCredential,SliceCredential
 from .site import SiteRole
 from .site import SitePrivilege
 from .planetstack import PlanetStackRole
 from .planetstack import PlanetStackPrivilege
 from .slicetag import SliceTag
+from .flavor import Flavor
 from .sliver import Sliver
 from .reservation import ReservedResource
 from .reservation import Reservation
diff --git a/planetstack/core/models/billing.py b/planetstack/core/models/billing.py
index 6d1c331..8c61418 100644
--- a/planetstack/core/models/billing.py
+++ b/planetstack/core/models/billing.py
@@ -6,6 +6,7 @@
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
 from django.db.models import Sum
+from django.utils import timezone
 
 class Account(PlCoreBase):
     site = models.ForeignKey(Site, related_name="accounts", help_text="Site for this account")
@@ -51,7 +52,7 @@
 class Payment(PlCoreBase):
     account = models.ForeignKey(Account, related_name="payments")
     amount = models.FloatField(default=0.0)
-    date = models.DateTimeField(default=datetime.datetime.now)
+    date = models.DateTimeField(default=timezone.now)
 
     def __unicode__(self): return u'%s-%0.2f-%s' % (self.account.site.name, self.amount, str(self.date))
 
diff --git a/planetstack/core/models/credential.py b/planetstack/core/models/credential.py
new file mode 100644
index 0000000..13bc1c8
--- /dev/null
+++ b/planetstack/core/models/credential.py
@@ -0,0 +1,52 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models import User,Site,Slice,Deployment
+from encrypted_fields import EncryptedCharField
+from core.models import Deployment,DeploymentLinkManager,DeploymentLinkDeletionManager
+
+class UserCredential(PlCoreBase):
+    user = models.ForeignKey(User, related_name='credentials', help_text="The User this credential is associated with")
+
+    name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
+    key_id = models.CharField(help_text="The backend id of this credential", max_length=1024)
+    enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
+
+
+    def __unicode__(self):
+        return self.name
+
+class SiteCredential(PlCoreBase):
+    site = models.ForeignKey(Site, related_name='credentials', help_text="The User this credential is associated with")
+
+    name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
+    key_id = models.CharField(help_text="The backend id of this credential", max_length=1024)
+    enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
+
+
+    def __unicode__(self):
+        return self.name
+
+class SliceCredential(PlCoreBase):
+    slice = models.ForeignKey(Slice, related_name='credentials', help_text="The User this credential is associated with")
+
+    name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
+    key_id = models.CharField(help_text="The backend id of this credential", max_length=1024)
+    enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
+
+
+    def __unicode__(self):
+        return self.name
+
+class DeploymentCredential(PlCoreBase):
+    objects = DeploymentLinkManager()
+    deleted_objects = DeploymentLinkDeletionManager()
+    deployment = models.ForeignKey(Deployment, related_name='credentials', help_text="The User this credential is associated with")
+
+    name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
+    key_id = models.CharField(help_text="The backend id of this credential", max_length=1024)
+    enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
+
+
+    def __unicode__(self):
+        return self.name
diff --git a/planetstack/core/models/flavor.py b/planetstack/core/models/flavor.py
new file mode 100644
index 0000000..84a5427
--- /dev/null
+++ b/planetstack/core/models/flavor.py
@@ -0,0 +1,45 @@
+import os
+import socket
+from django.db import models
+from core.models import PlCoreBase, Deployment
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+
+class Flavor(PlCoreBase):
+    name = models.CharField(max_length=32, help_text="name of this flavor, as displayed to users")
+    description = models.CharField(max_length=1024, blank=True, null=True)
+    flavor = models.CharField(max_length=32, help_text="flavor string used to configure deployments")
+    deployments = models.ManyToManyField(Deployment, blank=True, related_name="flavors")
+    order = models.IntegerField(default=0, help_text="used to order flavors when displayed in a list")
+    default = models.BooleanField(default=False, help_text="make this a default flavor to use when creating new instances")
+
+    class Meta:
+        app_label = "core"
+        ordering = ('order', 'name')
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    @staticmethod
+    def select_by_user(user):
+        return Flavor.objects.all()
+
+""" FlavorParameterType and FlavorParameter are below for completeness sake,
+    waiting for the day we might want to add parameters to flavors.
+
+class FlavorParameterType(PlCoreBase):
+    name = models.SlugField(help_text="The name of this parameter", max_length=128)
+    description = models.CharField(max_length=1024)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+class FlavorParameter(PlCoreBase):
+    parameter = models.ForeignKey(FlavorParameterType, related_name="parameters", help_text="The type of the parameter")
+    value = models.CharField(help_text="The value of this parameter", max_length=1024)
+
+    flavor = models.ForeignKey(Flavor)
+
+    def __unicode__(self):
+        return self.parameter.name
+
+"""
+
diff --git a/planetstack/core/models/image.py b/planetstack/core/models/image.py
index db01e1b..752dfe6 100644
--- a/planetstack/core/models/image.py
+++ b/planetstack/core/models/image.py
@@ -2,6 +2,7 @@
 from django.db import models
 from core.models import PlCoreBase
 from core.models import Deployment
+from core.models import Deployment,DeploymentLinkManager,DeploymentLinkDeletionManager
 
 # Create your models here.
 
@@ -14,6 +15,8 @@
     def __unicode__(self):  return u'%s' % (self.name)
 
 class ImageDeployments(PlCoreBase):
+    objects = DeploymentLinkManager()
+    deleted_objects = DeploymentLinkDeletionManager()
     image = models.ForeignKey(Image)
     deployment = models.ForeignKey(Deployment)
     glance_image_id = models.CharField(null=True, blank=True, max_length=200, help_text="Glance image id") 
diff --git a/planetstack/core/models/network.py b/planetstack/core/models/network.py
index e0e4975..1010cae 100644
--- a/planetstack/core/models/network.py
+++ b/planetstack/core/models/network.py
@@ -2,6 +2,7 @@
 import socket
 from django.db import models
 from core.models import PlCoreBase, Site, Slice, Sliver, Deployment
+from core.models import DeploymentLinkManager,DeploymentLinkDeletionManager
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
 
@@ -114,6 +115,9 @@
         return qs
 
 class NetworkDeployments(PlCoreBase):
+    objects = DeploymentLinkManager()
+    deleted_objects = DeploymentLinkDeletionManager()
+
     # Stores the openstack ids at various deployments
     network = models.ForeignKey(Network)
     deployment = models.ForeignKey(Deployment)
diff --git a/planetstack/core/models/plcorebase.py b/planetstack/core/models/plcorebase.py
index 446245b..d461c9d 100644
--- a/planetstack/core/models/plcorebase.py
+++ b/planetstack/core/models/plcorebase.py
@@ -1,10 +1,11 @@
-import datetime
 import os
 import sys
 from django.db import models
 from django.forms.models import model_to_dict
 from django.core.urlresolvers import reverse
 from django.forms.models import model_to_dict
+from django.utils import timezone
+import model_policy
 
 try:
     # This is a no-op if observer_disabled is set to 1 in the config file
@@ -21,14 +22,30 @@
 # This manager will be inherited by all subclasses because
 # the core model is abstract.
 class PlCoreBaseDeletionManager(models.Manager):
+    def get_queryset(self):
+        parent=super(PlCoreBaseDeletionManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(deleted=True)
+        else:
+            return parent.get_query_set().filter(deleted=True)
+
+    # deprecated in django 1.7 in favor of get_queryset().
     def get_query_set(self):
-        return super(PlCoreBaseDeletionManager, self).get_query_set().filter(deleted=True)
+        return self.get_queryset()
 
 # This manager will be inherited by all subclasses because
 # the core model is abstract.
 class PlCoreBaseManager(models.Manager):
+    def get_queryset(self):
+        parent=super(PlCoreBaseManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(deleted=False)
+        else:
+            return parent.get_query_set().filter(deleted=False)
+
+    # deprecated in django 1.7 in favor of get_queryset().
     def get_query_set(self):
-        return super(PlCoreBaseManager, self).get_query_set().filter(deleted=False)
+        return self.get_queryset()
 
 class PlCoreBase(models.Model):
     objects = PlCoreBaseManager()
@@ -36,8 +53,8 @@
 
     # default values for created and updated are only there to keep evolution
     # from failing.
-    created = models.DateTimeField(auto_now_add=True, default=datetime.datetime.now())
-    updated = models.DateTimeField(auto_now=True, default=datetime.datetime.now())
+    created = models.DateTimeField(auto_now_add=True, default=timezone.now)
+    updated = models.DateTimeField(auto_now=True, default=timezone.now)
     enacted = models.DateTimeField(null=True, default=None)
     backend_status = models.CharField(max_length=140,
                                       default="Provisioning in progress")
diff --git a/planetstack/core/models/serviceclass.py b/planetstack/core/models/serviceclass.py
index 3b6ee82..c339b67 100644
--- a/planetstack/core/models/serviceclass.py
+++ b/planetstack/core/models/serviceclass.py
@@ -4,7 +4,11 @@
 from core.models import Site
 from core.models import Deployment
 
-# Create your models here.
+def get_default_serviceclass():
+    try:
+        return ServiceClass.objects.get(name="Best Effort")
+    except ServiceClass.DoesNotExist:
+        return None
 
 class ServiceClass(PlCoreBase):
     name = models.CharField(max_length=32)
@@ -20,13 +24,6 @@
 
     def __unicode__(self):  return u'%s' % (self.name)
 
-    @staticmethod
-    def get_default():
-        try:
-            return ServiceClass.objects.get(name="Best Effort")
-        except ServiceClass.DoesNotExist:
-            return None
-
     def save_by_user(self, user, *args, **kwds):
         if self.can_update(user):
             super(ServiceClass, self).save(*args, **kwds)
diff --git a/planetstack/core/models/site.py b/planetstack/core/models/site.py
index fe7fb93..04d1073 100644
--- a/planetstack/core/models/site.py
+++ b/planetstack/core/models/site.py
@@ -1,11 +1,61 @@
 import os
 from django.db import models
-from core.models import PlCoreBase
+from core.models import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager
 from core.models import Tag
 from django.contrib.contenttypes import generic
 from geoposition.fields import GeopositionField
 from core.acl import AccessControlList
 
+class DeploymentLinkDeletionManager(PlCoreBaseDeletionManager):
+    def get_queryset(self):
+        parent=super(DeploymentLinkDeletionManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(Q(deployment__backend_type=config.observer_backend_type)|Q(backend_type=None))
+        else:
+            return parent.get_queryset().filter(Q(deployment__backend_type=config.observer_backend_type)|Q(backend_type=None))
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+
+class DeploymentDeletionManager(PlCoreBaseDeletionManager):
+    def get_queryset(self):
+        parent=super(DeploymentDeletionManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(Q(backend_type=config.observer_backend_type)|Q(backend_type=None))
+        else:
+            return parent.get_queryset().filter(Q(backend_type=config.observer_backend_type)|Q(backend_type=None))
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+class DeploymentLinkManager(PlCoreBaseManager):
+    def get_queryset(self):
+        parent=super(DeploymentLinkManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(Q(deployment__backend_type=config.observer_backend_type)|Q(backend_type=None))
+        else:
+            return parent.get_queryset().filter(Q(deployment__backend_type=config.observer_backend_type)|Q(backend_type=None))
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+
+class DeploymentManager(PlCoreBaseManager):
+    def get_queryset(self):
+        parent=super(DeploymentManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(Q(backend_type=config.observer_backend_type)|Q(backend_type=None))
+        else:
+            return parent.get_queryset().filter(Q(backend_type=config.observer_backend_type)|Q(backend_type=None))
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
 class Site(PlCoreBase):
     """
         A logical grouping of Nodes that are co-located at the same geographic location, which also typically corresponds to the Nodes' location in the physical network.
@@ -82,11 +132,14 @@
         return qs
 
 class Deployment(PlCoreBase):
+    objects = DeploymentManager()
+    deleted_objects = DeploymentDeletionManager()
     name = models.CharField(max_length=200, unique=True, help_text="Name of the Deployment")
     admin_user = models.CharField(max_length=200, null=True, blank=True, help_text="Username of an admin user at this deployment")
     admin_password = models.CharField(max_length=200, null=True, blank=True, help_text="Password of theadmin user at this deployment")

     admin_tenant = models.CharField(max_length=200, null=True, blank=True, help_text="Name of the tenant the admin user belongs to")

     auth_url = models.CharField(max_length=200, null=True, blank=True, help_text="Auth url for the deployment")
+    backend_type = models.CharField(max_length=200, null=True, blank=True, help_text="Type of deployment, e.g. EC2, OpenStack, or OpenStack version")
 
     # smbaker: the default of 'allow all' is intended for evolutions of existing
     #    deployments. When new deployments are created via the GUI, they are
@@ -133,6 +186,8 @@
         return Deployment.objects.all()
 
 class DeploymentRole(PlCoreBase):
+    objects = DeploymentLinkManager()
+    deleted_objects = DeploymentLinkDeletionManager()
 
     ROLE_CHOICES = (('admin','Admin'),)
     role = models.CharField(choices=ROLE_CHOICES, unique=True, max_length=30)
@@ -140,6 +195,8 @@
     def __unicode__(self):  return u'%s' % (self.role)
 
 class DeploymentPrivilege(PlCoreBase):
+    objects = DeploymentLinkManager()
+    deleted_objects = DeploymentLinkDeletionManager()
 
     user = models.ForeignKey('User', related_name='deployment_privileges')
     deployment = models.ForeignKey('Deployment', related_name='deployment_privileges')
@@ -168,6 +225,9 @@
         return qs 
 
 class SiteDeployments(PlCoreBase):
+    objects = DeploymentLinkManager()
+    deleted_objects = DeploymentLinkDeletionManager()
+
     site = models.ForeignKey(Site)
     deployment = models.ForeignKey(Deployment)
     tenant_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")    
diff --git a/planetstack/core/models/slice.py b/planetstack/core/models/slice.py
index e474560..12c278b 100644
--- a/planetstack/core/models/slice.py
+++ b/planetstack/core/models/slice.py
@@ -5,30 +5,32 @@
 from core.models.site import SitePrivilege
 from core.models import User
 from core.models import Role
-from core.models import Deployment
+from core.models import Deployment,DeploymentLinkManager,DeploymentLinkDeletionManager
 from core.models import ServiceClass
+from core.models.serviceclass import get_default_serviceclass
 from core.models import Tag
 from django.contrib.contenttypes import generic
 from core.models import Service
 from core.models import Deployment
+from django.core.exceptions import ValidationError
 
 # Create your models here.
 
 class Slice(PlCoreBase):
     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")
-    omf_friendly = models.BooleanField()
+    omf_friendly = models.BooleanField(default=False)
     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 Slice belongs to")
-    max_slivers = models.IntegerField(default=10) 
+    max_slivers = models.IntegerField(default=10)
     imagePreference = models.CharField(default="Ubuntu 12.04 LTS", null=True, blank=True, max_length=256)
     service = models.ForeignKey(Service, related_name='service', null=True, blank=True)
     network = models.CharField(default="Private Only",null=True, blank=True, max_length=256)
     mountDataSets = models.CharField(default="GenBank",null=True, blank=True, max_length=256)
     tags = generic.GenericRelation(Tag)
 
-    serviceClass = models.ForeignKey(ServiceClass, related_name = "slices", null=True, default=ServiceClass.get_default)
+    serviceClass = models.ForeignKey(ServiceClass, related_name = "slices", null=True, default=get_default_serviceclass)
     creator = models.ForeignKey(User, related_name='slices', blank=True, null=True)
 
     def __unicode__(self):  return u'%s' % (self.name)
@@ -38,6 +40,11 @@
         return "%s_%s" % (self.site.login_base, self.name)
 
     def save(self, *args, **kwds):
+        
+        site = Site.objects.get(id=self.site.id)
+        if not self.name.startswith(site.login_base):
+            raise ValidationError('slice name must begin with %s' % site.login_base)
+        
         if self.serviceClass is None:
             # We allowed None=True for serviceClass because Django evolution
             # will fail unless it is allowed. But, we we really don't want it to
@@ -106,6 +113,9 @@
         return qs
 
 class SliceDeployments(PlCoreBase):
+    objects = DeploymentLinkManager()
+    deleted_objects = DeploymentLinkDeletionManager()
+
     slice = models.ForeignKey(Slice)
     deployment = models.ForeignKey(Deployment)
     tenant_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")
diff --git a/planetstack/core/models/sliver.py b/planetstack/core/models/sliver.py
index e0ce5e2..ec7f266 100644
--- a/planetstack/core/models/sliver.py
+++ b/planetstack/core/models/sliver.py
@@ -9,11 +9,31 @@
 from core.models import Deployment
 from core.models import User
 from core.models import Tag
+from core.models import Flavor
 from django.contrib.contenttypes import generic
 
+def get_default_flavor(deployment = None):
+    # Find a default flavor that can be used for a sliver. This is particularly
+    # useful in evolution. It's also intended this helper function can be used
+    # for admin.py when users
+
+    if deployment:
+        flavors = deployment.flavors.all()
+    else:
+        flavors = Flavor.objects.all()
+
+    if not flavors:
+        return None
+
+    for flavor in flavors:
+        if flavor.default:
+            return flavor
+
+    return flavors[0]
+
 # Create your models here.
 class Sliver(PlCoreBase):
-    instance_id = models.CharField(null=True, blank=True, 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)
@@ -24,6 +44,7 @@
     node = models.ForeignKey(Node, related_name='slivers')
     deploymentNetwork = models.ForeignKey(Deployment, verbose_name='deployment', related_name='sliver_deploymentNetwork')
     numberCores = models.IntegerField(verbose_name="Number of Cores", help_text="Number of cores for sliver", default=0)
+    flavor = models.ForeignKey(Flavor, help_text="Flavor of this instance", default=get_default_flavor)
     tags = generic.GenericRelation(Tag)
     userData = models.TextField(blank=True, null=True, help_text="user_data passed to instance during creation")
 
diff --git a/planetstack/core/models/user.py b/planetstack/core/models/user.py
index 44e3f14..9a62e34 100644
--- a/planetstack/core/models/user.py
+++ b/planetstack/core/models/user.py
@@ -8,6 +8,9 @@
 from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
 from timezones.fields import TimeZoneField
 from operator import itemgetter, attrgetter
+from django.core.mail import EmailMultiAlternatives
+from core.middleware import get_request
+import model_policy
 
 # Create your models here.
 class UserManager(BaseUserManager):
@@ -45,9 +48,13 @@
         return user
 
 class DeletedUserManager(UserManager):
-    def get_query_set(self):
+    def get_queryset(self):
         return super(UserManager, self).get_query_set().filter(deleted=True)
 
+    # deprecated in django 1.7 in favor of get_queryset()
+    def get_query_set(self):
+        return self.get_queryset()
+
 class User(AbstractBaseUser):
 
     class Meta:
@@ -167,9 +174,24 @@
 
     def save(self, *args, **kwds):
         if not self.id:
-            self.set_password(self.password)    
+            self.set_password(self.password)
+        if self.is_active:
+            if self.password=="!":

+                self.send_temporary_password()

+

         self.username = self.email
-        super(User, self).save(*args, **kwds)  
+        super(User, self).save(*args, **kwds)
+
+    def send_temporary_password(self):
+        password = User.objects.make_random_password()
+        self.set_password(password)

+        subject, from_email, to = 'OpenCloud Account Credentials', 'support@opencloud.us', str(self.email)

+        text_content = 'This is an important message.'

+        userUrl="http://%s/" % get_request().get_host()

+        html_content = """<p>Your account has been created on OpenCloud. Please log in <a href="""+userUrl+""">here</a> to activate your account<br><br>Username: """+self.email+"""<br>Temporary Password: """+password+"""<br>Please change your password once you successully login into the site.</p>"""

+        msg = EmailMultiAlternatives(subject,text_content, from_email, [to])

+        msg.attach_alternative(html_content, "text/html")

+        msg.send()
 
     @staticmethod
     def select_by_user(user):
@@ -182,9 +204,9 @@
             sites = [sp.site for sp in site_privs if sp.role.role == 'pi']
             # get site privs of users at these sites
             site_privs = SitePrivilege.objects.filter(site__in=sites)
-            user_ids = [sp.user.id for sp in site_privs] + [user.id] 
+            user_ids = [sp.user.id for sp in site_privs] + [user.id]
             qs = User.objects.filter(Q(site__in=sites) | Q(id__in=user_ids))
-        return qs            
+        return qs
 
 class UserDashboardView(PlCoreBase):
      user = models.ForeignKey(User, related_name="dashboardViews")
diff --git a/planetstack/core/models/userdeployments.py b/planetstack/core/models/userdeployments.py
index 3422156..5685668 100644
--- a/planetstack/core/models/userdeployments.py
+++ b/planetstack/core/models/userdeployments.py
@@ -4,8 +4,12 @@
 from django.db import models
 from django.db.models import F, Q
 from core.models import PlCoreBase,Site,User,Deployment
+from core.models import Deployment,DeploymentLinkManager,DeploymentLinkDeletionManager
 
 class UserDeployments(PlCoreBase):
+    objects = DeploymentLinkManager()
+    deleted_objects = DeploymentLinkDeletionManager()
+
     user = models.ForeignKey(User)
     deployment = models.ForeignKey(Deployment)
     kuser_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone user id")
diff --git a/planetstack/core/views/legacyapi.py b/planetstack/core/views/legacyapi.py
index fa6ffb8..d7d77e4 100644
--- a/planetstack/core/views/legacyapi.py
+++ b/planetstack/core/views/legacyapi.py
@@ -158,8 +158,19 @@
             node_id = ps_id_to_pl_id(ps_sliver.node_id)
             if node_id in node_ids:
                 ps_node = ps_sliver.node
+
+                ip = socket.gethostbyname(ps_node.name)
+
+                # search for a dedicated public IP address
+                for networkSliver in ps_sliver.networksliver_set.all():
+                    if (not networkSliver.ip):
+                        continue
+                    template = networkSliver.network.template
+                    if (template.visibility=="public") and (template.translation=="none"):
+                        ip=networkSliver.ip
+
                 interface = {"node_id": node_id,
-                             "ip": socket.gethostbyname(ps_node.name),
+                             "ip": ip,
                              "broadcast": None,
                              "mac": "11:22:33:44:55:66",
                              "bwlimit": None,
diff --git a/planetstack/ec2_observer/__init__.pyc b/planetstack/ec2_observer/__init__.pyc
index c43a857..0be477a 100644
--- a/planetstack/ec2_observer/__init__.pyc
+++ b/planetstack/ec2_observer/__init__.pyc
Binary files differ
diff --git a/planetstack/ec2_observer/awslib.py b/planetstack/ec2_observer/awslib.py
index 5df0768..ca708ff 100644
--- a/planetstack/ec2_observer/awslib.py
+++ b/planetstack/ec2_observer/awslib.py
@@ -4,8 +4,8 @@
 class AwsException(Exception):
 	pass
 
-def aws_run(cmd):
-	cmd = 'aws %s'%cmd
+def aws_run(cmd,env=''):
+	cmd = '%s aws %s'%(env,cmd)
 	pipe = os.popen(cmd)
 	output_str = pipe.read()
 
diff --git a/planetstack/ec2_observer/creds.py b/planetstack/ec2_observer/creds.py
new file mode 100644
index 0000000..0a29c0d
--- /dev/null
+++ b/planetstack/ec2_observer/creds.py
@@ -0,0 +1,16 @@
+from core.models import *
+
+def get_creds(user=None, slice=None, site=None, deployment=None):
+    if (not user or not site):
+        raise Exception('User and Site have to be in context to use EC2')
+
+    cred = UserCredential.objects.filter(user=user)
+    if (not cred):
+        cred = SiteCredential.objects.filter(site=site)
+        
+    if (cred):
+        env = 'AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s'%(cred.key_id, cred.enc_value) 
+    else:
+        env = ''
+
+    return env
diff --git a/planetstack/ec2_observer/event_loop.py b/planetstack/ec2_observer/event_loop.py
index a579a94..1f15a8e 100644
--- a/planetstack/ec2_observer/event_loop.py
+++ b/planetstack/ec2_observer/event_loop.py
@@ -6,6 +6,7 @@
 import commands
 import threading
 import json
+import pdb
 
 from datetime import datetime
 from collections import defaultdict
@@ -16,26 +17,42 @@
 from util.logger import Logger, logging, logger
 #from timeout import timeout
 from planetstack.config import Config
-from ec2_observer.steps import *
+from observer.steps import *
 from syncstep import SyncStep
 from toposort import toposort
-from ec2_observer.error_mapper import *
+from observer.error_mapper import *
 
 debug_mode = False
 
 logger = Logger(level=logging.INFO)
 
 class StepNotReady(Exception):
-    pass
+	pass
 
 class NoOpDriver:
-    def __init__(self):
-         self.enabled = True
+	def __init__(self):
+		 self.enabled = True
+		 self.dependency_graph = None
+
+STEP_STATUS_WORKING=1
+STEP_STATUS_OK=2
+STEP_STATUS_KO=3
+
+def invert_graph(g):
+	ig = {}
+	for k,v in g.items():
+		for v0 in v:
+			try:
+				ig[v0].append(k)
+			except:
+				ig=[k]
+	return ig
 
 class PlanetStackObserver:
 	#sync_steps = [SyncNetworks,SyncNetworkSlivers,SyncSites,SyncSitePrivileges,SyncSlices,SyncSliceMemberships,SyncSlivers,SyncSliverIps,SyncExternalRoutes,SyncUsers,SyncRoles,SyncNodes,SyncImages,GarbageCollector]
 	sync_steps = []
 
+	
 	def __init__(self):
 		# The Condition object that gets signalled by Feefie events
 		self.step_lookup = {}
@@ -98,7 +115,7 @@
 			# This contains dependencies between backend records
 			self.backend_dependency_graph = json.loads(open(backend_path).read())
 		except Exception,e:
-			logger.info('Backend dependency graph not loaded: %s'%str(e))
+			logger.info('Backend dependency graph not loaded')
 			# We can work without a backend graph
 			self.backend_dependency_graph = {}
 
@@ -111,7 +128,6 @@
 				except KeyError:
 					provides_dict[m.__name__]=[s.__name__]
 
-				
 		step_graph = {}
 		for k,v in self.model_dependency_graph.iteritems():
 			try:
@@ -155,9 +171,10 @@
 					pass
 					# no dependencies, pass
 
-		dependency_graph = step_graph
+		self.dependency_graph = step_graph
+		self.deletion_dependency_graph = invert_graph(step_graph)
 
-		self.ordered_steps = toposort(dependency_graph, map(lambda s:s.__name__,self.sync_steps))
+		self.ordered_steps = toposort(self.dependency_graph, map(lambda s:s.__name__,self.sync_steps))
 		print "Order of steps=",self.ordered_steps
 		self.load_run_times()
 		
@@ -205,7 +222,6 @@
 				self.last_deletion_run_times[e]=0
 
 
-
 	def save_run_times(self):
 		run_times = json.dumps(self.last_run_times)
 		open('/tmp/observer_run_times','w').write(run_times)
@@ -221,16 +237,129 @@
 			if (failed_step in step.dependencies):
 				raise StepNotReady
 
+	def sync(self, S, deletion):
+		step = self.step_lookup[S]
+		start_time=time.time()
+		
+		dependency_graph = self.dependency_graph if not deletion else self.deletion_dependency_graph
+
+		# Wait for step dependencies to be met
+		try:
+			deps = self.dependency_graph[S]
+			has_deps = True
+		except KeyError:
+			has_deps = False
+
+		if (has_deps):
+			for d in deps:
+				cond = self.step_conditions[d]
+				cond.acquire()
+				if (self.step_status[d] is STEP_STATUS_WORKING):
+					cond.wait()
+				cond.release()
+			go = self.step_status[d] == STEP_STATUS_OK
+		else:
+			go = True
+
+		if (not go):
+			self.failed_steps.append(sync_step)
+			my_status = STEP_STATUS_KO
+		else:
+			sync_step = step(driver=self.driver,error_map=self.error_mapper)
+			sync_step.__name__ = step.__name__
+			sync_step.dependencies = []
+			try:
+				mlist = sync_step.provides
+				
+				for m in mlist:
+					sync_step.dependencies.extend(self.model_dependency_graph[m.__name__])
+			except KeyError:
+				pass
+			sync_step.debug_mode = debug_mode
+
+			should_run = False
+			try:
+				# Various checks that decide whether
+				# this step runs or not
+				self.check_class_dependency(sync_step, self.failed_steps) # dont run Slices if Sites failed
+				self.check_schedule(sync_step, deletion) # dont run sync_network_routes if time since last run < 1 hour
+				should_run = True
+			except StepNotReady:
+				logging.info('Step not ready: %s'%sync_step.__name__)
+				self.failed_steps.append(sync_step)
+				my_status = STEP_STATUS_KO
+			except Exception,e:
+				logging.error('%r',e)
+				logger.log_exc("sync step failed: %r. Deletion: %r"%(sync_step,deletion))
+				self.failed_steps.append(sync_step)
+				my_status = STEP_STATUS_KO
+
+			if (should_run):
+				try:
+					duration=time.time() - start_time
+
+					logger.info('Executing step %s' % sync_step.__name__)
+
+					failed_objects = sync_step(failed=list(self.failed_step_objects), deletion=deletion)
+
+					self.check_duration(sync_step, duration)
+
+					if failed_objects:
+						self.failed_step_objects.update(failed_objects)
+
+					my_status = STEP_STATUS_OK
+					self.update_run_time(sync_step,deletion)
+				except Exception,e:
+					logging.error('Model step failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!',e)
+					logger.log_exc(e)
+					self.failed_steps.append(S)
+					my_status = STEP_STATUS_KO
+			else:
+				my_status = STEP_STATUS_OK
+		
+		try:
+			my_cond = self.step_conditions[S]
+			my_cond.acquire()
+			self.step_status[S]=my_status
+			my_cond.notify_all()
+			my_cond.release()
+		except KeyError,e:
+			logging.info('Step %r is a leaf')
+			pass
+
 	def run(self):
 		if not self.driver.enabled:
 			return
+
 		if (self.driver_kind=="openstack") and (not self.driver.has_openstack):
 			return
 
 		while True:
 			try:
 				error_map_file = getattr(Config(), "error_map_path", "/opt/planetstack/error_map.txt")
-				error_mapper = ErrorMapper(error_map_file)
+				self.error_mapper = ErrorMapper(error_map_file)
+
+				# Set of whole steps that failed
+				self.failed_steps = []
+
+				# Set of individual objects within steps that failed
+				self.failed_step_objects = set()
+
+				# Set up conditions and step status
+				# This is needed for steps to run in parallel
+				# while obeying dependencies.
+
+				providers = set()
+				for v in self.dependency_graph.values():
+					if (v):
+						providers.update(v)
+
+				self.step_conditions = {}
+				self.step_status = {}
+				for p in list(providers):
+					self.step_conditions[p] = threading.Condition()
+					self.step_status[p] = STEP_STATUS_WORKING
+
 
 				logger.info('Waiting for event')
 				tBeforeWait = time.time()
@@ -238,68 +367,25 @@
 				logger.info('Observer woke up')
 
 				# Two passes. One for sync, the other for deletion.
-				for deletion in (False,True):
+				for deletion in [False,True]:
+					threads = []
 					logger.info('Deletion=%r...'%deletion)
-					# Set of whole steps that failed
-					failed_steps = []
+					schedule = self.ordered_steps if not deletion else reversed(self.ordered_steps)
 
-					# Set of individual objects within steps that failed
-					failed_step_objects = set()
+					for S in schedule:
+						thread = threading.Thread(target=self.sync, args=(S, deletion))
 
-					ordered_steps = self.ordered_steps if not deletion else reversed(self.ordered_steps)
+						logger.info('Deletion=%r...'%deletion)
+						threads.append(thread)
 
-					for S in ordered_steps:
-						step = self.step_lookup[S]
-						start_time=time.time()
-						
-						sync_step = step(driver=self.driver,error_map=error_mapper)
-						sync_step.__name__ = step.__name__
-						sync_step.dependencies = []
-						try:
-							mlist = sync_step.provides
-							
-							for m in mlist:
-								sync_step.dependencies.extend(self.model_dependency_graph[m.__name__])
-						except KeyError:
-							pass
-						sync_step.debug_mode = debug_mode
+					# Start threads 
+					for t in threads:
+						t.start()
 
-						should_run = False
-						try:
-							# Various checks that decide whether
-							# this step runs or not
-							self.check_class_dependency(sync_step, failed_steps) # dont run Slices if Sites failed
-							self.check_schedule(sync_step, deletion) # dont run sync_network_routes if time since last run < 1 hour
-							should_run = True
-						except StepNotReady:
-							logging.info('Step not ready: %s'%sync_step.__name__)
-							failed_steps.append(sync_step)
-						except Exception,e:
-							logging.error('%r',e)
-							logger.log_exc("sync step failed: %r. Deletion: %r"%(sync_step,deletion))
-							failed_steps.append(sync_step)
+					# Wait for all threads to finish before continuing with the run loop
+					for t in threads:
+						t.join()
 
-						if (should_run):
-							try:
-								duration=time.time() - start_time
-
-								logger.info('Executing step %s' % sync_step.__name__)
-
-								# ********* This is the actual sync step
-								#import pdb
-								#pdb.set_trace()
-								failed_objects = sync_step(failed=list(failed_step_objects), deletion=deletion)
-
-
-								self.check_duration(sync_step, duration)
-								if failed_objects:
-									failed_step_objects.update(failed_objects)
-
-								self.update_run_time(sync_step,deletion)
-							except Exception,e:
-								logging.error('Model step failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!',e)
-								logger.log_exc(e)
-								failed_steps.append(S)
 				self.save_run_times()
 			except Exception, e:
 				logging.error('Core error. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!',e)
diff --git a/planetstack/ec2_observer/event_manager.pyc b/planetstack/ec2_observer/event_manager.pyc
index d514197..a916928 100644
--- a/planetstack/ec2_observer/event_manager.pyc
+++ b/planetstack/ec2_observer/event_manager.pyc
Binary files differ
diff --git a/planetstack/ec2_observer/steps/sync_slivers.py b/planetstack/ec2_observer/steps/sync_slivers.py
index 55069aa..15cd5eb 100644
--- a/planetstack/ec2_observer/steps/sync_slivers.py
+++ b/planetstack/ec2_observer/steps/sync_slivers.py
@@ -11,6 +11,7 @@
 from ec2_observer.awslib import *
 from core.models.site import *
 from core.models.slice import *
+from ec2_observer.creds import *
 import pdb
 
 logger = Logger(level=logging.INFO)
@@ -38,9 +39,9 @@
         return my_slivers
 
     def delete_record(self, sliver):
-        import pdb
-        pdb.set_trace()
-        result = aws_run('ec2 terminate-instances --instance-ids=%s'%sliver.instance_id)
+        user = sliver.creator
+        e = get_creds(user=user, site=user.site)
+        result = aws_run('ec2 terminate-instances --instance-ids=%s'%sliver.instance_id, env=e)
 
     def sync_record(self, sliver):
         logger.info("sync'ing sliver:%s deployment:%s " % (sliver, sliver.node.deployment))
@@ -81,7 +82,10 @@
 
             # Bail out of we don't have a key
             key_name = sliver.creator.email.lower().replace('@', 'AT').replace('.', '')
-            key_sig = aws_run('ec2 describe-key-pairs')
+            u = sliver.creator
+            s = u.site
+            e = get_creds(user=u, site=s)
+            key_sig = aws_run('ec2 describe-key-pairs', env=e)
             ec2_keys = key_sig['KeyPairs']
             key_found = False
             for key in ec2_keys:
@@ -94,7 +98,7 @@
                 raise Exception('Will not sync sliver without key')
 
             image_id = sliver.image.path
-            instance_sig = aws_run('ec2 run-instances --image-id %s --instance-type %s --count 1 --key-name %s --placement AvailabilityZone=%s'%(image_id,instance_type,key_name,sliver.node.site.name))
+            instance_sig = aws_run('ec2 run-instances --image-id %s --instance-type %s --count 1 --key-name %s --placement AvailabilityZone=%s'%(image_id,instance_type,key_name,sliver.node.site.name), env=e)
             sliver.instance_id = instance_sig['Instances'][0]['InstanceId']
             sliver.save()
             state = instance_sig['Instances'][0]['State']['Code']
@@ -105,7 +109,7 @@
                 # This status message should go into backend_status
                 raise Exception('Waiting for instance to start')
         else:
-            ret = aws_run('ec2 describe-instances --instance-ids %s'%sliver.instance_id)
+            ret = aws_run('ec2 describe-instances --instance-ids %s'%sliver.instance_id, env=e)
             state = ret['Reservations'][0]['Instances'][0]['State']['Code']
             if (state==16):
                 sliver.ip = ret['Reservations'][0]['Instances'][0]['PublicIpAddress']
diff --git a/planetstack/ec2_observer/steps/sync_users.py b/planetstack/ec2_observer/steps/sync_users.py
index 496bc79..10ebd60 100644
--- a/planetstack/ec2_observer/steps/sync_users.py
+++ b/planetstack/ec2_observer/steps/sync_users.py
@@ -9,6 +9,7 @@
 from core.models.user import User
 from core.models.site import *
 from ec2_observer.awslib import *
+from ec2_observer.creds import *
 import pdb
 
 class SyncUsers(SyncStep):
@@ -20,13 +21,19 @@
             return []
 
         users = User.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
-        if (users):
-            key_sig = aws_run('ec2 describe-key-pairs')
+        
+        keys = []
+        creds = []
+        for u in users:
+            e = get_creds(user=u, site=u.site)
+            key_sig = aws_run('ec2 describe-key-pairs', env=e)
             ec2_keys = key_sig['KeyPairs']
+            creds.append(e)
+            keys.append(ec2_keys)
         else:
             ec2_keys = []
 
-        for user in users:
+        for user,ec2_keys,e in zip(users,keys,creds):
             if (user.public_key): 
                 key_name = user.email.lower().replace('@', 'AT').replace('.', '')
                 key_found = False
@@ -37,10 +44,9 @@
                         break
 
                 if (not key_found):
-                    aws_run('ec2 import-key-pair --key-name %s --public-key-material "%s"'%(key_name, user.public_key))
+                    aws_run('ec2 import-key-pair --key-name %s --public-key-material "%s"'%(key_name, user.public_key),env=e)
                     
         return users
 
     def sync_record(self, node):
         node.save()
-          
diff --git a/planetstack/ec2_observer/syncstep.py b/planetstack/ec2_observer/syncstep.py
index d5f7523..31fec04 100644
--- a/planetstack/ec2_observer/syncstep.py
+++ b/planetstack/ec2_observer/syncstep.py
@@ -86,7 +86,8 @@
                 except:
                     o.backend_status = str(e)
 
-                o.save(update_fields=['backend_status'])
+                if (o.pk):
+                    o.save(update_fields=['backend_status'])
 
                 logger.log_exc("sync step failed!")
                 failed.append(o)
diff --git a/planetstack/ec2_observer/toposort.py b/planetstack/ec2_observer/toposort.py
index a2c9389..e771325 100644
--- a/planetstack/ec2_observer/toposort.py
+++ b/planetstack/ec2_observer/toposort.py
@@ -10,6 +10,32 @@
 from datetime import datetime
 from collections import defaultdict
 
+# Assumes that there are no empty dependencies
+# in the graph. E.g. Foo -> []
+def dfs(graph, visit):
+	nodes = graph.keys()
+	edge_nodes = set()
+
+	for n in nodes:
+		edge_nodes|=set(graph[n])
+
+	sinks = list(edge_nodes - set(nodes))
+	sources = list(set(nodes) - edge_nodes)
+	
+	nodes.extend(sinks)
+
+	visited = set(sources)
+	stack = sources
+	while stack:
+		current = stack.pop()
+		visit(current)
+		for node in graph[current]:
+			if node not in visited:
+				stack.append(node)
+				visited.add(node)
+
+	return sources
+
 # Topological sort
 # Notes:
 # - Uses a stack instead of recursion
diff --git a/planetstack/hpc/migrations/0001_initial.py b/planetstack/hpc/migrations/0001_initial.py
new file mode 100644
index 0000000..c2e55b1
--- /dev/null
+++ b/planetstack/hpc/migrations/0001_initial.py
@@ -0,0 +1,159 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import datetime
+from django.conf import settings
+import django.utils.timezone
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0002_omf_friendly_default_false'),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='AccessMap',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.CharField(help_text=b'Name of the Access Map', max_length=64)),
+                ('description', models.TextField(max_length=130, null=True, blank=True)),
+                ('map', models.FileField(help_text=b'specifies which client requests are allowed', upload_to=b'maps/')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='CDNPrefix',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('cdn_prefix_id', models.IntegerField(null=True, blank=True)),
+                ('prefix', models.CharField(help_text=b'Registered Prefix for Domain', max_length=200)),
+                ('description', models.TextField(help_text=b'Description of Content Provider', max_length=254, null=True, blank=True)),
+                ('enabled', models.BooleanField(default=True)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ContentProvider',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('content_provider_id', models.IntegerField(null=True, blank=True)),
+                ('name', models.CharField(max_length=254)),
+                ('enabled', models.BooleanField(default=True)),
+                ('description', models.TextField(help_text=b'Description of Content Provider', max_length=254, null=True, blank=True)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='HpcService',
+            fields=[
+                ('service_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='core.Service')),
+            ],
+            options={
+                'verbose_name': 'HPC Service',
+            },
+            bases=('core.service', models.Model),
+        ),
+        migrations.CreateModel(
+            name='OriginServer',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('origin_server_id', models.IntegerField(null=True, blank=True)),
+                ('url', models.URLField()),
+                ('authenticated', models.BooleanField(default=False, help_text=b'Status for this Site')),
+                ('enabled', models.BooleanField(default=True, help_text=b'Status for this Site')),
+                ('protocol', models.CharField(default=b'HTTP', max_length=12, choices=[(b'http', b'HTTP'), (b'rtmp', b'RTMP'), (b'rtp', b'RTP'), (b'shout', b'SHOUTcast')])),
+                ('redirects', models.BooleanField(default=True, help_text=b'Indicates whether Origin Server redirects should be used for this Origin Server')),
+                ('description', models.TextField(max_length=255, null=True, blank=True)),
+                ('contentProvider', models.ForeignKey(to='hpc.ContentProvider')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ServiceProvider',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('service_provider_id', models.IntegerField(null=True, blank=True)),
+                ('name', models.CharField(help_text=b'Service Provider Name', max_length=254)),
+                ('description', models.TextField(help_text=b'Description of Service Provider', max_length=254, null=True, blank=True)),
+                ('enabled', models.BooleanField(default=True)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SiteMap',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.CharField(help_text=b'Name of the Site Map', max_length=64)),
+                ('description', models.TextField(max_length=130, null=True, blank=True)),
+                ('map', models.FileField(help_text=b'specifies how to map requests to hpc instances', upload_to=b'maps/')),
+                ('contentProvider', models.ForeignKey(blank=True, to='hpc.ContentProvider', null=True)),
+                ('serviceProvider', models.ForeignKey(blank=True, to='hpc.ServiceProvider', null=True)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AddField(
+            model_name='contentprovider',
+            name='serviceProvider',
+            field=models.ForeignKey(to='hpc.ServiceProvider'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='contentprovider',
+            name='users',
+            field=models.ManyToManyField(to=settings.AUTH_USER_MODEL),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='cdnprefix',
+            name='contentProvider',
+            field=models.ForeignKey(to='hpc.ContentProvider'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='cdnprefix',
+            name='defaultOriginServer',
+            field=models.ForeignKey(blank=True, to='hpc.OriginServer', null=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='accessmap',
+            name='contentProvider',
+            field=models.ForeignKey(to='hpc.ContentProvider'),
+            preserve_default=True,
+        ),
+    ]
diff --git a/planetstack/hpc/migrations/__init__.py b/planetstack/hpc/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/hpc/migrations/__init__.py
diff --git a/planetstack/kairos/migrations/0001_initial.py b/planetstack/kairos/migrations/0001_initial.py
new file mode 100644
index 0000000..4579cf6
--- /dev/null
+++ b/planetstack/kairos/migrations/0001_initial.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import django.utils.timezone
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0002_omf_friendly_default_false'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='KairosDBService',
+            fields=[
+                ('service_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='core.Service')),
+            ],
+            options={
+                'verbose_name': 'KairosDB Service',
+            },
+            bases=('core.service', models.Model),
+        ),
+    ]
diff --git a/planetstack/kairos/migrations/__init__.py b/planetstack/kairos/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/kairos/migrations/__init__.py
diff --git a/planetstack/model_policies/__init__.py b/planetstack/model_policies/__init__.py
new file mode 100644
index 0000000..8671d6a
--- /dev/null
+++ b/planetstack/model_policies/__init__.py
@@ -0,0 +1,3 @@
+from .model_policy_Slice import *
+from .model_policy_User import *
+from .model_policy_Network import *
diff --git a/planetstack/model_policies/model_policy_Network.py b/planetstack/model_policies/model_policy_Network.py
new file mode 100644
index 0000000..f48b25a
--- /dev/null
+++ b/planetstack/model_policies/model_policy_Network.py
@@ -0,0 +1,23 @@
+from core.models import *
+
+def handle(network):
+	from core.models import SliceDeployments,NetworkDeployments
+	from collections import defaultdict
+	# network deployments are not visible to users. We must ensure
+	# networks are deployed at all deploymets available to their slices.
+	slice_deployments = SliceDeployments.objects.all()
+	slice_deploy_lookup = defaultdict(list)
+	for slice_deployment in slice_deployments:
+		slice_deploy_lookup[slice_deployment.slice].append(slice_deployment.deployment)
+
+	network_deployments = NetworkDeployments.objects.all()
+	network_deploy_lookup = defaultdict(list)
+	for network_deployment in network_deployments:
+		network_deploy_lookup[network_deployment.network].append(network_deployment.deployment)
+
+	expected_deployments = slice_deploy_lookup[network.owner]
+	for expected_deployment in expected_deployments:
+		if network not in network_deploy_lookup or \
+		  expected_deployment not in network_deploy_lookup[network]:
+			nd = NetworkDeployments(network=network, deployment=expected_deployment)
+			nd.save()
diff --git a/planetstack/model_policies/model_policy_Slice.py b/planetstack/model_policies/model_policy_Slice.py
new file mode 100644
index 0000000..6fd968c
--- /dev/null
+++ b/planetstack/model_policies/model_policy_Slice.py
@@ -0,0 +1,24 @@
+
+def handle(slice):
+	from core.models import SiteDeployments,SliceDeployments,Deployment
+	from collections import defaultdict
+	site_deployments = SiteDeployments.objects.all()
+	site_deploy_lookup = defaultdict(list)
+	for site_deployment in site_deployments:
+		site_deploy_lookup[site_deployment.site].append(site_deployment.deployment)
+	
+	slice_deployments = SliceDeployments.objects.all()
+	slice_deploy_lookup = defaultdict(list)
+	for slice_deployment in slice_deployments:
+		slice_deploy_lookup[slice_deployment.slice].append(slice_deployment.deployment)
+	
+	all_deployments = Deployment.objects.all() 
+	# slices are added to all deployments for now
+	expected_deployments = all_deployments
+	#expected_deployments = site_deploy_lookup[slice.site]
+	for expected_deployment in expected_deployments:
+		if slice not in slice_deploy_lookup or \
+		   expected_deployment not in slice_deploy_lookup[slice]:
+			sd = SliceDeployments(slice=slice, deployment=expected_deployment)
+			sd.save()
+
diff --git a/planetstack/model_policies/model_policy_User.py b/planetstack/model_policies/model_policy_User.py
new file mode 100644
index 0000000..6118a7b
--- /dev/null
+++ b/planetstack/model_policies/model_policy_User.py
@@ -0,0 +1,32 @@
+from core.models import *
+
+def handle(user):
+	from core.models import Deployment,SiteDeployments,UserDeployments
+	from collections import defaultdict
+	deployments = Deployment.objects.all()
+	site_deployments = SiteDeployments.objects.all()
+	site_deploy_lookup = defaultdict(list)
+	for site_deployment in site_deployments:
+		site_deploy_lookup[site_deployment.site].append(site_deployment.deployment)
+
+	user_deploy_lookup = defaultdict(list)
+	for user_deployment in UserDeployments.objects.all():
+		user_deploy_lookup[user_deployment.user].append(user_deployment.deployment)
+   
+	all_deployments = Deployment.objects.filter() 
+	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]
+		# 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]: 
+			# add new record
+			ud = UserDeployments(user=user, deployment=expected_deployment)
+			ud.save()    
+
diff --git a/planetstack/model_policy.py b/planetstack/model_policy.py
new file mode 100644
index 0000000..dbe8453
--- /dev/null
+++ b/planetstack/model_policy.py
@@ -0,0 +1,17 @@
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+import pdb
+from core.models import *
+import model_policies
+
+@receiver(post_save)
+def post_save_handler(sender, **kwargs):
+	sender_name = sender.__name__
+	policy_name = 'model_policy_%s'%sender_name
+	
+	if (not kwargs['update_fields']):
+		try:
+			policy_handler = getattr(model_policies, policy_name)
+			policy_handler.handle(sender)
+		except:
+			pass
diff --git a/planetstack/nagios/migrations/0001_initial.py b/planetstack/nagios/migrations/0001_initial.py
new file mode 100644
index 0000000..7a117cc
--- /dev/null
+++ b/planetstack/nagios/migrations/0001_initial.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0002_omf_friendly_default_false'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='NagiosService',
+            fields=[
+                ('service_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='core.Service')),
+            ],
+            options={
+                'verbose_name': 'Nagios Service',
+            },
+            bases=('core.service', models.Model),
+        ),
+    ]
diff --git a/planetstack/nagios/migrations/__init__.py b/planetstack/nagios/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/nagios/migrations/__init__.py
diff --git a/planetstack/openstack/driver.py b/planetstack/openstack/driver.py
index c3e1f35..4f1c177 100644
--- a/planetstack/openstack/driver.py
+++ b/planetstack/openstack/driver.py
@@ -417,11 +417,12 @@
 
         return (subnet_id, subnet)
 
-    def spawn_instance(self, name, key_name=None, hostname=None, image_id=None, security_group=None, pubkeys=[], nics=None, metadata=None, userdata=None):
-        flavor_name = self.config.nova_default_flavor
+    def spawn_instance(self, name, key_name=None, hostname=None, image_id=None, security_group=None, pubkeys=[], nics=None, metadata=None, userdata=None, flavor_name=None):
+        if not flavor_name:
+            flavor_name = self.config.nova_default_flavor
+
         flavor = self.shell.nova.flavors.find(name=flavor_name)
-        #if not image:
-        #    image = self.config.nova_default_imave
+
         if not security_group:
             security_group = self.config.nova_default_security_group
 
diff --git a/planetstack/openstack_observer/event_loop.py b/planetstack/openstack_observer/event_loop.py
index 9f4658e..12965bb 100644
--- a/planetstack/openstack_observer/event_loop.py
+++ b/planetstack/openstack_observer/event_loop.py
@@ -6,11 +6,13 @@
 import commands
 import threading
 import json
+import pdb
 
 from datetime import datetime
 from collections import defaultdict
 from core.models import *
 from django.db.models import F, Q
+from django.db import connection
 #from openstack.manager import OpenStackManager
 from openstack.driver import OpenStackDriver
 from util.logger import Logger, logging, logger
@@ -31,11 +33,27 @@
 class NoOpDriver:
 	def __init__(self):
 		 self.enabled = True
+		 self.dependency_graph = None
+
+STEP_STATUS_WORKING=1
+STEP_STATUS_OK=2
+STEP_STATUS_KO=3
+
+def invert_graph(g):
+	ig = {}
+	for k,v in g.items():
+		for v0 in v:
+			try:
+				ig[v0].append(k)
+			except:
+				ig=[k]
+	return ig
 
 class PlanetStackObserver:
 	#sync_steps = [SyncNetworks,SyncNetworkSlivers,SyncSites,SyncSitePrivileges,SyncSlices,SyncSliceMemberships,SyncSlivers,SyncSliverIps,SyncExternalRoutes,SyncUsers,SyncRoles,SyncNodes,SyncImages,GarbageCollector]
 	sync_steps = []
 
+	
 	def __init__(self):
 		# The Condition object that gets signalled by Feefie events
 		self.step_lookup = {}
@@ -111,7 +129,6 @@
 				except KeyError:
 					provides_dict[m.__name__]=[s.__name__]
 
-				
 		step_graph = {}
 		for k,v in self.model_dependency_graph.iteritems():
 			try:
@@ -155,9 +172,10 @@
 					pass
 					# no dependencies, pass
 
-		dependency_graph = step_graph
+		self.dependency_graph = step_graph
+		self.deletion_dependency_graph = invert_graph(step_graph)
 
-		self.ordered_steps = toposort(dependency_graph, map(lambda s:s.__name__,self.sync_steps))
+		self.ordered_steps = toposort(self.dependency_graph, map(lambda s:s.__name__,self.sync_steps))
 		print "Order of steps=",self.ordered_steps
 		self.load_run_times()
 		
@@ -205,7 +223,6 @@
 				self.last_deletion_run_times[e]=0
 
 
-
 	def save_run_times(self):
 		run_times = json.dumps(self.last_run_times)
 		open('/tmp/observer_run_times','w').write(run_times)
@@ -221,16 +238,143 @@
 			if (failed_step in step.dependencies):
 				raise StepNotReady
 
+	def sync(self, S, deletion):
+            try:
+		step = self.step_lookup[S]
+		start_time=time.time()
+
+                logger.info("Starting to work on step %s" % step.__name__)
+		
+		dependency_graph = self.dependency_graph if not deletion else self.deletion_dependency_graph
+
+		# Wait for step dependencies to be met
+		try:
+			deps = self.dependency_graph[S]
+			has_deps = True
+		except KeyError:
+			has_deps = False
+
+		if (has_deps):
+			for d in deps:
+                                if d==step.__name__:
+                                    logger.info("   step %s self-wait skipped" % step.__name__)
+                                    continue
+
+				cond = self.step_conditions[d]
+				cond.acquire()
+				if (self.step_status[d] is STEP_STATUS_WORKING):
+                                        logger.info("  step %s wait on dep %s" % (step.__name__, d))
+					cond.wait()
+				cond.release()
+			go = self.step_status[d] == STEP_STATUS_OK
+		else:
+			go = True
+
+		if (not go):
+                        # SMBAKER: sync_step was not defined here, so I changed
+                        #    this from 'sync_step' to 'step'. Verify.
+			self.failed_steps.append(step)
+			my_status = STEP_STATUS_KO
+		else:
+			sync_step = step(driver=self.driver,error_map=self.error_mapper)
+			sync_step.__name__ = step.__name__
+			sync_step.dependencies = []
+			try:
+				mlist = sync_step.provides
+
+				for m in mlist:
+					sync_step.dependencies.extend(self.model_dependency_graph[m.__name__])
+			except KeyError:
+				pass
+			sync_step.debug_mode = debug_mode
+
+			should_run = False
+			try:
+				# Various checks that decide whether
+				# this step runs or not
+				self.check_class_dependency(sync_step, self.failed_steps) # dont run Slices if Sites failed
+				self.check_schedule(sync_step, deletion) # dont run sync_network_routes if time since last run < 1 hour
+				should_run = True
+			except StepNotReady:
+				logger.info('Step not ready: %s'%sync_step.__name__)
+				self.failed_steps.append(sync_step)
+				my_status = STEP_STATUS_KO
+			except Exception,e:
+				logger.error('%r' % e)
+				logger.log_exc("sync step failed: %r. Deletion: %r"%(sync_step,deletion))
+				self.failed_steps.append(sync_step)
+				my_status = STEP_STATUS_KO
+
+			if (should_run):
+				try:
+					duration=time.time() - start_time
+
+					logger.info('Executing step %s' % sync_step.__name__)
+
+					failed_objects = sync_step(failed=list(self.failed_step_objects), deletion=deletion)
+
+					self.check_duration(sync_step, duration)
+
+					if failed_objects:
+						self.failed_step_objects.update(failed_objects)
+
+                                        logger.info("Step %r succeeded" % step)
+					my_status = STEP_STATUS_OK
+					self.update_run_time(sync_step,deletion)
+				except Exception,e:
+					logger.error('Model step %r failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!' % (step, e))
+					logger.log_exc(e)
+					self.failed_steps.append(S)
+					my_status = STEP_STATUS_KO
+			else:
+                                logger.info("Step %r succeeded due to non-run" % step)
+				my_status = STEP_STATUS_OK
+
+		try:
+			my_cond = self.step_conditions[S]
+			my_cond.acquire()
+			self.step_status[S]=my_status
+			my_cond.notify_all()
+			my_cond.release()
+		except KeyError,e:
+			logger.info('Step %r is a leaf' % step)
+			pass
+            finally:
+                connection.close()
+
 	def run(self):
 		if not self.driver.enabled:
 			return
+
 		if (self.driver_kind=="openstack") and (not self.driver.has_openstack):
 			return
 
 		while True:
 			try:
 				error_map_file = getattr(Config(), "error_map_path", "/opt/planetstack/error_map.txt")
-				error_mapper = ErrorMapper(error_map_file)
+				self.error_mapper = ErrorMapper(error_map_file)
+
+				# Set of whole steps that failed
+				self.failed_steps = []
+
+				# Set of individual objects within steps that failed
+				self.failed_step_objects = set()
+
+				# Set up conditions and step status
+				# This is needed for steps to run in parallel
+				# while obeying dependencies.
+
+				providers = set()
+				for v in self.dependency_graph.values():
+					if (v):
+						providers.update(v)
+
+				self.step_conditions = {}
+				self.step_status = {}
+				for p in list(providers):
+					self.step_conditions[p] = threading.Condition()
+					self.step_status[p] = STEP_STATUS_WORKING
+
 
 				logger.info('Waiting for event')
 				tBeforeWait = time.time()
@@ -238,70 +382,27 @@
 				logger.info('Observer woke up')
 
 				# Two passes. One for sync, the other for deletion.
-				for deletion in (False,True):
+				for deletion in [False,True]:
+					threads = []
 					logger.info('Deletion=%r...'%deletion)
-					# Set of whole steps that failed
-					failed_steps = []
+					schedule = self.ordered_steps if not deletion else reversed(self.ordered_steps)
 
-					# Set of individual objects within steps that failed
-					failed_step_objects = set()
+					for S in schedule:
+						thread = threading.Thread(target=self.sync, args=(S, deletion))
 
-					ordered_steps = self.ordered_steps if not deletion else reversed(self.ordered_steps)
+						logger.info('Deletion=%r...'%deletion)
+						threads.append(thread)
 
-					for S in ordered_steps:
-						step = self.step_lookup[S]
-						start_time=time.time()
-						
-						sync_step = step(driver=self.driver,error_map=error_mapper)
-						sync_step.__name__ = step.__name__
-						sync_step.dependencies = []
-						try:
-							mlist = sync_step.provides
-							
-							for m in mlist:
-								sync_step.dependencies.extend(self.model_dependency_graph[m.__name__])
-						except KeyError:
-							pass
-						sync_step.debug_mode = debug_mode
+					# Start threads 
+					for t in threads:
+						t.start()
 
-						should_run = False
-						try:
-							# Various checks that decide whether
-							# this step runs or not
-							self.check_class_dependency(sync_step, failed_steps) # dont run Slices if Sites failed
-							self.check_schedule(sync_step, deletion) # dont run sync_network_routes if time since last run < 1 hour
-							should_run = True
-						except StepNotReady:
-							logging.info('Step not ready: %s'%sync_step.__name__)
-							failed_steps.append(sync_step)
-						except Exception,e:
-							logging.error('%r',e)
-							logger.log_exc("sync step failed: %r. Deletion: %r"%(sync_step,deletion))
-							failed_steps.append(sync_step)
+					# Wait for all threads to finish before continuing with the run loop
+					for t in threads:
+						t.join()
 
-						if (should_run):
-							try:
-								duration=time.time() - start_time
-
-								logger.info('Executing step %s' % sync_step.__name__)
-
-								# ********* This is the actual sync step
-								#import pdb
-								#pdb.set_trace()
-								failed_objects = sync_step(failed=list(failed_step_objects), deletion=deletion)
-
-
-								self.check_duration(sync_step, duration)
-								if failed_objects:
-									failed_step_objects.update(failed_objects)
-
-								self.update_run_time(sync_step,deletion)
-							except Exception,e:
-								logging.error('Model step failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!',e)
-								logger.log_exc(e)
-								failed_steps.append(S)
 				self.save_run_times()
 			except Exception, e:
-				logging.error('Core error. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!',e)
+				logger.error('Core error. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!' % e)
 				logger.log_exc("Exception in observer run loop")
 				traceback.print_exc()
diff --git a/planetstack/openstack_observer/steps/__init__.py b/planetstack/openstack_observer/steps/__init__.py
index 2ef6922..0151af3 100644
--- a/planetstack/openstack_observer/steps/__init__.py
+++ b/planetstack/openstack_observer/steps/__init__.py
@@ -1,16 +1,16 @@
-#from .sync_external_routes import SyncExternalRoutes
-from .sync_network_slivers import SyncNetworkSlivers
-from .sync_networks import SyncNetworks
-from .sync_network_deployments import SyncNetworkDeployments
-from .sync_site_privileges import SyncSitePrivileges
-from .sync_sites import SyncSites
-from .sync_slice_memberships import SyncSliceMemberships
-from .sync_slices import SyncSlices
-#from .sync_sliver_ips import SyncSliverIps
-from .sync_slivers import SyncSlivers
-from .sync_users import SyncUsers
-from .sync_roles import SyncRoles
-from .sync_nodes import SyncNodes
-from .sync_images import SyncImages
-from .sync_image_deployments import SyncImageDeployments
-from .garbage_collector import GarbageCollector
+##from .sync_external_routes import SyncExternalRoutes
+#from .sync_network_slivers import SyncNetworkSlivers
+#from .sync_networks import SyncNetworks
+#from .sync_network_deployments import SyncNetworkDeployments
+#from .sync_site_privileges import SyncSitePrivileges
+#from .sync_sites import SyncSites
+#from .sync_slice_memberships import SyncSliceMemberships
+#from .sync_slices import SyncSlices
+##from .sync_sliver_ips import SyncSliverIps
+#from .sync_slivers import SyncSlivers
+#from .sync_users import SyncUsers
+#from .sync_roles import SyncRoles
+#from .sync_nodes import SyncNodes
+#from .sync_images import SyncImages
+#from .sync_image_deployments import SyncImageDeployments
+#from .garbage_collector import GarbageCollector
diff --git a/planetstack/openstack_observer/steps/sync_network_deployments.py b/planetstack/openstack_observer/steps/sync_network_deployments.py
index 367440d..77d3a3a 100644
--- a/planetstack/openstack_observer/steps/sync_network_deployments.py
+++ b/planetstack/openstack_observer/steps/sync_network_deployments.py
@@ -20,25 +20,6 @@
         if (deleted):
             return NetworkDeployments.deleted_objects.all()
         else:
-            # network deployments are not visible to users. We must ensure
-            # networks are deployed at all deploymets available to their slices.
-            slice_deployments = SliceDeployments.objects.all()
-            slice_deploy_lookup = defaultdict(list)
-            for slice_deployment in slice_deployments:
-                slice_deploy_lookup[slice_deployment.slice].append(slice_deployment.deployment)
-
-            network_deployments = NetworkDeployments.objects.all()
-            network_deploy_lookup = defaultdict(list)
-            for network_deployment in network_deployments:
-                network_deploy_lookup[network_deployment.network].append(network_deployment.deployment)
-
-            for network in Network.objects.filter():
-                expected_deployments = slice_deploy_lookup[network.owner]
-                for expected_deployment in expected_deployments:
-                    if network not in network_deploy_lookup or \
-                      expected_deployment not in network_deploy_lookup[network]:
-                        nd = NetworkDeployments(network=network, deployment=expected_deployment)
-                        nd.save()
             return NetworkDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
 
     def get_next_subnet(self, deployment=None):
@@ -122,6 +103,10 @@
         network_deployment.save()
 
     def sync_record(self, network_deployment):
+        if not network_deployment.deployment.admin_user:
+            logger.info("deployment %r has no admin_user, skipping" % network_deployment.deployment)
+            return
+
         if network_deployment.network.owner and network_deployment.network.owner.creator:
             try:
                 # update manager context
diff --git a/planetstack/openstack_observer/steps/sync_networks.py b/planetstack/openstack_observer/steps/sync_networks.py
index 84257f7..5174fe6 100644
--- a/planetstack/openstack_observer/steps/sync_networks.py
+++ b/planetstack/openstack_observer/steps/sync_networks.py
@@ -5,6 +5,7 @@
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models.network import *
 from util.logger import Logger, logging
+from observer.steps.sync_network_deployments import *
 
 logger = Logger(level=logging.INFO)
 
@@ -16,10 +17,10 @@
         network.save()
 
     def delete_record(self, network):
-        network_deployment_deleter = NetworkDeploymentDeleter()
+        network_deployment_deleter = SyncNetworkDeployments().delete_record
         for network_deployment in NetworkDeployments.objects.filter(network=network):
             try:
-                network_deployment_deleter(network_deployment.id)    
+                network_deployment_deleter(network_deployment)    
             except Exeption,e:
                 logger.log_exc("Failed to delete network deployment %s" % network_deployment)
                 raise e
diff --git a/planetstack/openstack_observer/steps/sync_nodes.py b/planetstack/openstack_observer/steps/sync_nodes.py
index 740b5e1..d648b7d 100644
--- a/planetstack/openstack_observer/steps/sync_nodes.py
+++ b/planetstack/openstack_observer/steps/sync_nodes.py
@@ -1,12 +1,15 @@
 import os
 import base64
 import random
-from datetime import datetime 
+from datetime import datetime
 from django.db.models import F, Q
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models.node import Node
 from core.models.site import Site, Deployment
+from util.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
 
 class SyncNodes(OpenStackSyncStep):
     provides=[Node]
@@ -23,12 +26,17 @@
         nodes = Node.objects.all()
         node_hostnames  = [node.name for node in nodes]
 
-        # fetch all nodes from each deployment 
+        # fetch all nodes from each deployment
         deployments = Deployment.objects.all()
         new_nodes = []
         for deployment in deployments:
-            driver = self.driver.admin_driver(deployment=deployment.name)
-            compute_nodes = driver.shell.nova.hypervisors.list()
+            try:
+                driver = self.driver.admin_driver(deployment=deployment.name)
+                compute_nodes = driver.shell.nova.hypervisors.list()
+            except:
+                logger.log_exc("Failed to get nodes from deployment %s" % str(deployment))
+                continue
+
             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.
diff --git a/planetstack/openstack_observer/steps/sync_sites.py b/planetstack/openstack_observer/steps/sync_sites.py
index e7c645e..c560a6a 100644
--- a/planetstack/openstack_observer/steps/sync_sites.py
+++ b/planetstack/openstack_observer/steps/sync_sites.py
@@ -4,6 +4,7 @@
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models.site import Site
+from observer.steps.sync_site_deployments import *
 
 class SyncSites(OpenStackSyncStep):
     provides=[Site]
@@ -14,6 +15,6 @@
 
     def delete_record(self, site):
         site_deployments = SiteDeployments.objects.filter(site=site)
-        site_deployment_deleter = SiteDeploymentDeleter()
+        site_deployment_deleter = SyncSiteDeployments().delete_record
         for site_deployment in site_deployments:
-            site_deployment_deleter(site_deployment.id)
+            site_deployment_deleter(site_deployment)
diff --git a/planetstack/openstack_observer/steps/sync_slice_deployments.py b/planetstack/openstack_observer/steps/sync_slice_deployments.py
index 24b7459..03ea2ca 100644
--- a/planetstack/openstack_observer/steps/sync_slice_deployments.py
+++ b/planetstack/openstack_observer/steps/sync_slice_deployments.py
@@ -20,30 +20,6 @@
         if (deleted):
             return SliceDeployments.deleted_objects.all()
         else:
-            # slice deployments are not visible to users. We must ensure
-            # slices are deployed at all deploymets available to their site.
-            site_deployments = SiteDeployments.objects.all()
-            site_deploy_lookup = defaultdict(list)
-            for site_deployment in site_deployments:
-                site_deploy_lookup[site_deployment.site].append(site_deployment.deployment)
-            
-            slice_deployments = SliceDeployments.objects.all()
-            slice_deploy_lookup = defaultdict(list)
-            for slice_deployment in slice_deployments:
-                slice_deploy_lookup[slice_deployment.slice].append(slice_deployment.deployment)
-            
-            all_deployments = Deployment.objects.all() 
-            for slice in Slice.objects.all():
-                # slices are added to all deployments for now
-                expected_deployments = all_deployments
-                #expected_deployments = site_deploy_lookup[slice.site]
-                for expected_deployment in expected_deployments:
-                    if slice not in slice_deploy_lookup or \
-                       expected_deployment not in slice_deploy_lookup[slice]:
-                        sd = SliceDeployments(slice=slice, deployment=expected_deployment)
-                        sd.save()
-
-            # now we can return all slice deployments that need to be enacted   
             return SliceDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
 
     def get_next_subnet(self, deployment=None):
@@ -66,6 +42,11 @@
 
     def sync_record(self, slice_deployment):
         logger.info("sync'ing slice deployment %s" % slice_deployment)
+
+        if not slice_deployment.deployment.admin_user:
+            logger.info("deployment %r has no admin_user, skipping" % slice_deployment.deployment)
+            return
+
         if not slice_deployment.tenant_id:
             nova_fields = {'tenant_name': slice_deployment.slice.name,
                    'description': slice_deployment.slice.description,
diff --git a/planetstack/openstack_observer/steps/sync_slices.py b/planetstack/openstack_observer/steps/sync_slices.py
index c0b8abe..a6073b6 100644
--- a/planetstack/openstack_observer/steps/sync_slices.py
+++ b/planetstack/openstack_observer/steps/sync_slices.py
@@ -6,6 +6,7 @@
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models.slice import Slice, SliceDeployments
 from util.logger import Logger, logging
+from observer.steps.sync_slice_deployments import *
 
 logger = Logger(level=logging.INFO)
 
@@ -20,10 +21,10 @@
             slice_deployment.save()    
 
     def delete_record(self, slice):
-        slice_deployment_deleter = SliceDeploymentDeleter()
+        slice_deployment_deleter = SyncSliceDeployments().delete_record
         for slice_deployment in SliceDeployments.objects.filter(slice=slice):
             try:
-                slice_deployment_deleter(slice_deployment.id)
+                slice_deployment_deleter(slice_deployment)
             except Exception,e:
                 logger.log_exc("Failed to delete slice_deployment %s" % slice_deployment) 
                 raise e
diff --git a/planetstack/openstack_observer/steps/sync_sliver_ips.py b/planetstack/openstack_observer/steps/sync_sliver_ips.py
deleted file mode 100644
index d723da5..0000000
--- a/planetstack/openstack_observer/steps/sync_sliver_ips.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import os
-import base64
-from django.db.models import F, Q
-from planetstack.config import Config
-from observer.openstacksyncstep import OpenStackSyncStep
-from core.models.sliver import Sliver
-from util.logger import Logger, logging
-
-logger = Logger(level=logging.INFO)
-
-class SyncSliverIps(OpenStackSyncStep):
-    provides=[Sliver]
-    requested_interval=0
-
-    def fetch_pending(self, deleted):
-        return [] # XXX smbaker - disabling this sync_step, since sliver.ip is obsoleted by sync_network_slivers()
-
-        # Not supported yet
-        if (deleted):
-            return []
-        slivers = Sliver.objects.filter(ip=None)
-        return slivers
-
-    def sync_record(self, sliver):
-        driver = self.driver.client_driver(tenant=sliver.slice.name,
-                                           deployment=sliver.node.deployment.name)
-        servers = driver.shell.nova.servers.findall(id=sliver.instance_id)
-        if not servers:
-            return
-        server = servers[0]
-
-        # First try to grab the dedicated public address
-        # NOTE: "ext-net" is hardcoded here.
-        ip = None
-        ext_net_addrs = server.addresses.get("ext-net")

-        if ext_net_addrs:

-            ip = ext_net_addrs[0]["addr"]

-

-        # If there was no public address, then grab the first address in the

-        # list.

-        if not ip:

-            if server.addresses:

-                addrs = server.addresses.values()[0]

-                if addrs:

-                    ip = addrs[0]["addr"]
-
-        if ip and ip!=sliver.ip:
-            sliver.ip = ip
-            sliver.save()
-            logger.info("saved sliver ip: %s %s" % (sliver, ip))
diff --git a/planetstack/openstack_observer/steps/sync_slivers.py b/planetstack/openstack_observer/steps/sync_slivers.py
index 299b02f..dcedd1d 100644
--- a/planetstack/openstack_observer/steps/sync_slivers.py
+++ b/planetstack/openstack_observer/steps/sync_slivers.py
@@ -86,7 +86,8 @@
                                 hostname = sliver.node.name,
                                 pubkeys = pubkeys,
                                 nics = nics,
-                                userdata = userData )
+                                userdata = userData,
+                                flavor_name = sliver.flavor.flavor )
             sliver.instance_id = instance.id
             sliver.instance_name = getattr(instance, 'OS-EXT-SRV-ATTR:instance_name')
             sliver.save()    
diff --git a/planetstack/openstack_observer/steps/sync_user_deployments.py b/planetstack/openstack_observer/steps/sync_user_deployments.py
index 5d6ce2d..43ca260 100644
--- a/planetstack/openstack_observer/steps/sync_user_deployments.py
+++ b/planetstack/openstack_observer/steps/sync_user_deployments.py
@@ -20,46 +20,16 @@
 
         if (deleted):
             return UserDeployments.deleted_objects.all()
-
-        # user deployments are not visible to users. We must ensure
-        # user are deployed at all deploymets available to their sites.
         else:
-            deployments = Deployment.objects.all()
-            site_deployments = SiteDeployments.objects.all()
-            site_deploy_lookup = defaultdict(list)
-            for site_deployment in site_deployments:
-                site_deploy_lookup[site_deployment.site].append(site_deployment.deployment)
-
-            user_deploy_lookup = defaultdict(list)
-            for user_deployment in UserDeployments.objects.all():
-                user_deploy_lookup[user_deployment.user].append(user_deployment.deployment)
-           
-            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]
-                    # 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]: 
-                        # add new record
-                        ud = UserDeployments(user=user, deployment=expected_deployment)
-                        ud.save()
-                        #user_deployments.append(ud)
-                    #else:
-                    #    # update existing record
-                    #    ud = UserDeployments.objects.get(user=user, deployment=expected_deployment)
-                    #    user_deployments.append(ud)
-
             return UserDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None)) 
 
     def sync_record(self, user_deployment):
         logger.info("sync'ing user %s at deployment %s" % (user_deployment.user, user_deployment.deployment.name))
+
+        if not user_deployment.deployment.admin_user:
+            logger.info("deployment %r has no admin_user, skipping" % user_deployment.deployment)
+            return
+
         name = user_deployment.user.email[:user_deployment.user.email.find('@')]
         user_fields = {'name': user_deployment.user.email,
                        'email': user_deployment.user.email,
diff --git a/planetstack/openstack_observer/steps/sync_users.py b/planetstack/openstack_observer/steps/sync_users.py
index 2852b73..a22c213 100644
--- a/planetstack/openstack_observer/steps/sync_users.py
+++ b/planetstack/openstack_observer/steps/sync_users.py
@@ -6,6 +6,7 @@
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models.user import User
 from core.models.userdeployments import  UserDeployments
+from observer.steps.sync_user_deployments import SyncUserDeployments
 
 class SyncUsers(OpenStackSyncStep):
     provides=[User]
@@ -18,6 +19,6 @@
             user_deployment.save()
 
     def delete_record(self, user):
-        user_deployment_deleter = UserDeploymentDeleter()
+        user_deployment_deleter = SyncUserDeployments().delete_record
         for user_deployment in UserDeployments.objects.filter(user=user):
-            user_deployment_deleter(user_deployment.id)
+            user_deployment_deleter(user_deployment)
diff --git a/planetstack/openstack_observer/syncstep.py b/planetstack/openstack_observer/syncstep.py
index c77c8d5..ad148b5 100644
--- a/planetstack/openstack_observer/syncstep.py
+++ b/planetstack/openstack_observer/syncstep.py
@@ -4,6 +4,7 @@
 from planetstack.config import Config
 from util.logger import Logger, logging
 from observer.steps import *
+from django.db.models import F, Q
 
 logger = Logger(level=logging.INFO)
 
@@ -48,7 +49,7 @@
         # Steps should override it if they have their own logic
         # for figuring out what objects are outstanding.
         main_obj = self.provides[0]
-        if (not deleted):
+        if (not deletion):
             objs = main_obj.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
         else:
             objs = main_obj.deleted_objects.all()
@@ -59,10 +60,16 @@
     def check_dependencies(self, obj, failed):
         for dep in self.dependencies:
             peer_name = dep[0].lower() + dep[1:]    # django names are camelCased with the first letter lower
-            peer_object = getattr(obj, peer_name)
+            try:
+                peer_object = getattr(obj, peer_name)
+            except:
+                peer_object = None
+
             if (peer_object and peer_object.pk==failed.pk and type(peer_object)==type(failed)):
-                raise FailedDependency("Failed dependency for %s:%s peer %s:%s failed  %s:%s" % (obj.__class__.__name__, str(obj.pk\

-), peer_object.__class__.__name__, str(peer_object.pk), failed.__class__.__name__, str(failed.pk)))
+                if (obj.backend_status!=peer_object.backend_status):
+                    obj.backend_status = peer_object.backend_status
+                    obj.save(update_fields=['backend_status'])
+                raise FailedDependency("Failed dependency for %s:%s peer %s:%s failed  %s:%s" % (obj.__class__.__name__, str(obj.pk), peer_object.__class__.__name__, str(peer_object.pk), failed.__class__.__name__, str(failed.pk)))
 
     def call(self, failed=[], deletion=False):
         pending = self.fetch_pending(deletion)
@@ -79,14 +86,22 @@
                     o.backend_status = "OK"
                     o.save(update_fields=['enacted'])
             except Exception,e:
-                try:
-                    o.backend_status = self.error_map.map(str(e))
-                except:
-                    o.backend_status = str(e)
-
-                o.save(update_fields=['backend_status'])
-
                 logger.log_exc("sync step failed!")
+                str_e = '%r'%e
+                try:
+                    o.backend_status = self.error_map.map(str_e)
+                except:
+                    o.backend_status = str_e
+
+                # TOFIX:
+                # DatabaseError: value too long for type character varying(140)
+                if (o.pk):
+                    try:
+                        o.save(update_fields=['backend_status'])
+                    except:
+                        print "Could not update backend status field!"
+                        pass
+
                 failed.append(o)
 
         return failed
diff --git a/planetstack/planetstack-backend.py b/planetstack/planetstack-backend.py
old mode 100755
new mode 100644
index 596ecdd..7d403c5
--- a/planetstack/planetstack-backend.py
+++ b/planetstack/planetstack-backend.py
@@ -3,7 +3,12 @@
 import argparse
 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "planetstack.settings")
 from observer.backend import Backend
-from planetstack.config import Config 
+from planetstack.config import Config
+
+try:
+    from django import setup as django_setup # django 1.7
+except:
+    django_setup = False
 
 config = Config()
 
@@ -27,16 +32,19 @@
 def main():
     # Generate command line parser
     parser = argparse.ArgumentParser(usage='%(prog)s [options]')
-    parser.add_argument('-d', '--daemon', dest='daemon', action='store_true', default=False, 
+    parser.add_argument('-d', '--daemon', dest='daemon', action='store_true', default=False,
                         help='Run as daemon.')
     # smbaker: util/config.py parses sys.argv[] directly to get config file name; include the option here to avoid
     #   throwing unrecognized argument exceptions
     parser.add_argument('-C', '--config', dest='config_file', action='store', default="/opt/planetstack/plstackapi_config",
                         help='Name of config file.')
     args = parser.parse_args()
-       
+
     if args.daemon: daemon()
 
+    if django_setup: # 1.7
+        django_setup()
+
     backend = Backend()
     backend.run()    
 
diff --git a/planetstack/planetstack/settings.py b/planetstack/planetstack/settings.py
index b694373..f3f435d 100644
--- a/planetstack/planetstack/settings.py
+++ b/planetstack/planetstack/settings.py
@@ -262,4 +262,8 @@
 BIGQUERY_TABLE = getattr(config, "bigquery_table", "demoevents")
 
 DISABLE_MINIDASHBOARD = getattr(config, "gui_disable_minidashboard", False)
+ENCRYPTED_FIELDS_KEYDIR = '/opt/planetstack/private_keys'
+ENCRYPTED_FIELD_MODE = 'ENCRYPT'
 
+# prevents warnings on django 1.7                                                                                                 
+TEST_RUNNER = 'django.test.runner.DiscoverRunner'
diff --git a/planetstack/requestrouter/migrations/0001_initial.py b/planetstack/requestrouter/migrations/0001_initial.py
new file mode 100644
index 0000000..e54c7de
--- /dev/null
+++ b/planetstack/requestrouter/migrations/0001_initial.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import datetime
+import django.utils.timezone
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0002_omf_friendly_default_false'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='RequestRouterService',
+            fields=[
+                ('service_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='core.Service')),
+                ('behindNat', models.BooleanField(default=False, help_text=b"Enables 'Behind NAT' mode.")),
+                ('defaultTTL', models.PositiveIntegerField(default=30, help_text=b'DNS response time-to-live(TTL)')),
+                ('defaultAction', models.CharField(default=b'best', help_text=b'Review if this should be enum', max_length=30)),
+                ('lastResortAction', models.CharField(default=b'random', help_text=b'Review if this should be enum', max_length=30)),
+                ('maxAnswers', models.PositiveIntegerField(default=3, help_text=b'Maximum number of answers in DNS response.')),
+            ],
+            options={
+                'verbose_name': 'Request Router Service',
+            },
+            bases=('core.service', models.Model),
+        ),
+        migrations.CreateModel(
+            name='ServiceMap',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(help_text=b'name of this service map', unique=True)),
+                ('prefix', models.CharField(help_text=b'FQDN of the region of URI space managed by RR on behalf of this service', max_length=256)),
+                ('siteMap', models.FileField(help_text=b'maps client requests to service instances', upload_to=b'maps/', blank=True)),
+                ('accessMap', models.FileField(help_text=b'specifies which client requests are allowed', upload_to=b'maps/', blank=True)),
+                ('owner', models.ForeignKey(help_text=b'service which owns this map', to='core.Service')),
+                ('slice', models.ForeignKey(help_text=b'slice that implements this service', to='core.Slice')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+    ]
diff --git a/planetstack/requestrouter/migrations/__init__.py b/planetstack/requestrouter/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/requestrouter/migrations/__init__.py
diff --git a/planetstack/scripts/opencloud b/planetstack/scripts/opencloud
index daee3d6..b307e66 100755
--- a/planetstack/scripts/opencloud
+++ b/planetstack/scripts/opencloud
@@ -7,6 +7,8 @@
 
 BACKUP_DIR=/opt/planetstack_backups
 
+DJANGO_17=`python -c "import django; from distutils.version import StrictVersion; print int(StrictVersion(django.get_version()) >= StrictVersion('1.7'))"`
+
 cd /opt/planetstack
 
 function ensure_postgres_running {
@@ -44,11 +46,19 @@
 function syncdb {
     echo "Syncing OpenCloud services..."
     python /opt/planetstack/manage.py syncdb --noinput
+    if [[ $DJANGO_17 ]]; then
+        echo "Loading initial data from fixture..."
+        python /opt/planetstack/manage.py loaddata /opt/planetstack/core/fixtures/initial_data.json
+    fi
 }
 function evolvedb {
-    echo "Syncing OpenCloud services..."
+    echo "Evolving OpenCloud services..."
     python /opt/planetstack/manage.py evolve --hint --execute --noinput
 }
+function migratedb {
+    echo "Migrating OpenCloud services..."
+    python /opt/planetstack/manage.py migrate
+}
 function stopserver {
     echo "Stopping any running OpenCloud Service(s)"
     pkill -f "python.*runserver"
@@ -78,6 +88,19 @@
     ln -s $FN $BACKUP_DIR/dumpdata-latest.json
 }
 
+function genkeys {
+    mkdir -p public_keys
+    mkdir -p private_keys
+    echo "Generating keys"
+	keyczart create --location=private_keys --name="OpenCloud" --purpose=crypt --asymmetric=rsa
+	keyczart addkey --location=private_keys --status=primary --size=1024
+	keyczart pubkey --location=private_keys --destination=public_keys
+    if [[ ! -f public_keys/1 ]]; then
+        echo "FAILED to create keys"
+        exit
+    fi
+}
+
 COMMAND=$1
 
 if [ "$COMMAND" = "initdb" ]; then
@@ -111,10 +134,14 @@
     createdb
     syncdb
 fi
-if [ "$COMMAND" = "evolvedb" ]; then
+if [ "$COMMAND" = "evolvedb" -o "$COMMAND" = "migratedb" ]; then
     stopserver
     ensure_postgres_running
-    evolvedb
+    if [[ $DJANGO_17 ]]; then
+        migratedb
+    else
+        evolvedb
+    fi
 fi
 if [ "$COMMAND" = "resetdb" ]; then
     stopserver
@@ -136,3 +163,6 @@
 if [ "$COMMAND" = "dumpdata" ]; then
     dumpdata
 fi
+if [ "$COMMAND" = "genkeys" ]; then
+    genkeys
+fi
diff --git a/planetstack/syndicate_storage/migrations/0001_initial.py b/planetstack/syndicate_storage/migrations/0001_initial.py
new file mode 100644
index 0000000..07cbf97
--- /dev/null
+++ b/planetstack/syndicate_storage/migrations/0001_initial.py
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import datetime
+import syndicate_storage.models
+from django.conf import settings
+import django.utils.timezone
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0002_omf_friendly_default_false'),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='SliceSecret',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('secret', syndicate_storage.models.ObserverSecretValue(help_text=b"Shared secret between OpenCloud and this slice's Syndicate daemons.", blank=True)),
+                ('slice_id', models.ForeignKey(to='core.Slice')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SyndicatePrincipal',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('principal_id', models.TextField(unique=True)),
+                ('public_key_pem', models.TextField()),
+                ('sealed_private_key', models.TextField()),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SyndicateService',
+            fields=[
+                ('service_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='core.Service')),
+            ],
+            options={
+                'verbose_name': 'Syndicate Service',
+                'verbose_name_plural': 'Syndicate Service',
+            },
+            bases=('core.service', models.Model),
+        ),
+        migrations.CreateModel(
+            name='Volume',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'Human-readable, searchable name of the Volume', max_length=64)),
+                ('description', models.TextField(help_text=b'Human-readable description of what this Volume is used for.', max_length=130, null=True, blank=True)),
+                ('blocksize', models.PositiveIntegerField(help_text=b'Number of bytes per block.')),
+                ('private', models.BooleanField(default=True, help_text=b'Indicates if the Volume is visible to users other than the Volume Owner and Syndicate Administrators.')),
+                ('archive', models.BooleanField(default=False, help_text=b'Indicates if this Volume is read-only, and only an Aquisition Gateway owned by the Volume owner (or Syndicate admin) can write to it.')),
+                ('cap_read_data', models.BooleanField(default=True, help_text=b'VM can read Volume data')),
+                ('cap_write_data', models.BooleanField(default=True, help_text=b'VM can write Volume data')),
+                ('cap_host_data', models.BooleanField(default=True, help_text=b'VM can host Volume data')),
+                ('owner_id', models.ForeignKey(verbose_name=b'Owner', to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='VolumeAccessRight',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('cap_read_data', models.BooleanField(default=True, help_text=b'VM can read Volume data')),
+                ('cap_write_data', models.BooleanField(default=True, help_text=b'VM can write Volume data')),
+                ('cap_host_data', models.BooleanField(default=True, help_text=b'VM can host Volume data')),
+                ('owner_id', models.ForeignKey(verbose_name=b'user', to=settings.AUTH_USER_MODEL)),
+                ('volume', models.ForeignKey(to='syndicate_storage.Volume')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='VolumeSlice',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('cap_read_data', models.BooleanField(default=True, help_text=b'VM can read Volume data')),
+                ('cap_write_data', models.BooleanField(default=True, help_text=b'VM can write Volume data')),
+                ('cap_host_data', models.BooleanField(default=True, help_text=b'VM can host Volume data')),
+                ('UG_portnum', models.PositiveIntegerField(help_text=b'User Gateway port.  Any port above 1024 will work, but it must be available slice-wide.', verbose_name=b'UG port')),
+                ('RG_portnum', models.PositiveIntegerField(help_text=b'Replica Gateway port.  Any port above 1024 will work, but it must be available slice-wide.', verbose_name=b'RG port')),
+                ('credentials_blob', models.TextField(help_text=b'Encrypted slice credentials, sealed with the slice secret.', null=True, blank=True)),
+                ('slice_id', models.ForeignKey(verbose_name=b'Slice', to='core.Slice')),
+                ('volume_id', models.ForeignKey(verbose_name=b'Volume', to='syndicate_storage.Volume')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AddField(
+            model_name='volume',
+            name='slice_id',
+            field=models.ManyToManyField(to='core.Slice', through='syndicate_storage.VolumeSlice'),
+            preserve_default=True,
+        ),
+    ]
diff --git a/planetstack/syndicate_storage/migrations/__init__.py b/planetstack/syndicate_storage/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/syndicate_storage/migrations/__init__.py
diff --git a/planetstack/templates/admin/core/slice/change_form.html b/planetstack/templates/admin/core/slice/change_form.html
index c94b580..31f09c0 100644
--- a/planetstack/templates/admin/core/slice/change_form.html
+++ b/planetstack/templates/admin/core/slice/change_form.html
@@ -1,5 +1,5 @@
 {% extends 'admin/change_form.html' %}
-{% block extrahead %} 
+{% block extrahead %}
 {{ block.super }} 
 <script>
 deployment_nodes = [
@@ -8,17 +8,124 @@
 {% endfor %}
 ];
 
-function update_nodes(deployment_select, node_select_id) {
+deployment_flavors = [
+{% for dn in deployment_flavors %}
+   [{{ dn.0 }}, {{ dn.1 }} , "{{ dn.2 }}"],
+{% endfor %}
+];
+
+deployment_images = [
+{% for dn in deployment_images %}
+   [{{ dn.0 }}, {{ dn.1 }} , "{{ dn.2 }}"],
+{% endfor %}
+];
+
+site_login_bases = [
+{% for s in site_login_bases %}
+  [{{ s.0 }}, "{{ s.1 }}"],
+{% endfor %}
+];
+
+function option_html(val, text, selected) {
+    if (selected) {
+        return '<option value="' + val + '" selected>' + text + '</option>\n';
+    } else {
+        return '<option value="' + val + '">' + text + '</option>\n';
+    }
+}
+
+function update_nodes(deployment_select, flavor_select, node_select) {
     deployment_id = $(deployment_select).val();
-    html = "<option value=''>---------</option>\n";
+    node_id = $(node_select).val();
+    flavor_name = $(flavor_select).children(":selected").text()
+    html="";
     for (i in deployment_nodes) {
+        // this is for EC2, where the node hostnames imply the flavor.
         dn = deployment_nodes[i];
-        if (dn[0] == deployment_id) {
-            html = html + '<option value="' + dn[1] + '">' + dn[2] + '</option>\n'
+        if ((dn[0] == deployment_id) && (dn[2].lastIndexOf(flavor_name,0) === 0)) {
+            html = html + option_html(dn[1], dn[2], dn[1]==node_id);
         }
     }
-    //console.log(html);
-    $("#"+node_select_id).empty().append(html);
+    if (!html) {
+        // now try it without the flavor hostname prefix matching
+        for (i in deployment_nodes) {
+            dn = deployment_nodes[i];
+            if (dn[0] == deployment_id) {
+                html = html + option_html(dn[1], dn[2], dn[1]==node_id);
+            }
+        }
+    }
+    html = "<option value=''>---------</option>\n" + html;
+    node_select.empty().append(html);
+}
+
+function update_flavors(deployment_select, flavor_select) {
+    deployment_id = $(deployment_select).val();
+    flavor_id = $(flavor_select).val();
+    html = "<option value=''>---------</option>\n";
+    for (i in deployment_flavors) {
+        dn = deployment_flavors[i];
+        if (dn[0] == deployment_id) {
+            html = html + option_html(dn[1], dn[2], dn[1] == flavor_id);
+        }
+    }
+    flavor_select.empty().append(html);
+}
+
+function update_images(deployment_select, image_select) {
+    deployment_id = $(deployment_select).val();
+    image_id = $(image_select).val();
+    html = "<option value=''>---------</option>\n";
+    for (i in deployment_images) {
+        dn = deployment_images[i];
+        if (dn[0] == deployment_id) {
+            html = html + option_html(dn[1], dn[2], dn[1] == image_id);
+        }
+    }
+    image_select.empty().append(html);
+}
+
+function sliver_deployment_changed(any_control) {
+   /* This function handles someone changing the deploymentNetwork control
+      in the add-sliver line. It updats the flavors and nodes dialogs
+      accordingly.
+   */
+
+   /* the inscrutable jquery selector below says:
+      find the closest parent "tr" to the current element
+      then find the child with class "field-deploymentNetwork"
+      then find the child with that is a select
+      then return it's id
+      then turn it into a jquery object
+    */
+    deployment_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-deploymentNetwork select')[0].id);
+    node_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-node select')[0].id);
+    flavor_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-flavor select')[0].id);
+    image_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-image select')[0].id);
+    update_nodes(deployment_select, flavor_select, node_select);
+    update_flavors(deployment_select, flavor_select);
+    update_images(deployment_select, image_select);
+}
+
+function sliver_flavor_changed(any_control) {
+    /* this is like sliver_flavor changed, but does not update the flavors
+       control
+    */
+    deployment_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-deploymentNetwork select')[0].id);
+    node_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-node select')[0].id);
+    flavor_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-flavor select')[0].id);
+    update_nodes(deployment_select, flavor_select, node_select);
+}
+
+function update_slice_prefix(site_select, slice_name_id) {
+    site_id = $(site_select).val();
+    slice_prefix="";
+    for (i in site_login_bases) {
+        if (site_login_bases[i][0] == site_id) {
+            slice_prefix=site_login_bases[i][1]+"_";
+        }
+    }
+    $("#"+slice_name_id).val(slice_prefix); 
 }
 </script>
 
diff --git a/planetstack/templates/admin/dashboard/tenant.html b/planetstack/templates/admin/dashboard/tenant.html
index bf49471..9560807 100644
--- a/planetstack/templates/admin/dashboard/tenant.html
+++ b/planetstack/templates/admin/dashboard/tenant.html
@@ -18,6 +18,16 @@
 		</fieldset>
 	</form>
 </div>
+<div id="add-user-form" title="Add User" style="display: none;">
+        <form>
+                <fieldset>
+			<div class="create-slice-row">
+                                <label for="add-slice-user">Add User</label>
+                                <select id="add-slice-user" class="tenant-create-slice"></select>
+                        </div>
+                </fieldset>
+        </form>
+</div>
 <div id="create-slice-form" title="Create New Slice" style="display: none;">
 	<form>
 		<fieldset>
@@ -42,7 +52,11 @@
 				<input type="checkbox" name="checkbox" id="private-vol" value="value">
 			</div>
 			<div class="create-slice-row">
-                                <label for="mount-data-sets">Data Sets</label>
+                                <label for="add-user">Add User</label>
+                                <select id="add-user" class="tenant-create-slice"></select>
+                        </div>
+			<div class="create-slice-row">
+                                <label for="mount-data-sets">Data Set</label>
                                 <select id="mount-data-sets" class="tenant-create-slice"></select>
                         </div>
 			<div class="create-slice-row">
@@ -182,7 +196,7 @@
                                 $("#adv-service-level-dropdown").append("<option>" + serviceLevelData[row]['serviceClass'] + "</option>");
                         }
                         for (row in imageData) {
-                                $("#adv-image-dropdown").append("<option>" + imageData[row]['Image'] + "</option>");
+                                $("#adv-image-dropdown").append("<option>" + imageData[row] + "</option>");
                         }
                         for (row in dataSet) {
                                 $("#adv-dataset-dropdown").append("<option>" + dataSet[row]['DataSet'] + "</option>");
@@ -200,9 +214,11 @@
 				}
 			}
 			for (row in siteRows) {
-				var entry = siteRows[row]['siteName'];
+				//var entry = siteRows[row]['siteName'];
+				var entry = siteRows[row];
 				if (!(entry in tableData)) {
-					tableData[siteRows[row]['siteName']] = 0;
+					//tableData[siteRows[row]['siteName']] = 0;
+					tableData[siteRows[row]] = 0;
 				}
 			}
 			for (row in tableData) {
@@ -224,6 +240,7 @@
 								siteName: newRow,
 								count: newTableData[newRow] - tableData[newRow],
 								slice: $("#advTenantSliceDropDown").val(),
+								image: $("#adv-image-dropdown").val(),
 								actionToDo: "add",
 								csrfmiddlewaretoken: "{{ csrf_token }}", // < here 
 								state: "inactive"
@@ -242,6 +259,7 @@
 								siteName: newRow,
 								count: tableData[newRow] - newTableData[newRow],
 								slice: $("#advTenantSliceDropDown").val(),
+								image: $("#adv-image-dropdown").val(),
 								actionToDo: "rem",
 								csrfmiddlewaretoken: "{{ csrf_token }}", // < here
 								state: "inactive"
@@ -333,14 +351,14 @@
 			}
 		}
 
-		function UserSliceTable(rows,imageData,serviceLevelData,siteRows,dataSet) {
+		function UserSliceTable(rows,imageData,serviceLevelData,siteRows,dataSet,siteUsers) {
 				//Add check for #dynamicusersliceinfo_filter label-> input having focus here
 				$("<div></div>").attr('id', 'tenantSliceDataWrapper').appendTo('#tabs-5');
 				$("<div></div>").attr('id', 'advancedTenantSliceDataWrapper').appendTo('#tabs-5');
 				var sliceData = '';
 				sliceData += '<div class="tenant-row public-key-warning"><span class="summary-attr">You have not uploaded your Public Key. <a href="http://{{ request.get_host}}/admin/core/user/{{user.id}}">Click here</a> to upload it now.</span></div><div class="tenant-row"><span class="summary-attr"><b>Slice Name:</b> <span id="slice-name-value"> </span> </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Service Level:</b> <span id="service-level-value"> </span>  </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Image:</b> <span id="slice-image-value"> </span>  </span><br></div><div class="btn btn-high btn-info" id="advanced-tenant">Go to Advanced View</div>';
 				var advSliceData = '';
-				advSliceData += '<div class="tenant-row public-key-warning"><span class="summary-attr">You have not uploaded your Public Key. <a href="http://{{ request.get_host}}/admin/core/user/{{user.id}}">Click here</a> to upload it now.</span></div><div class="adv-tenant-row"><span class="summary-attr"><b>Slice Name:</b> <span id="adv-slice-name-value"> </span> </span><br><br></div><div class="tenant-row"><span class="summary-attr"><b>Service Level:</b> <span id="adv-service-level-value"> </span> <span class="help-inline">Changes are potentially disruptive to existing slivers</span> </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Image:</b> <span id="adv-slice-image-value"> </span><span class="help-inline">Changes are potentially disruptive to existing slivers</span>  </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Network:</b> <input type="text" name="adv-network-value" id="adv-network-value"> <span class="help-inline">List of port ranges(if any) e.g. 1021-1026,1029</span><br></div><div class="tenant-row"><span class="summary-attr"><b>Data Sets:</b> <span id="adv-slice-data-set-value"> </span>  <input type="checkbox" name="checkbox" id="private-vol-checkbox" value="value"><span class="help-inline">Include Private Volume</span></span></div>';
+				advSliceData += '<div class="tenant-row public-key-warning"><span class="summary-attr">You have not uploaded your Public Key. <a href="http://{{ request.get_host}}/admin/core/user/{{user.id}}">Click here</a> to upload it now.</span></div><div class="adv-tenant-row"><span class="summary-attr"><b>Slice Name:</b> <span id="adv-slice-name-value"> </span> </span><br><br></div><div class="tenant-row"><span class="summary-attr"><b>Service Level:</b> <span id="adv-service-level-value"> </span> <span class="help-inline">Changes are potentially disruptive to existing slivers</span> </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Image:</b> <span id="adv-slice-image-value"> </span><span class="help-inline">Changes are potentially disruptive to existing slivers</span>  </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Network:</b> <input type="text" name="adv-network-value" id="adv-network-value"> <span class="help-inline">List of port ranges(if any) e.g. 1021-1026,1029</span><br></div><div class="tenant-row"><span class="summary-attr"><b>Data Set:</b> <span id="adv-slice-data-set-value"> </span>  <input type="checkbox" name="checkbox" id="private-vol-checkbox" value="value"><span class="help-inline">Include Private Volume</span></span></div>';
 				$('#tenantSliceDataWrapper').append(sliceData).css("display", "none");
 				$('#advancedTenantSliceDataWrapper').append(advSliceData);
 				$("#advancedTenantSliceDataWrapper").css("display", "none");
@@ -356,6 +374,7 @@
 				$("<div></div>").attr('id', 'advTenantSiteTable').appendTo('#tabs-5').css("display", "none");
 				$('<div class="btn btn-success" id="create-slice-btn"><i class="icon-plus-sign icon-white"></i>&nbsp;Create New Slice</div>').appendTo("#tabs-5");
 				$('<div class="btn btn-success" id="delete-slice-btn"><i class="icon-plus-sign icon-white"></i>&nbsp;Delete a Slice</div>').appendTo("#tabs-5");
+				$('<div class="btn btn-success" id="add-user-btn"><i class="icon-plus-sign icon-white"></i>&nbsp;Add User</div>').appendTo("#tabs-5");
 				$('<div class="btn btn-high btn-info" id="download-details">Download Slice Details</div>').appendTo("#tabs-5");
 				$('<div class="btn btn-success" id="sliver-btn"><i class="icon-plus-sign icon-white"></i>&nbsp;Add/Remove Slivers</div>').appendTo("#tabs-5");
 				$('<div class="btn btn-high btn-info" id="save-btn">Save</div>').appendTo("#tabs-5").css("display", "none");
@@ -386,6 +405,7 @@
 								data: {
 									count: parseInt($("#numOfSlivers").val()),
 									slice: $("#tenantSliceDropDown").val(),
+									image: $("#slice-image-value").html(),
 									actionToDo: "add",
 									csrfmiddlewaretoken: "{{ csrf_token }}", // < here 
 									state: "inactive"
@@ -412,6 +432,7 @@
 								data: {
 									count: parseInt($("#numOfSlivers").val()),
 									slice: $("#tenantSliceDropDown").val(),
+									image: $("#slice-image-value").html(),
 									actionToDo: "rem",
 									csrfmiddlewaretoken: "{{ csrf_token }}", // < here
 									state: "inactive"
@@ -436,26 +457,69 @@
 				});
 				$("#dialog-form").dialog("open");
 			});
+			$("#add-user-btn").unbind().click(function(){
+				$("#add-slice-user").empty();
+				for (row in siteUsers) {
+                                        $("#add-slice-user").append("<option>" + siteUsers[row] + "</option>");
+                                }
+				$("#add-user-form").dialog({
+                                        autoOpen: false,
+                                        height: 200,
+                                        width: 350,
+                                        modal: true,
+                                        dialogClass: "tenantDialog",
+                                        buttons: {
+                                                "Submit": function () {
+                                                        $.ajax({
+                                                                url: '/adduser/',
+                                                                dataType: 'json',
+                                                                data: {
+                                                                        sliceName: $("#advTenantSliceDropDown").val(),
+                                                                        userEmail: $("#add-slice-user").val(),
+                                                                        csrfmiddlewaretoken: "{{ csrf_token }}", // < here
+                                                                        state: "inactive"
+                                                                },
+                                                                async: false,
+                                                                type: 'POST',
+                                                                success: function () {
+                                                                        location.reload();
+                                                                }
+
+                                                        });
+                                                },
+                                                Cancel: function () {
+                                                        $(this).dialog("close");
+                                                }
+                                        }
+                                });
+                                $("#add-user-form").dialog("open");
+							
+
+			});
 			$("#create-slice-btn").unbind().click(function () {
 				$("#new-service-class").empty();
 				$("#new-image").empty();
+				$("#add-user").empty();
 				$("#mount-data-sets").empty();
 				$("#new-network").empty();
 				for (row in serviceLevelData) {
 					$("#new-service-class").append("<option>" + serviceLevelData[row]['serviceClass'] + "</option>");
 				}
 				for (row in imageData) {
-					$("#new-image").append("<option>" + imageData[row]['Image'] + "</option>");
+					$("#new-image").append("<option>" + imageData[row] + "</option>");
 				}
 				for (row in dataSet) {
                                         $("#mount-data-sets").append("<option>" + dataSet[row]['DataSet'] + "</option>");
                                 }
+				for (row in siteUsers) {
+                                        $("#add-user").append("<option>" + siteUsers[row] + "</option>");
+                                }
 				var nameOfSlice = $("#new-slice-name").val();
 				var nameOfServiceClass = $("#new-service-class").val();
 				var nameOfImage = $("#new-image").val();
 				$("#create-slice-form").dialog({
 					autoOpen: false,
-					height: 400,
+					height: 420,
 					width: 400,
 					modal: true,
 					dialogClass: "tenantDialog",
@@ -471,6 +535,7 @@
 									network: $("#new-network").val(),
 									privateVolume: $("#private-vol").is(":checked"),
 									mountDataSets: $("#mount-data-sets").val(),
+									userEmail: $("#add-user").val(),
 									actionToDo: "add",
 									csrfmiddlewaretoken: "{{ csrf_token }}", // < here 
 									state: "inactive"
@@ -495,6 +560,7 @@
                                                                 data: {
                                                                         count: parseInt($("#number-of-slivers").val()),
                                                                         slice: $("#new-slice-name").val(),
+									image: $("#new-image").val(),
                                                                         actionToDo: "add",
                                                                         csrfmiddlewaretoken: "{{ csrf_token }}", // < here
                                                                         state: "inactive"
@@ -563,9 +629,11 @@
 				var imageData = data['image']['rows'];
 				//var networkData = data['network']['rows'];
 				var serviceLevelData = data['sliceServiceClass']['rows'];
-				var siteRows = data['sites']['rows'];
+				//var siteRows = data['sites']['rows'];
+				var siteRows = data['availableSites']['rows'];
 				var dataSet = data['mountDataSets']['rows'];
-				UserSliceTable(rows,imageData,serviceLevelData,siteRows,dataSet);
+				var siteUsers = data['siteUsers'];
+				UserSliceTable(rows,imageData,serviceLevelData,siteRows,dataSet,siteUsers);
 				if(!(data['publicKey'])){
 					$(".public-key-warning").css("display","block");
 				}
@@ -574,6 +642,14 @@
 				$("#tooltip").css("display", "none");
 				$("#basic-tooltip").css("display", "none");
 				$("#adv-tooltip").css("display", "none");
+				if(!(data['role']=="pi"||data['role']=="admin")){
+					$("#create-slice-btn").off();
+					$("#create-slice-btn").css('background','grey');
+					$("#delete-slice-btn").off();
+					$("#delete-slice-btn").css('background','grey');
+					$("#add-user-btn").off();
+                                        $("#add-user-btn").css('background','grey');
+				}
 			},
 			complete: function () {}
 		});
diff --git a/planetstack/tools/get_instance_ip.py b/planetstack/tools/get_instance_ip.py
index c227e2e..b3e4502 100644
--- a/planetstack/tools/get_instance_ip.py
+++ b/planetstack/tools/get_instance_ip.py
@@ -21,8 +21,13 @@
     return r.json()[0]["id"]
 
 def get_node_id(host_name):
-    r = requests.get(NODES_API + "?name=%s" % host_name, auth=opencloud_auth)
-    return r.json()[0]["id"]
+     r = requests.get(NODES_API)
+     nodes = r.json()
+     for node in nodes:
+         if node["name"].lower() == host_name.lower():
+             return node["id"]
+     print >> sys.stderr, "Error: failed to find node %s" % host_name
+     sys.exit(-1)
 
 def get_slivers(slice_id=None, node_id=None):
     queries = []
diff --git a/planetstack/tools/get_instance_name.py b/planetstack/tools/get_instance_name.py
index a0b55d2..01fc841 100644
--- a/planetstack/tools/get_instance_name.py
+++ b/planetstack/tools/get_instance_name.py
@@ -18,8 +18,15 @@
     return r.json()[0]["id"]
 
 def get_node_id(host_name):
-    r = requests.get(NODES_API + "?name=%s" % host_name, auth=opencloud_auth)
-    return r.json()[0]["id"]
+#    r = requests.get(NODES_API + "?name=%s" % host_name, auth=opencloud_auth)
+#    return r.json()[0]["id"]
+     r = requests.get(NODES_API)
+     nodes = r.json()
+     for node in nodes:
+         if node["name"].lower() == host_name.lower():
+             return node["id"]
+     print >> sys.stderr, "Error: failed to find node %s" % host_name
+     sys.exit(-1)
 
 def get_slivers(slice_id=None, node_id=None):
     queries = []