Merged with Tony's changes -- added numberCores to SliverAdmins
diff --git a/config/plstackapi_config b/config/plstackapi_config
index cf02ee7..1d7b761 100644
--- a/config/plstackapi_config
+++ b/config/plstackapi_config
@@ -17,6 +17,7 @@
ratelimit_enabled=0
omf_enabled=0
mail_support_address=support@localhost
+nova_enabled=True
[nova]
admin_user=admin@domain.com
diff --git a/plstackapi/core/admin.py b/plstackapi/core/admin.py
index 3a40bca..4bb9a98 100644
--- a/plstackapi/core/admin.py
+++ b/plstackapi/core/admin.py
@@ -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 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 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 @@
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 @@
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 @@
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 @@
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 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 @@
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(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)
diff --git a/plstackapi/core/api/auth.py b/plstackapi/core/api/auth.py
index 4054da6..412df00 100644
--- a/plstackapi/core/api/auth.py
+++ b/plstackapi/core/api/auth.py
@@ -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
index 94c38eb..0000000
--- a/plstackapi/core/api/flavors.py
+++ /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
-
-
-
diff --git a/plstackapi/core/api/slivers.py b/plstackapi/core/api/slivers.py
index a5b3084..cc45b8d 100644
--- a/plstackapi/core/api/slivers.py
+++ b/plstackapi/core/api/slivers.py
@@ -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 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 @@
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 @@
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]
diff --git a/plstackapi/core/api_root.py b/plstackapi/core/api_root.py
index 583e7c4..61e76da 100644
--- a/plstackapi/core/api_root.py
+++ b/plstackapi/core/api_root.py
@@ -15,5 +15,4 @@
'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),
})
diff --git a/plstackapi/core/models/__init__.py b/plstackapi/core/models/__init__.py
index 1c87f34..e893c6d 100644
--- a/plstackapi/core/models/__init__.py
+++ b/plstackapi/core/models/__init__.py
@@ -2,7 +2,6 @@
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
index 3081f82..0000000
--- a/plstackapi/core/models/flavor.py
+++ /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)
diff --git a/plstackapi/core/models/pluser.py b/plstackapi/core/models/pluser.py
index 1c01a42..f914662 100644
--- a/plstackapi/core/models/pluser.py
+++ b/plstackapi/core/models/pluser.py
@@ -102,15 +102,16 @@
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):
diff --git a/plstackapi/core/models/role.py b/plstackapi/core/models/role.py
index b9f3e2f..41bfd62 100644
--- a/plstackapi/core/models/role.py
+++ b/plstackapi/core/models/role.py
@@ -13,13 +13,10 @@
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)
diff --git a/plstackapi/core/models/sliver.py b/plstackapi/core/models/sliver.py
index 529c131..a4bf2c0 100644
--- a/plstackapi/core/models/sliver.py
+++ b/plstackapi/core/models/sliver.py
@@ -2,7 +2,6 @@
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 @@
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 @@
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)
diff --git a/plstackapi/core/serializers.py b/plstackapi/core/serializers.py
index 2cc88e0..b4ffe68 100644
--- a/plstackapi/core/serializers.py
+++ b/plstackapi/core/serializers.py
@@ -151,7 +151,6 @@
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 @@
fields = ('id',
'instance_id',
'name',
+ 'instance_name',
'ip',
- 'flavor',
'image',
'key',
'slice',
@@ -193,18 +192,6 @@
'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 @@
Sliver: SliverSerializer,
DeploymentNetwork: DeploymentNetworkSerializer,
Image: ImageSerializer,
- Flavor: FlavorSerializer,
None: None,
}
diff --git a/plstackapi/core/urls.py b/plstackapi/core/urls.py
index 9493a06..0c9b858 100644
--- a/plstackapi/core/urls.py
+++ b/plstackapi/core/urls.py
@@ -13,7 +13,6 @@
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 @@
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 @@
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
index 0e06c8e..0000000
--- a/plstackapi/core/views/flavors.py
+++ /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)
-
-
-
-
diff --git a/plstackapi/core/views/slivers.py b/plstackapi/core/views/slivers.py
index 4063419..2f5842c 100644
--- a/plstackapi/core/views/slivers.py
+++ b/plstackapi/core/views/slivers.py
@@ -37,7 +37,7 @@
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 @@
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)
diff --git a/plstackapi/openstack/driver.py b/plstackapi/openstack/driver.py
index a1a3333..ce0f7c0 100644
--- a/plstackapi/openstack/driver.py
+++ b/plstackapi/openstack/driver.py
@@ -234,16 +234,17 @@
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 @@
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 @@
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)
+
diff --git a/plstackapi/openstack/manager.py b/plstackapi/openstack/manager.py
index 342b08e..b4ad8d2 100644
--- a/plstackapi/openstack/manager.py
+++ b/plstackapi/openstack/manager.py
@@ -2,19 +2,43 @@
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:
+class OpenStackManager:
- def __init__(self):
+ 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 @@
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 @@
# 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
index 0000000..98fedae
--- /dev/null
+++ b/plstackapi/openstack/siteagent.py
@@ -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()
+
diff --git a/plstackapi/plstackapi-debug-server.py b/plstackapi/plstackapi-debug-server.py
index 2a5353e..56542bf 100644
--- a/plstackapi/plstackapi-debug-server.py
+++ b/plstackapi/plstackapi-debug-server.py
@@ -5,16 +5,25 @@
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()