allow openstack fields to contain null/blank values. separate User.is_admin from User.is_staff. expose User.is_admin on mdole admin form
diff --git a/plstackapi/core/models/key.py b/plstackapi/core/models/key.py
index afbebff..aa31599 100644
--- a/plstackapi/core/models/key.py
+++ b/plstackapi/core/models/key.py
@@ -6,8 +6,7 @@
 # Create your models here.
 
 class Key(PlCoreBase):
-    name = models.CharField(max_length=256, unique=True)
-    key_id = models.CharField(max_length=256, unique=True)
+    key_id = models.CharField(null=True, blank=True, max_length=256, unique=True)
     key = models.CharField(max_length=512)
     type = models.CharField(max_length=256)
     blacklisted = models.BooleanField(default=False)
diff --git a/plstackapi/core/models/pluser.py b/plstackapi/core/models/pluser.py
index b64f223..6688cfe 100644
--- a/plstackapi/core/models/pluser.py
+++ b/plstackapi/core/models/pluser.py
@@ -55,7 +55,7 @@
         db_index=True,
     )
 
-    user_id = models.CharField(help_text="keystone user id", max_length=200) 
+    user_id = models.CharField(null=True, blank=True, help_text="keystone user id", max_length=200) 
     firstname = models.CharField(help_text="person's given name", max_length=200)
     lastname = models.CharField(help_text="person's surname", max_length=200)
 
@@ -64,7 +64,7 @@
     site = models.ForeignKey(Site, related_name='users', verbose_name="Site this user will be homed too", null=True)
 
     is_active = models.BooleanField(default=True)
-    is_admin = models.BooleanField(default=True)
+    is_admin = models.BooleanField(default=False)
     is_staff = models.BooleanField(default=True)
 
     objects = PLUserManager()
@@ -93,13 +93,6 @@
         # Simplest possible answer: Yes, always
         return True
 
-    @property
-    def is_staff(self):
-        "Is the user a member of staff?"
-        # Simplest possible answer: All admins are staff
-        return self.is_admin
-
-
     def save(self, *args, **kwds):
         if not hasattr(self, 'os_manager'):
             setattr(self, 'os_manager', OpenStackManager())
diff --git a/plstackapi/core/models/site.py b/plstackapi/core/models/site.py
index f23ef3f..cba70f4 100644
--- a/plstackapi/core/models/site.py
+++ b/plstackapi/core/models/site.py
@@ -6,7 +6,7 @@
 
 class Site(PlCoreBase):
 
-    tenant_id = models.CharField(max_length=200, help_text="Keystone tenant id")
+    tenant_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")
     name = models.CharField(max_length=200, help_text="Name for this Site")
     site_url = models.URLField(null=True, blank=True, max_length=512, help_text="Site's Home URL Page")
     enabled = models.BooleanField(default=True, help_text="Status for this Site")
diff --git a/plstackapi/core/models/slice.py b/plstackapi/core/models/slice.py
index 024c41c..f29d93a 100644
--- a/plstackapi/core/models/slice.py
+++ b/plstackapi/core/models/slice.py
@@ -15,9 +15,9 @@
     description=models.TextField(blank=True,help_text="High level description of the slice and expected activities", max_length=1024)
     slice_url = models.URLField(blank=True, max_length=512)
     site = models.ForeignKey(Site, related_name='slices', help_text="The Site this Node belongs too")
-    network_id = models.CharField(max_length=256, help_text="Quantum network")
-    router_id = models.CharField(max_length=256, help_text="Quantum router id")
-    subnet_id = models.CharField(max_length=256, help_text="Quantum subnet id")
+    network_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network")
+    router_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum router id")
+    subnet_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum subnet id")
 
     SVC_CLASS_CHOICES = (('besteffort', 'Best Effort'), ('silver', 'Silver'), ('gold','Gold'))
     serviceClass = models.CharField(verbose_name="Service Class",default="besteffort",help_text="The Service Class of this slice", max_length=30, choices=SVC_CLASS_CHOICES)
diff --git a/plstackapi/core/models/sliver.py b/plstackapi/core/models/sliver.py
index 5cb73d8..7a2fbed 100644
--- a/plstackapi/core/models/sliver.py
+++ b/plstackapi/core/models/sliver.py
@@ -11,7 +11,7 @@
 
 # Create your models here.
 class Sliver(PlCoreBase):
-    instance_id = models.CharField(max_length=200, help_text="Nova instance id")    
+    instance_id = models.CharField(null=True, blank=True, max_length=200, help_text="Nova instance id")    
     name = models.CharField(max_length=200, help_text="Sliver name")
     instance_name = models.CharField(blank=True, null=True, max_length=200, help_text="OpenStack generated name")
     ip = models.GenericIPAddressField(help_text="Sliver ip address", blank=True, null=True)
diff --git a/plstackapi/openstack/manager.py b/plstackapi/openstack/manager.py
index f991676..86ad014 100644
--- a/plstackapi/openstack/manager.py
+++ b/plstackapi/openstack/manager.py
@@ -58,7 +58,7 @@
     @require_enabled
     def save_key(self, key):
         if not key.key_id:
-            key_fields = {'name': key.name,
+            key_fields = {'name': key.user.email[:key.user.email.find('@')],
                           'key': key.key}
             nova_key = self.driver.create_keypair(**key_fields)
             key.key_id = nova_key.id        
@@ -80,10 +80,11 @@
             user.user_id = keystone_user.id
         if user.site:
             if user.is_admin:
-                role = 'admin'
+                self.driver.add_user_role(user.user_id, user.site.tenant_id, 'admin')
             else:
-                role = 'user'       
-            self.driver.add_user_role(user.user_id, user.site.tenant_id, role)
+                # may have admin role so attempt to remove it
+                self.driver.remove_user_role(user.user_id, user.site.tenant_id, 'admin')
+                self.driver.add_user_role(user.user_id, user.site.tenant_id, 'user')
   
     @require_enabled
     def delete_user(self, user):