summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorBrian Waldon <brian.waldon@rackspace.com>2011-12-26 11:14:47 -0500
committerBrian Waldon <brian.waldon@rackspace.com>2011-12-26 18:00:51 -0500
commit1b372a7bddb3095b0672e2de750c43922783b440 (patch)
tree4718cf07313ae1b74e5e23a85ce4238feeb603cc /nova/api
parentcff2ddcbd532ed54d60dbfbdbb7720f4634487b9 (diff)
Converting zones into true extension
Related to blueprint separate-nova-adminapi Change-Id: I733b05e7de0036f3dce31c95efef150186e302ee
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/openstack/v2/__init__.py10
-rw-r--r--nova/api/openstack/v2/contrib/zones.py207
-rw-r--r--nova/api/openstack/v2/zones.py215
3 files changed, 204 insertions, 228 deletions
diff --git a/nova/api/openstack/v2/__init__.py b/nova/api/openstack/v2/__init__.py
index 1dadd7bef..9504e4f7e 100644
--- a/nova/api/openstack/v2/__init__.py
+++ b/nova/api/openstack/v2/__init__.py
@@ -34,7 +34,6 @@ from nova.api.openstack.v2 import limits
from nova.api.openstack.v2 import servers
from nova.api.openstack.v2 import server_metadata
from nova.api.openstack.v2 import versions
-from nova.api.openstack.v2 import zones
from nova.api.openstack import wsgi
from nova import flags
from nova import log as logging
@@ -130,15 +129,6 @@ class APIRouter(base_wsgi.Router):
mapper.resource(resource.collection, resource.collection, **kargs)
def _setup_routes(self, mapper):
- if FLAGS.allow_admin_api:
- LOG.debug(_("Including admin operations in API."))
-
- mapper.resource("zone", "zones",
- controller=zones.create_resource(),
- collection={'detail': 'GET',
- 'info': 'GET',
- 'select': 'POST'})
-
mapper.connect("versions", "/",
controller=versions.create_resource(),
action='show')
diff --git a/nova/api/openstack/v2/contrib/zones.py b/nova/api/openstack/v2/contrib/zones.py
index 89c3ef517..62ce423a7 100644
--- a/nova/api/openstack/v2/contrib/zones.py
+++ b/nova/api/openstack/v2/contrib/zones.py
@@ -17,16 +17,195 @@
"""The zones extension."""
+import json
+from nova.api.openstack import common
+from nova.api.openstack.v2 import servers
+from nova.api.openstack.v2 import extensions
+from nova.api.openstack import xmlutil
+from nova.api.openstack import wsgi
+from nova.compute import api as compute
+from nova import crypto
+from nova import exception
from nova import flags
from nova import log as logging
-from nova.api.openstack.v2 import extensions
+import nova.scheduler.api
LOG = logging.getLogger("nova.api.openstack.v2.contrib.zones")
FLAGS = flags.FLAGS
+def _filter_keys(item, keys):
+ """
+ Filters all model attributes except for keys
+ item is a dict
+
+ """
+ return dict((k, v) for k, v in item.iteritems() if k in keys)
+
+
+def _exclude_keys(item, keys):
+ return dict((k, v) for k, v in item.iteritems() if k and (k not in keys))
+
+
+def _scrub_zone(zone):
+ return _exclude_keys(zone, ('username', 'password', 'created_at',
+ 'deleted', 'deleted_at', 'updated_at'))
+
+
+def check_encryption_key(func):
+ def wrapped(*args, **kwargs):
+ if not FLAGS.build_plan_encryption_key:
+ raise exception.Error(_("--build_plan_encryption_key not set"))
+ return func(*args, **kwargs)
+ return wrapped
+
+
+class Controller(object):
+ """Controller for Zone resources."""
+
+ def __init__(self):
+ self.compute_api = compute.API()
+
+ def index(self, req):
+ """Return all zones in brief"""
+ # Ask the ZoneManager in the Scheduler for most recent data,
+ # or fall-back to the database ...
+ items = nova.scheduler.api.get_zone_list(req.environ['nova.context'])
+ items = common.limited(items, req)
+ items = [_scrub_zone(item) for item in items]
+ return dict(zones=items)
+
+ def detail(self, req):
+ """Return all zones in detail"""
+ return self.index(req)
+
+ def info(self, req):
+ """Return name and capabilities for this zone."""
+ context = req.environ['nova.context']
+ items = nova.scheduler.api.get_zone_capabilities(context)
+
+ zone = dict(name=FLAGS.zone_name)
+ caps = FLAGS.zone_capabilities
+ for cap in caps:
+ key, value = cap.split('=')
+ zone[key] = value
+ for item, (min_value, max_value) in items.iteritems():
+ zone[item] = "%s,%s" % (min_value, max_value)
+ return dict(zone=zone)
+
+ def show(self, req, id):
+ """Return data about the given zone id"""
+ zone_id = int(id)
+ context = req.environ['nova.context']
+ zone = nova.scheduler.api.zone_get(context, zone_id)
+ return dict(zone=_scrub_zone(zone))
+
+ def delete(self, req, id):
+ """Delete a child zone entry."""
+ zone_id = int(id)
+ nova.scheduler.api.zone_delete(req.environ['nova.context'], zone_id)
+ return {}
+
+ def create(self, req, body):
+ """Create a child zone entry."""
+ context = req.environ['nova.context']
+ zone = nova.scheduler.api.zone_create(context, body["zone"])
+ return dict(zone=_scrub_zone(zone))
+
+ def update(self, req, id, body):
+ """Update a child zone entry."""
+ context = req.environ['nova.context']
+ zone_id = int(id)
+ zone = nova.scheduler.api.zone_update(context, zone_id, body["zone"])
+ return dict(zone=_scrub_zone(zone))
+
+ @check_encryption_key
+ def select(self, req, body):
+ """Returns a weighted list of costs to create instances
+ of desired capabilities."""
+ ctx = req.environ['nova.context']
+ specs = json.loads(body)
+ build_plan = nova.scheduler.api.select(ctx, specs=specs)
+ cooked = self._scrub_build_plan(build_plan)
+ return {"weights": cooked}
+
+ def _scrub_build_plan(self, build_plan):
+ """Remove all the confidential data and return a sanitized
+ version of the build plan. Include an encrypted full version
+ of the weighting entry so we can get back to it later."""
+ encryptor = crypto.encryptor(FLAGS.build_plan_encryption_key)
+ cooked = []
+ for entry in build_plan:
+ json_entry = json.dumps(entry)
+ cipher_text = encryptor(json_entry)
+ cooked.append(dict(weight=entry['weight'],
+ blob=cipher_text))
+ return cooked
+
+
+class CapabilitySelector(object):
+ def __call__(self, obj, do_raise=False):
+ return [(k, v) for k, v in obj.items()
+ if k not in ('id', 'api_url', 'name', 'capabilities')]
+
+
+def make_zone(elem):
+ #elem = xmlutil.SubTemplateElement(parent, 'zone', selector=selector)
+ elem.set('id')
+ elem.set('api_url')
+ elem.set('name')
+ elem.set('capabilities')
+
+ cap = xmlutil.SubTemplateElement(elem, xmlutil.Selector(0),
+ selector=CapabilitySelector())
+ cap.text = 1
+
+
+zone_nsmap = {None: wsgi.XMLNS_V10}
+
+
+class ZoneTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('zone', selector='zone')
+ make_zone(root)
+ return xmlutil.MasterTemplate(root, 1, nsmap=zone_nsmap)
+
+
+class ZonesTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('zones')
+ elem = xmlutil.SubTemplateElement(root, 'zone', selector='zones')
+ make_zone(elem)
+ return xmlutil.MasterTemplate(root, 1, nsmap=zone_nsmap)
+
+
+class WeightsTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('weights')
+ weight = xmlutil.SubTemplateElement(root, 'weight', selector='weights')
+ blob = xmlutil.SubTemplateElement(weight, 'blob')
+ blob.text = 'blob'
+ inner_weight = xmlutil.SubTemplateElement(weight, 'weight')
+ inner_weight.text = 'weight'
+ return xmlutil.MasterTemplate(root, 1, nsmap=zone_nsmap)
+
+
+class ZonesXMLSerializer(xmlutil.XMLTemplateSerializer):
+ def index(self):
+ return ZonesTemplate()
+
+ def detail(self):
+ return ZonesTemplate()
+
+ def select(self):
+ return WeightsTemplate()
+
+ def default(self):
+ return ZoneTemplate()
+
+
class Zones(extensions.ExtensionDescriptor):
"""Enables zones-related functionality such as adding child zones,
listing child zones, getting the capabilities of the local zone,
@@ -37,7 +216,29 @@ class Zones(extensions.ExtensionDescriptor):
alias = "os-zones"
namespace = "http://docs.openstack.org/compute/ext/zones/api/v1.1"
updated = "2011-09-21T00:00:00+00:00"
+ admin_only = True
def get_resources(self):
- # Nothing yet.
- return []
+ body_serializers = {
+ 'application/xml': ZonesXMLSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
+ body_deserializers = {
+ 'application/xml': servers.ServerXMLDeserializer(),
+ }
+ deserializer = wsgi.RequestDeserializer(body_deserializers)
+
+ #NOTE(bcwaldon): This resource should be prefixed with 'os-'
+ coll_actions = {
+ 'detail': 'GET',
+ 'info': 'GET',
+ 'select': 'POST',
+ }
+
+ res = extensions.ResourceExtension('zones',
+ Controller(),
+ deserializer=deserializer,
+ serializer=serializer,
+ collection_actions=coll_actions)
+ return [res]
diff --git a/nova/api/openstack/v2/zones.py b/nova/api/openstack/v2/zones.py
deleted file mode 100644
index 8457eb5dd..000000000
--- a/nova/api/openstack/v2/zones.py
+++ /dev/null
@@ -1,215 +0,0 @@
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import json
-
-from nova.api.openstack import common
-from nova.api.openstack.v2 import servers
-from nova.api.openstack import xmlutil
-from nova.api.openstack import wsgi
-from nova.compute import api as compute
-from nova import crypto
-from nova import exception
-from nova import flags
-from nova import log as logging
-from nova.scheduler import api
-
-
-FLAGS = flags.FLAGS
-
-
-LOG = logging.getLogger('nova.api.openstack.v2.zones')
-
-
-def _filter_keys(item, keys):
- """
- Filters all model attributes except for keys
- item is a dict
-
- """
- return dict((k, v) for k, v in item.iteritems() if k in keys)
-
-
-def _exclude_keys(item, keys):
- return dict((k, v) for k, v in item.iteritems() if k and (k not in keys))
-
-
-def _scrub_zone(zone):
- return _exclude_keys(zone, ('username', 'password', 'created_at',
- 'deleted', 'deleted_at', 'updated_at'))
-
-
-def check_encryption_key(func):
- def wrapped(*args, **kwargs):
- if not FLAGS.build_plan_encryption_key:
- raise exception.Error(_("--build_plan_encryption_key not set"))
- return func(*args, **kwargs)
- return wrapped
-
-
-class Controller(object):
- """Controller for Zone resources."""
-
- def __init__(self):
- self.compute_api = compute.API()
-
- def index(self, req):
- """Return all zones in brief"""
- # Ask the ZoneManager in the Scheduler for most recent data,
- # or fall-back to the database ...
- items = api.get_zone_list(req.environ['nova.context'])
- items = common.limited(items, req)
- items = [_scrub_zone(item) for item in items]
- return dict(zones=items)
-
- def detail(self, req):
- """Return all zones in detail"""
- return self.index(req)
-
- def info(self, req):
- """Return name and capabilities for this zone."""
- items = api.get_zone_capabilities(req.environ['nova.context'])
-
- zone = dict(name=FLAGS.zone_name)
- caps = FLAGS.zone_capabilities
- for cap in caps:
- key, value = cap.split('=')
- zone[key] = value
- for item, (min_value, max_value) in items.iteritems():
- zone[item] = "%s,%s" % (min_value, max_value)
- return dict(zone=zone)
-
- def show(self, req, id):
- """Return data about the given zone id"""
- zone_id = int(id)
- zone = api.zone_get(req.environ['nova.context'], zone_id)
- return dict(zone=_scrub_zone(zone))
-
- def delete(self, req, id):
- """Delete a child zone entry."""
- zone_id = int(id)
- api.zone_delete(req.environ['nova.context'], zone_id)
- return {}
-
- def create(self, req, body):
- """Create a child zone entry."""
- context = req.environ['nova.context']
- zone = api.zone_create(context, body["zone"])
- return dict(zone=_scrub_zone(zone))
-
- def update(self, req, id, body):
- """Update a child zone entry."""
- context = req.environ['nova.context']
- zone_id = int(id)
- zone = api.zone_update(context, zone_id, body["zone"])
- return dict(zone=_scrub_zone(zone))
-
- @check_encryption_key
- def select(self, req, body):
- """Returns a weighted list of costs to create instances
- of desired capabilities."""
- ctx = req.environ['nova.context']
- specs = json.loads(body)
- build_plan = api.select(ctx, specs=specs)
- cooked = self._scrub_build_plan(build_plan)
- return {"weights": cooked}
-
- def _scrub_build_plan(self, build_plan):
- """Remove all the confidential data and return a sanitized
- version of the build plan. Include an encrypted full version
- of the weighting entry so we can get back to it later."""
- encryptor = crypto.encryptor(FLAGS.build_plan_encryption_key)
- cooked = []
- for entry in build_plan:
- json_entry = json.dumps(entry)
- cipher_text = encryptor(json_entry)
- cooked.append(dict(weight=entry['weight'],
- blob=cipher_text))
- return cooked
-
-
-class CapabilitySelector(object):
- def __call__(self, obj, do_raise=False):
- return [(k, v) for k, v in obj.items()
- if k not in ('id', 'api_url', 'name', 'capabilities')]
-
-
-def make_zone(elem):
- #elem = xmlutil.SubTemplateElement(parent, 'zone', selector=selector)
- elem.set('id')
- elem.set('api_url')
- elem.set('name')
- elem.set('capabilities')
-
- cap = xmlutil.SubTemplateElement(elem, xmlutil.Selector(0),
- selector=CapabilitySelector())
- cap.text = 1
-
-
-zone_nsmap = {None: wsgi.XMLNS_V10}
-
-
-class ZoneTemplate(xmlutil.TemplateBuilder):
- def construct(self):
- root = xmlutil.TemplateElement('zone', selector='zone')
- make_zone(root)
- return xmlutil.MasterTemplate(root, 1, nsmap=zone_nsmap)
-
-
-class ZonesTemplate(xmlutil.TemplateBuilder):
- def construct(self):
- root = xmlutil.TemplateElement('zones')
- elem = xmlutil.SubTemplateElement(root, 'zone', selector='zones')
- make_zone(elem)
- return xmlutil.MasterTemplate(root, 1, nsmap=zone_nsmap)
-
-
-class WeightsTemplate(xmlutil.TemplateBuilder):
- def construct(self):
- root = xmlutil.TemplateElement('weights')
- weight = xmlutil.SubTemplateElement(root, 'weight', selector='weights')
- blob = xmlutil.SubTemplateElement(weight, 'blob')
- blob.text = 'blob'
- inner_weight = xmlutil.SubTemplateElement(weight, 'weight')
- inner_weight.text = 'weight'
- return xmlutil.MasterTemplate(root, 1, nsmap=zone_nsmap)
-
-
-class ZonesXMLSerializer(xmlutil.XMLTemplateSerializer):
- def index(self):
- return ZonesTemplate()
-
- def detail(self):
- return ZonesTemplate()
-
- def select(self):
- return WeightsTemplate()
-
- def default(self):
- return ZoneTemplate()
-
-
-def create_resource():
- body_serializers = {
- 'application/xml': ZonesXMLSerializer(),
- }
- serializer = wsgi.ResponseSerializer(body_serializers)
-
- body_deserializers = {
- 'application/xml': servers.ServerXMLDeserializer(),
- }
- deserializer = wsgi.RequestDeserializer(body_deserializers)
-
- return wsgi.Resource(Controller(), deserializer, serializer)