Merged with Tony's changes -- added numberCores to SliverAdmins
authorSiobhan Tully <stully@verivue.com>
Thu, 2 May 2013 10:02:36 +0000 (06:02 -0400)
committerSiobhan Tully <stully@verivue.com>
Thu, 2 May 2013 10:02:36 +0000 (06:02 -0400)
19 files changed:
config/plstackapi_config
plstackapi/core/admin.py
plstackapi/core/api/auth.py
plstackapi/core/api/flavors.py [deleted file]
plstackapi/core/api/slivers.py
plstackapi/core/api_root.py
plstackapi/core/models/__init__.py
plstackapi/core/models/flavor.py [deleted file]
plstackapi/core/models/pluser.py
plstackapi/core/models/role.py
plstackapi/core/models/sliver.py
plstackapi/core/serializers.py
plstackapi/core/urls.py
plstackapi/core/views/flavors.py [deleted file]
plstackapi/core/views/slivers.py
plstackapi/openstack/driver.py
plstackapi/openstack/manager.py
plstackapi/openstack/siteagent.py [new file with mode: 0644]
plstackapi/plstackapi-debug-server.py

index cf02ee7..1d7b761 100644 (file)
@@ -17,6 +17,7 @@ ca_ssl_cert=None
 ratelimit_enabled=0
 omf_enabled=0
 mail_support_address=support@localhost
+nova_enabled=True
 
 [nova]
 admin_user=admin@domain.com
index 3a40bca..4bb9a98 100644 (file)
@@ -1,5 +1,6 @@
 from plstackapi.core.models import Site
 from plstackapi.core.models import *
+from plstackapi.openstack.manager import OpenStackManager
 from plstackapi.openstack.driver import OpenStackDriver
 from plstackapi.openstack.client import OpenStackClient
 
@@ -31,7 +32,7 @@ class ReadonlyTabularInline(admin.TabularInline):
 
 class SliverInline(admin.TabularInline):
     model = Sliver
-    fields = ['ip', 'name', 'slice', 'flavor', 'image', 'key', 'node', 'deploymentNetwork']
+    fields = ['ip', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
     extra = 0
 
 class SiteInline(admin.TabularInline):
@@ -63,6 +64,7 @@ class PlanetStackBaseAdmin(admin.ModelAdmin):
 
 class OSModelAdmin(PlanetStackBaseAdmin):
     """Attach client connection to openstack on delete() and save()""" 
+
     def save_model(self, request, obj, form, change):
         client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
         obj.driver = OpenStackDriver(client=client)
@@ -75,12 +77,24 @@ class OSModelAdmin(PlanetStackBaseAdmin):
         obj.caller = request.user
         obj.delete()
 
-class RoleAdmin(OSModelAdmin):
+class RoleAdmin(PlanetStackBaseAdmin):
     fieldsets = [
         ('Role', {'fields': ['role_type']})
     ]
     list_display = ('role_type',)
 
+    def save_model(self, request, obj, form, change):
+        auth = request.session.get('auth', {})
+        auth['tenant'] = request.user.site.login_base
+        obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+        obj.save()
+
+    def delete_model(self, request, obj):
+        auth = request.session.get('auth', {})
+        auth['tenant'] = request.user.site.login_base
+        obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+        obj.delete()
+
 class DeploymentNetworkAdminForm(forms.ModelForm):
     sites = forms.ModelMultipleChoiceField(
         queryset=Site.objects.all(),
@@ -113,6 +127,17 @@ class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
     form = DeploymentNetworkAdminForm
     inlines = [NodeInline,]
 
+    def get_formsets(self, request, obj=None):
+        for inline in self.get_inline_instances(request, obj):
+            # hide MyInline in the add view
+            if obj is None:
+                continue
+            # give inline object access to driver and caller
+            client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
+            inline.model.driver = OpenStackDriver(client=client)
+            inline.model.caller = request.user
+            yield inline.get_formset(request, obj)
+
 class SiteAdmin(OSModelAdmin):
     fieldsets = [
         (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
@@ -124,6 +149,17 @@ class SiteAdmin(OSModelAdmin):
     inlines = [NodeInline,]
     search_fields = ['name']
 
+    def get_formsets(self, request, obj=None):
+        for inline in self.get_inline_instances(request, obj):
+            # hide MyInline in the add view
+            if obj is None:
+                continue
+            # give inline object access to driver and caller
+            client = OpenStackClient(tenant=request.user.site.login_base, **request.session.get('auth', {}))
+            inline.model.driver = OpenStackDriver(client=client)
+            inline.model.caller = request.user
+            yield inline.get_formset(request, obj)
+
 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
     fieldsets = [
         (None, {'fields': ['user', 'site', 'role']})
@@ -164,6 +200,17 @@ class SliceAdmin(OSModelAdmin):
     list_display = ('name', 'site','serviceClass', 'slice_url', 'instantiation')
     inlines = [SliverInline]
 
+    def get_formsets(self, request, obj=None):
+        for inline in self.get_inline_instances(request, obj):
+            # hide MyInline in the add view
+            if obj is None:
+                continue
+            # give inline object access to driver and caller
+            client = OpenStackClient(tenant=obj.name, **request.session.get('auth', {}))
+            inline.model.driver = OpenStackDriver(client=client)
+            inline.model.caller = request.user
+            yield inline.get_formset(request, obj)
+
     def get_queryset(self, request):
         qs = super(SliceAdmin, self).get_queryset(request)
         if request.user.is_superuser:
@@ -228,9 +275,9 @@ class SliverForm(forms.ModelForm):
 class SliverAdmin(PlanetStackBaseAdmin):
     form = SliverForm
     fieldsets = [
-        ('Sliver', {'fields': ['ip', 'name', 'slice', 'numberCores', 'flavor', 'image', 'key', 'node', 'deploymentNetwork']})
+        ('Sliver', {'fields': ['ip', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
     ]
-    list_display = ['ip', 'name', 'slice', 'flavor', 'image', 'key', 'node', 'deploymentNetwork']
+    list_display = ['ip', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
 
     def save_model(self, request, obj, form, change):
         # update openstack connection to use this sliver's slice/tenant
@@ -268,7 +315,8 @@ class UserCreationForm(forms.ModelForm):
     def save(self, commit=True):
         # Save the provided password in hashed format
         user = super(UserCreationForm, self).save(commit=False)
-        user.set_password(self.cleaned_data["password1"])
+        user.password = self.cleaned_data["password1"]
+        #user.set_password(self.cleaned_data["password1"])
         if commit:
             user.save()
         return user
@@ -340,7 +388,6 @@ admin.site.register(Subnet, SubnetAdmin)
 admin.site.register(Image, ImageAdmin)
 admin.site.register(Node, NodeAdmin)
 admin.site.register(Sliver, SliverAdmin)
-admin.site.register(Flavor)
 admin.site.register(Key, KeyAdmin)
 admin.site.register(Role, RoleAdmin)
 admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)
index 4054da6..412df00 100644 (file)
@@ -1,8 +1,8 @@
 from plstackapi.openstack.client import OpenStackClient
 
-def auth_check(auth):
-    client = OpenStackClient(username=auth['Username'],
-                             password=auth['AuthString'],
-                             tenant=auth['LoginBase'])
+def auth_check(username, password, tenant):
+    client = OpenStackClient(username=username,
+                             password=password,
+                             tenant=tenant)
     client.authenticate()
     return client
diff --git a/plstackapi/core/api/flavors.py b/plstackapi/core/api/flavors.py
deleted file mode 100644 (file)
index 94c38eb..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-from types import StringTypes
-from plstackapi.openstack.client import OpenStackClient
-from plstackapi.openstack.driver import OpenStackDriver
-from plstackapi.core.api.auth import auth_check
-from plstackapi.core.models import Flavor
-def _get_flavors(filter):
-    if isinstance(filter, StringTypes) and filter.isdigit():
-        filter = int(filter)
-    if isinstance(filter, int):
-        flavors = Flavor.objects.filter(id=filter)
-    elif isinstance(filter, StringTypes):
-        flavors = Flavor.objects.filter(name=filter)
-    elif isinstance(filter, dict):
-        flavors = Flavor.objects.filter(**filter)
-    else:
-        flavors = []
-    return flavors
-
-def add_flavor(auth, fields={}):
-    """not implemented"""
-    return 
-
-def delete_flavor(auth, filter={}):
-    """not implemented"""
-    return 1
-
-def get_flavors(auth, filter={}):
-    auth_check(auth)   
-    flavors = _get_flavors(filter)
-    return flavors             
-        
-
-    
index a5b3084..cc45b8d 100644 (file)
@@ -1,9 +1,9 @@
 from types import StringTypes
+from django.contrib.auth import authenticate
 from plstackapi.openstack.client import OpenStackClient
 from plstackapi.openstack.driver import OpenStackDriver
 from plstackapi.core.api.auth import auth_check
 from plstackapi.core.models import Sliver, Slice
-from plstackapi.core.api.flavors import _get_flavors
 from plstackapi.core.api.images import _get_images
 from plstackapi.core.api.keys import _get_keys
 from plstackapi.core.api.slices import _get_slices
@@ -26,9 +26,7 @@ def _get_slivers(filter):
  
 def add_sliver(auth, fields):
     driver = OpenStackDriver(client = auth_check(auth))
-    
-    flavors = _get_flavors(fields.get('flavor'))
-    if flavors: fields['flavor'] = flavors[0]     
+        
     images = _get_images(fields.get('image'))
     if images: fields['image'] = images[0]     
     keys = _get_keys(fields.get('key'))
@@ -41,15 +39,7 @@ def add_sliver(auth, fields):
     nodes = _get_nodes(fields.get('node'))
     if nodes: fields['node'] = nodes[0]     
     sliver = Sliver(**fields)
-    # create quantum sliver
-    instance = driver.spawn_instance(name=sliver.name,
-                                   key_name = sliver.key.name,
-                                   flavor_id = sliver.flavor.flavor_id,
-                                   image_id = sliver.image.image_id,
-                                   hostname = sliver.node.name )
-
-    sliver.instance_id=instance.id
-
+    sliver.driver = driver    
     sliver.save()
     return sliver
 
@@ -60,12 +50,13 @@ def delete_sliver(auth, filter={}):
     driver = OpenStackDriver(client = auth_check(auth))   
     slivers = _get_slivers(filter)
     for sliver in slivers:
-        driver.destroy_instance(sliver.sliver_id) 
+        sliver.driver = driver
         sliver.delete()
     return 1
 
 def get_slivers(auth, filter={}):
-    client = auth_check(auth)
+    user = authenticate(username=auth.get('username'),
+                        password=auth.get('password'))
     if 'slice' in filter:
         slices = _get_slices(filter.get('slice'))
         if slices: filter['slice'] = slices[0]
index 583e7c4..61e76da 100644 (file)
@@ -15,5 +15,4 @@ def api_root(request, format=None):
         'subnets': reverse('subnet-list', request=request, format=format),
         'slivers': reverse('sliver-list', request=request, format=format),
         'images': reverse('image-list', request=request, format=format),
-        'flavors': reverse('flavor-list', request=request, format=format),
     })
index 1c87f34..e893c6d 100644 (file)
@@ -2,7 +2,6 @@ from plstackapi.core.models.plcorebase import PlCoreBase
 from plstackapi.core.models.deploymentnetwork import DeploymentNetwork
 from plstackapi.core.models.site import Site
 from plstackapi.core.models.site import SitePrivilege
-from plstackapi.core.models.flavor import Flavor
 from plstackapi.core.models.image import Image
 from plstackapi.core.models.pluser import PLUser
 from plstackapi.core.models.role import Role
diff --git a/plstackapi/core/models/flavor.py b/plstackapi/core/models/flavor.py
deleted file mode 100644 (file)
index 3081f82..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-import os
-from django.db import models
-from plstackapi.core.models import PlCoreBase
-
-# Create your models here.
-
-class Flavor(PlCoreBase):
-    flavor_id = models.IntegerField(unique=True)
-    name = models.CharField(max_length=256, unique=True)
-    memory_mb = models.IntegerField()
-    disk_gb = models.IntegerField()
-    vcpus = models.IntegerField()
-
-    def __unicode__(self):  return u'%s' % (self.name)
index 1c01a42..f914662 100644 (file)
@@ -102,15 +102,16 @@ class PLUser(AbstractBaseUser):
 
     def save(self, *args, **kwds):
         if not self.user_id:
-            if not hasattr(self, 'driver'):
+            if not self.driver:
                 setattr(self, 'driver', OpenStackDriver())
             name = self.email[:self.email.find('@')]
             user_fields = {'name': name,
                            'email': self.email,
                            'password': self.password,
-                           'enabled': self.is_active}
-            user = self.driver.create_user(**user_fields)
-            self.user_id = user.id
+                           'enabled': True}
+            keystone_user = self.driver.create_user(**user_fields)
+            self.user_id = keystone_user.id
+        self.set_password(self.password)    
         super(PLUser, self).save(*args, **kwds)   
 
     def delete(self, *args, **kwds):
index b9f3e2f..41bfd62 100644 (file)
@@ -13,13 +13,10 @@ class Role(PlCoreBase):
 
 
     def save(self, *args, **kwds):
-        if not self.role_id:
-            keystone_role = self.driver.create_role(name=self.role_type)
-            self.role_id = keystone_role.id
+        self.os_manager.save_role(self)
         super(Role, self).save(*args, **kwds)
     
     def delete(self, *args, **kwds):
-        if self.role_id:
-            self.driver.delete_role({'id': self.role_id})   
+        self.os_manager.delete_role(self)   
         super(Role, self).delete(*args, **kwds)
             
index 529c131..a4bf2c0 100644 (file)
@@ -2,7 +2,6 @@ import os
 from django.db import models
 from django.core import exceptions
 from plstackapi.core.models import PlCoreBase
-from plstackapi.core.models import Flavor
 from plstackapi.core.models import Image
 from plstackapi.core.models import Key
 from plstackapi.core.models import Slice
@@ -14,8 +13,8 @@ from plstackapi.core.models import DeploymentNetwork
 class Sliver(PlCoreBase):
     instance_id = models.CharField(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)
-    flavor = models.ForeignKey(Flavor, related_name='slivers')
     image = models.ForeignKey(Image, related_name='slivers')
     key = models.ForeignKey(Key, related_name='slivers')
     slice = models.ForeignKey(Slice, related_name='slivers')
@@ -33,10 +32,10 @@ class Sliver(PlCoreBase):
         if not self.instance_id:
             instance = self.driver.spawn_instance(name=self.name,
                                    key_name = self.key.name,
-                                   flavor_id = self.flavor.flavor_id,
                                    image_id = self.image.image_id,
                                    hostname = self.node.name )
             self.instance_id = instance.id
+            self.instance_name = getattr(instance, 'OS-EXT-SRV-ATTR:instance_name')
 
         super(Sliver, self).save(*args, **kwds)
 
index 2cc88e0..b4ffe68 100644 (file)
@@ -151,7 +151,6 @@ class DeploymentNetworkSerializer(serializers.HyperlinkedModelSerializer):
 class SliverSerializer(serializers.HyperlinkedModelSerializer):
     # HyperlinkedModelSerializer doesn't include the id by default
     id = serializers.Field()
-    flavor = serializers.HyperlinkedRelatedField(view_name='flavor-detail')
     image = serializers.HyperlinkedRelatedField(view_name='image-detail')
     key = serializers.HyperlinkedRelatedField(view_name='key-detail')
     slice = serializers.HyperlinkedRelatedField(view_name='slice-detail')
@@ -166,8 +165,8 @@ class SliverSerializer(serializers.HyperlinkedModelSerializer):
         fields = ('id',
                   'instance_id',
                   'name',
+                  'instance_name',
                   'ip',
-                  'flavor',
                   'image',
                   'key',
                   'slice',
@@ -193,18 +192,6 @@ class ImageSerializer(serializers.HyperlinkedModelSerializer):
                   'disk_format',
                   'container_format')
 
-class FlavorSerializer(serializers.HyperlinkedModelSerializer):
-    # HyperlinkedModelSerializer doesn't include the id by default
-    id = serializers.Field()
-    class Meta:
-        model = Flavor
-        fields = ('id',
-                  'flavor_id',
-                  'name',
-                  'memory_mb',
-                  'disk_gb',
-                  'vcpus')
-
 serializerLookUp = { 
                  Role: RoleSerializer,
                  PLUser: UserSerializer,
@@ -218,7 +205,6 @@ serializerLookUp = {
                  Sliver: SliverSerializer,
                  DeploymentNetwork: DeploymentNetworkSerializer,
                  Image: ImageSerializer,
-                 Flavor: FlavorSerializer, 
                  None: None,
                 }
 
index 9493a06..0c9b858 100644 (file)
@@ -13,7 +13,6 @@ from plstackapi.core.views.slivers import SliverListCreate, SliverRetrieveUpdate
 from plstackapi.core.views.keys import KeyListCreate, KeyRetrieveUpdateDestroy
 from plstackapi.core.views.deployment_networks import DeploymentNetworkListCreate, DeploymentNetworkRetrieveUpdateDestroy
 from plstackapi.core.views.images import ImageListCreate, ImageRetrieveUpdateDestroy
-from plstackapi.core.views.flavors import FlavorListCreate, FlavorRetrieveUpdateDestroy
 from plstackapi.core.views.nodes import NodeListCreate, NodeRetrieveUpdateDestroy
 from plstackapi.core.models import Site
 from plstackapi.core.api_root import api_root
@@ -56,13 +55,13 @@ urlpatterns = patterns('',
     url(r'^plstackapi/slice_memberships/(?P<pk>[0-9]+)/$', SliceMembershipRetrieveUpdateDestroy.as_view(), name='slice_membership-detail'),
     
     url(r'^plstackapi/subnets/$', SubnetListCreate.as_view(), name='subnet-list'),
-    url(r'^plstackapi/subnets/(?P<pk>[0-9]+)/$', SubnetRetrieveUpdateDestroy.as_view(), name='subnet-detail'),
+    url(r'^plstackapi/subnets/(?P<pk>[a-zA-Z0-9_]+)/$', SubnetRetrieveUpdateDestroy.as_view(), name='subnet-detail'),
 
     url(r'^plstackapi/slivers/$', SliverListCreate.as_view(), name='sliver-list'),
-    url(r'^plstackapi/slivers/(?P<pk>[0-9]+)/$', SliverRetrieveUpdateDestroy.as_view(), name='sliver-detail'),
+    url(r'^plstackapi/slivers/(?P<pk>[a-zA-Z0-9_]+)/$', SliverRetrieveUpdateDestroy.as_view(), name='sliver-detail'),
 
     url(r'^plstackapi/nodes/$', NodeListCreate.as_view(), name='node-list'),
-    url(r'^plstackapi/nodes/(?P<pk>[0-9]+)/$', NodeRetrieveUpdateDestroy.as_view(), name='node-detail'),
+    url(r'^plstackapi/nodes/(?P<pk>[a-zA-Z0-9_]+)/$', NodeRetrieveUpdateDestroy.as_view(), name='node-detail'),
     
     url(r'^plstackapi/deploymentnetworks/$', DeploymentNetworkListCreate.as_view(), name='deploymentnetwork-list'),
     url(r'^plstackapi/deploymentnetworks/(?P<pk>[a-zA-Z0-9]+)/$', DeploymentNetworkRetrieveUpdateDestroy.as_view(), name='deploymentnetwork-detail'),
@@ -70,8 +69,6 @@ urlpatterns = patterns('',
     url(r'^plstackapi/images/$', ImageListCreate.as_view(), name='image-list'),
     url(r'^plstackapi/images/(?P<pk>[a-zA-Z0-9_]+)/$', ImageRetrieveUpdateDestroy.as_view(), name='image-detail'),
 
-    url(r'^plstackapi/flavors/$', FlavorListCreate.as_view(), name='flavor-list'),
-    url(r'^plstackapi/flavors/(?P<pk>[a-zA-Z0-9_]+)/$', FlavorRetrieveUpdateDestroy.as_view(), name='flavor-detail'),
     #Adding in rest_framework urls
     url(r'^plstackapi/', include('rest_framework.urls', namespace='rest_framework')),
     
diff --git a/plstackapi/core/views/flavors.py b/plstackapi/core/views/flavors.py
deleted file mode 100644 (file)
index 0e06c8e..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-from django.http import Http404
-from rest_framework.views import APIView
-from rest_framework.response import Response
-from rest_framework import status
-
-from plstackapi.core.api.flavors import add_flavor, delete_flavor, get_flavors
-from plstackapi.core.serializers import FlavorSerializer
-from plstackapi.util.request import parse_request
-
-
-class FlavorListCreate(APIView):
-    """ 
-    List all flavors or create a new flavor.
-    """
-
-    def post(self, request, format = None):
-        data = parse_request(request.DATA)  
-        if 'auth' not in data:
-            return Response(status=status.HTTP_400_BAD_REQUEST)        
-        elif 'flavor' in data:
-            """Not Implemented"""
-            return Response(status=status.HTTP_404_NOT_FOUND)
-        else:
-            flavors = get_flavors(data['auth'])
-            serializer = FlavorSerializer(flavors, many=True)
-            return Response(serializer.data)
-        
-            
-class FlavorRetrieveUpdateDestroy(APIView):
-    """
-    Retrieve, update or delete an flavor  
-    """
-
-    def post(self, request, pk, format=None):
-        """Retrieve an flavor """
-        data = parse_request(request.DATA)
-        if 'auth' not in data:
-            return Response(status=status.HTTP_400_BAD_REQUEST)
-        flavors = get_flavors(data['auth'], pk)
-        if not flavors:
-            return Response(status=status.HTTP_404_NOT_FOUND)
-        serializer = FlavorSerializer(flavors[0])
-        return Response(serializer.data)                  
-
-    def put(self, request, pk, format=None):
-        """update flavor not implemnted""" 
-        return Response(status=status.HTTP_404_NOT_FOUND) 
-
-    def delete(self, request, pk, format=None):
-        """delete flavor not implemnted""" 
-        return Response(status=status.HTTP_404_NOT_FOUND) 
-
-            
-            
-        
index 4063419..2f5842c 100644 (file)
@@ -37,7 +37,7 @@ class SliverRetrieveUpdateDestroy(APIView):
         data = parse_request(request.DATA)
         if 'auth' not in data:
             return Response(status=status.HTTP_400_BAD_REQUEST)
-        slivers = get_slivers(data['auth'], {'id': pk})
+        slivers = get_slivers(data['auth'], pk)
         if not slivers:
             return Response(status=status.HTTP_404_NOT_FOUND)
         serializer = SliverSerializer(slivers[0])
@@ -59,7 +59,7 @@ class SliverRetrieveUpdateDestroy(APIView):
         data = parse_request(request.DATA) 
         if 'auth' not in data:
             return Response(status=status.HTTP_400_BAD_REQUEST)
-        delete_sliver(data['auth'], {'id': pk})
+        delete_sliver(data['auth'], pk)
         return Response(status=status.HTTP_204_NO_CONTENT) 
             
             
index a1a3333..ce0f7c0 100644 (file)
@@ -234,16 +234,17 @@ class OpenStackDriver:
             self.shell.nova.keypairs.delete(key) 
         return 1 
 
-    def spawn_instance(self, name, key_name=None, hostname=None, flavor_id=None, image_id=None, security_group=None, pubkeys=[]):
-        #if not flavor_id:
-        #    flavor = self.config.nova_default_flavor
+    def spawn_instance(self, name, key_name=None, hostname=None, image_id=None, security_group=None, pubkeys=[]):
+        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 
 
-        authorized_keys = "\n".join(pubkeys)
-        files = {'/root/.ssh/authorized_keys': authorized_keys}
+        #authorized_keys = "\n".join(pubkeys)
+        #files = {'/root/.ssh/authorized_keys': authorized_keys}
+        files = {}
        
         hints = {}
         availability_zone = None
@@ -252,7 +253,7 @@ class OpenStackDriver:
         server = self.shell.nova.servers.create(
                                             name=name,
                                             key_name = key_name,
-                                            flavor=flavor_id,
+                                            flavor=flavor.id,
                                             image=image_id,
                                             security_group = security_group,
                                             files=files,
@@ -264,3 +265,17 @@ class OpenStackDriver:
         servers = self.shell.nova.servers.findall(id=id)
         for server in servers:
             self.shell.nova.servers.delete(server)
+
+    def update_instance_metadata(self, id, metadata):
+        servers = self.shell.nova.servers.findall(id=id)
+        for server in servers:
+            self.shell.nova.servers.set_meta(server, metadata)
+            # note: set_meta() returns a broken Server() object. Don't try to
+            # print it in the shell or it will fail in __repr__.
+
+    def delete_instance_metadata(self, id, metadata):
+        # note: metadata is a dict. Only the keys matter, not the values.
+        servers = self.shell.nova.servers.findall(id=id)
+        for server in servers:
+            self.shell.nova.servers.delete_meta(server, metadata)
+
index 342b08e..b4ad8d2 100644 (file)
@@ -2,19 +2,43 @@ from plstackapi.planetstack import settings
 from django.core import management
 management.setup_environ(settings)
 from plstackapi.openstack.client import OpenStackClient
+from plstackapi.openstack.driver import OpenStackDriver
+from plstackapi.planetstack.config import Config
+from plstackapi.core.models import * 
 
+def require_enabled(callable):
+    enabled = Config().api_nova_enabled
+    def wrapper(*args, **kwds):
+        if enabled:
+            return callable(*args, **kwds)
+        else:
+            return None
+    return wrapper
 
-class Manager:
 
-    def __init__(self):
+class OpenStackManager:
+
+    def __init__(self, auth={}, caller=None):
+        self.client = None
+        if auth:
+            self.client = OpenStackClient(**auth)
         
-        self.client = OpenStackClient()
+        self.driver = OpenStackDriver(client=self.client) 
+        self.caller=None
+
+    @require_enabled
+    def save_role(self, role):
+        if not role.role_id:
+            keystone_role = self.driver.create_role(role.role_type)
+            role.role_id = keystone_role.id
 
+    @require_enabled
+    def delete_role(self, role):
+        if role.role_id:
+            self.driver.delete_role({'id': role.role_id})        
+                  
     def refresh_nodes(self):
         # collect local nodes
-        from plstackapi.core.models import Node
-        from plstackapi.core.models import DeploymentNetwork
-        from plstackapi.core.models import Site
         nodes = Node.objects.all()
         nodes_dict = {}
         for node in nodes:
@@ -49,38 +73,8 @@ class Manager:
         old_node_names = set(nodes_dict.keys()).difference(compute_nodes_dict.keys())
         Node.objects.filter(name__in=old_node_names).delete()
 
-    def refresh_flavors(self):
-        # collect local flavors
-        from plstackapi.core.models import Flavor
-        flavors = Flavor.objects.all()
-        flavors_dict = {}
-        for flavor in flavors:
-            flavors_dict[flavor.name] = flavor
-
-        # collect nova falvors
-        nova_flavors = self.client.nova.flavors.list()
-        nova_flavors_dict = {}
-        for nova_flavor in nova_flavors:
-            nova_flavors_dict[nova_flavor.name] = nova_flavor
-
-        # add new flavors 
-        new_flavor_names = set(nova_flavors_dict.keys()).difference(flavors_dict.keys())
-        for name in new_flavor_names:
-             
-            flavor = Flavor(flavor_id=nova_flavors_dict[name].id,
-                            name=nova_flavors_dict[name].name,
-                            memory_mb=nova_flavors_dict[name].ram,
-                            disk_gb=nova_flavors_dict[name].disk,   
-                            vcpus=nova_flavors_dict[name].vcpus)
-            flavor.save()
-
-        # remove old flavors
-        old_flavor_names = set(flavors_dict.keys()).difference(nova_flavors_dict.keys())
-        Flavor.objects.filter(name__in=old_flavor_names).delete()
-            
     def refresh_images(self):
         # collect local images
-        from plstackapi.core.models import Image
         images = Image.objects.all()
         images_dict = {}    
         for image in images:
@@ -104,3 +98,5 @@ class Manager:
         # remove old images
         old_image_names = set(images_dict.keys()).difference(glance_images_dict.keys())
         Image.objects.filter(name__in=old_image_names).delete()
+
+
diff --git a/plstackapi/openstack/siteagent.py b/plstackapi/openstack/siteagent.py
new file mode 100644 (file)
index 0000000..98fedae
--- /dev/null
@@ -0,0 +1,21 @@
+import os
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "plstackapi.planetstack.settings")
+import time
+from plstackapi.core.models.site import Site
+from plstackapi.openstack.driver import OpenStackDriver    
+
+class SiteAgent:
+    def run(self):
+        driver = OpenStackDriver()
+        # fill in null tenant ids 
+        sites = Site.objects.filter(tenant_id__in=[None, ''])
+        for site in sites:
+            # calling save() on the model should force the tenant_id to be set
+            site.driver = driver
+            site.caller = driver.admin_user
+            site.caller.user_id = site.caller.id
+            site.save() 
+                                        
+if __name__ == '__main__':
+    SiteAgent().run()
+                 
index 2a5353e..56542bf 100644 (file)
@@ -5,16 +5,25 @@ import threading
 
 from plstackapi.planetstack.config import Config 
 from plstackapi.openstack.sliveragent import SliverAgent
+from plstackapi.openstack.siteagent import SiteAgent
 
 if __name__ == '__main__':
 
+    # bootstrap envirnment
     os.environ.setdefault("DJANGO_SETTINGS_MODULE", "plstackapi.planetstack.settings")
     from django.core.management import ManagementUtility
     config = Config()
     url = "%s:%s" % (config.api_host, config.api_port)
     args = [__file__, 'runserver', url] 
-    server = ManagementUtility(args)
+
+    # run site agent once on startup
+    SiteAgent().run()    
+    
+    # start the sliver agent thread
     sliver_agent = SliverAgent()
     sliver_agent_thread = threading.Thread(target=sliver_agent.run)
     sliver_agent_thread.start()
+
+    # start the server
+    server = ManagementUtility(args)
     server.execute()