summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorJohn Tran <jtran@attinteractive.com>2011-05-23 14:27:56 -0700
committerJohn Tran <jtran@attinteractive.com>2011-05-23 14:27:56 -0700
commit1816b3e6a99da512aeb51822e90d40f30b443014 (patch)
tree02d1377b96b41bc7ba1ee9877b425d75cd47b27e /nova/api
parent0a3da155228228d3f0eeac1efdea1e29eef2f3a0 (diff)
parente1795bd73c71a20290bc988c410e0cc30afe6bd8 (diff)
merged from trunk
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/ec2/cloud.py29
-rw-r--r--nova/api/openstack/__init__.py3
-rw-r--r--nova/api/openstack/auth.py17
-rw-r--r--nova/api/openstack/extensions.py84
-rw-r--r--nova/api/openstack/flavors.py3
-rw-r--r--nova/api/openstack/servers.py20
-rw-r--r--nova/api/openstack/views/limits.py9
-rw-r--r--nova/api/openstack/zones.py43
8 files changed, 147 insertions, 61 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index ad8c3fe90..59e00781e 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -27,6 +27,8 @@ import datetime
import IPy
import os
import urllib
+import tempfile
+import shutil
from nova import compute
from nova import context
@@ -35,6 +37,7 @@ from nova import crypto
from nova import db
from nova import exception
from nova import flags
+from nova import ipv6
from nova import log as logging
from nova import network
from nova import utils
@@ -315,6 +318,27 @@ class CloudController(object):
'keyMaterial': data['private_key']}
# TODO(vish): when context is no longer an object, pass it here
+ def import_public_key(self, context, key_name, public_key,
+ fingerprint=None):
+ LOG.audit(_("Import key %s"), key_name, context=context)
+ key = {}
+ key['user_id'] = context.user_id
+ key['name'] = key_name
+ key['public_key'] = public_key
+ if fingerprint is None:
+ tmpdir = tempfile.mkdtemp()
+ pubfile = os.path.join(tmpdir, 'temp.pub')
+ fh = open(pubfile, 'w')
+ fh.write(public_key)
+ fh.close()
+ (out, err) = utils.execute('ssh-keygen', '-q', '-l', '-f',
+ '%s' % (pubfile))
+ fingerprint = out.split(' ')[1]
+ shutil.rmtree(tmpdir)
+ key['fingerprint'] = fingerprint
+ db.key_pair_create(context, key)
+ return True
+
def delete_key_pair(self, context, key_name, **kwargs):
LOG.audit(_("Delete key pair %s"), key_name, context=context)
try:
@@ -718,9 +742,10 @@ class CloudController(object):
fixed = instance['fixed_ip']
floating_addr = fixed['floating_ips'][0]['address']
if instance['fixed_ip']['network'] and 'use_v6' in kwargs:
- i['dnsNameV6'] = utils.to_global_ipv6(
+ i['dnsNameV6'] = ipv6.to_global(
instance['fixed_ip']['network']['cidr_v6'],
- instance['mac_address'])
+ instance['mac_address'],
+ instance['project_id'])
i['privateDnsName'] = fixed_addr
i['privateIpAddress'] = fixed_addr
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index 348b70d5b..5b7f080ad 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -98,7 +98,8 @@ class APIRouter(wsgi.Router):
server_members['inject_network_info'] = 'POST'
mapper.resource("zone", "zones", controller=zones.Controller(),
- collection={'detail': 'GET', 'info': 'GET'}),
+ collection={'detail': 'GET', 'info': 'GET',
+ 'select': 'GET'})
mapper.resource("user", "users", controller=users.Controller(),
collection={'detail': 'GET'})
diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py
index 311e6bde9..6c6ee22a2 100644
--- a/nova/api/openstack/auth.py
+++ b/nova/api/openstack/auth.py
@@ -17,7 +17,6 @@
import datetime
import hashlib
-import json
import time
import webob.exc
@@ -25,11 +24,9 @@ import webob.dec
from nova import auth
from nova import context
-from nova import db
from nova import exception
from nova import flags
from nova import log as logging
-from nova import manager
from nova import utils
from nova import wsgi
from nova.api.openstack import faults
@@ -102,11 +99,11 @@ class AuthMiddleware(wsgi.Middleware):
token, user = self._authorize_user(username, key, req)
if user and token:
res = webob.Response()
- res.headers['X-Auth-Token'] = token.token_hash
+ res.headers['X-Auth-Token'] = token['token_hash']
res.headers['X-Server-Management-Url'] = \
- token.server_management_url
- res.headers['X-Storage-Url'] = token.storage_url
- res.headers['X-CDN-Management-Url'] = token.cdn_management_url
+ token['server_management_url']
+ res.headers['X-Storage-Url'] = token['storage_url']
+ res.headers['X-CDN-Management-Url'] = token['cdn_management_url']
res.content_type = 'text/plain'
res.status = '204'
LOG.debug(_("Successfully authenticated '%s'") % username)
@@ -130,11 +127,11 @@ class AuthMiddleware(wsgi.Middleware):
except exception.NotFound:
return None
if token:
- delta = datetime.datetime.now() - token.created_at
+ delta = datetime.datetime.utcnow() - token['created_at']
if delta.days >= 2:
- self.db.auth_token_destroy(ctxt, token.token_hash)
+ self.db.auth_token_destroy(ctxt, token['token_hash'])
else:
- return self.auth.get_user(token.user_id)
+ return self.auth.get_user(token['user_id'])
return None
def _authorize_user(self, username, key, req):
diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py
index 7ea7afef6..8e77b25fb 100644
--- a/nova/api/openstack/extensions.py
+++ b/nova/api/openstack/extensions.py
@@ -105,15 +105,14 @@ class ExtensionDescriptor(object):
actions = []
return actions
- def get_response_extensions(self):
- """List of extensions.ResponseExtension extension objects.
+ def get_request_extensions(self):
+ """List of extensions.RequestException extension objects.
- Response extensions are used to insert information into existing
- response data.
+ Request extensions are used to handle custom request data.
"""
- response_exts = []
- return response_exts
+ request_exts = []
+ return request_exts
class ActionExtensionController(common.OpenstackController):
@@ -137,7 +136,7 @@ class ActionExtensionController(common.OpenstackController):
return res
-class ResponseExtensionController(common.OpenstackController):
+class RequestExtensionController(common.OpenstackController):
def __init__(self, application):
self.application = application
@@ -148,20 +147,9 @@ class ResponseExtensionController(common.OpenstackController):
def process(self, req, *args, **kwargs):
res = req.get_response(self.application)
- content_type = req.best_match_content_type()
- # currently response handlers are un-ordered
+ # currently request handlers are un-ordered
for handler in self.handlers:
- res = handler(res)
- try:
- body = res.body
- headers = res.headers
- except AttributeError:
- default_xmlns = None
- body = self._serialize(res, content_type, default_xmlns)
- headers = {"Content-Type": content_type}
- res = webob.Response()
- res.body = body
- res.headers = headers
+ res = handler(req, res)
return res
@@ -226,24 +214,24 @@ class ExtensionMiddleware(wsgi.Middleware):
return action_controllers
- def _response_ext_controllers(self, application, ext_mgr, mapper):
- """Returns a dict of ResponseExtensionController-s by collection."""
- response_ext_controllers = {}
- for resp_ext in ext_mgr.get_response_extensions():
- if not resp_ext.key in response_ext_controllers.keys():
- controller = ResponseExtensionController(application)
- mapper.connect(resp_ext.url_route + '.:(format)',
+ def _request_ext_controllers(self, application, ext_mgr, mapper):
+ """Returns a dict of RequestExtensionController-s by collection."""
+ request_ext_controllers = {}
+ for req_ext in ext_mgr.get_request_extensions():
+ if not req_ext.key in request_ext_controllers.keys():
+ controller = RequestExtensionController(application)
+ mapper.connect(req_ext.url_route + '.:(format)',
action='process',
controller=controller,
- conditions=resp_ext.conditions)
+ conditions=req_ext.conditions)
- mapper.connect(resp_ext.url_route,
+ mapper.connect(req_ext.url_route,
action='process',
controller=controller,
- conditions=resp_ext.conditions)
- response_ext_controllers[resp_ext.key] = controller
+ conditions=req_ext.conditions)
+ request_ext_controllers[req_ext.key] = controller
- return response_ext_controllers
+ return request_ext_controllers
def __init__(self, application, ext_mgr=None):
@@ -271,13 +259,13 @@ class ExtensionMiddleware(wsgi.Middleware):
controller = action_controllers[action.collection]
controller.add_action(action.action_name, action.handler)
- # extended responses
- resp_controllers = self._response_ext_controllers(application, ext_mgr,
+ # extended requests
+ req_controllers = self._request_ext_controllers(application, ext_mgr,
mapper)
- for response_ext in ext_mgr.get_response_extensions():
- LOG.debug(_('Extended response: %s'), response_ext.key)
- controller = resp_controllers[response_ext.key]
- controller.add_handler(response_ext.handler)
+ for request_ext in ext_mgr.get_request_extensions():
+ LOG.debug(_('Extended request: %s'), request_ext.key)
+ controller = req_controllers[request_ext.key]
+ controller.add_handler(request_ext.handler)
self._router = routes.middleware.RoutesMiddleware(self._dispatch,
mapper)
@@ -347,17 +335,17 @@ class ExtensionManager(object):
pass
return actions
- def get_response_extensions(self):
- """Returns a list of ResponseExtension objects."""
- response_exts = []
+ def get_request_extensions(self):
+ """Returns a list of RequestExtension objects."""
+ request_exts = []
for alias, ext in self.extensions.iteritems():
try:
- response_exts.extend(ext.get_response_extensions())
+ request_exts.extend(ext.get_request_extensions())
except AttributeError:
- # NOTE(dprince): Extension aren't required to have response
+ # NOTE(dprince): Extension aren't required to have request
# extensions
pass
- return response_exts
+ return request_exts
def _check_extension(self, extension):
"""Checks for required methods in extension objects."""
@@ -421,9 +409,13 @@ class ExtensionManager(object):
self.extensions[alias] = ext
-class ResponseExtension(object):
- """Add data to responses from core nova OpenStack API controllers."""
+class RequestExtension(object):
+ """Extend requests and responses of core nova OpenStack API controllers.
+ Provide a way to add data to responses and handle custom request data
+ that is sent to core nova OpenStack API controllers.
+
+ """
def __init__(self, method, url_route, handler):
self.url_route = url_route
self.handler = handler
diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py
index 40787bd17..4c5971cf6 100644
--- a/nova/api/openstack/flavors.py
+++ b/nova/api/openstack/flavors.py
@@ -45,6 +45,9 @@ class Controller(common.OpenstackController):
items = self._get_flavors(req, is_detail=True)
return dict(flavors=items)
+ def _get_view_builder(self, req):
+ raise NotImplementedError()
+
def _get_flavors(self, req, is_detail=True):
"""Helper function that returns a list of flavor dicts."""
ctxt = req.environ['nova.context']
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 547310613..8f2de2afe 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -75,6 +75,21 @@ class Controller(common.OpenstackController):
""" Returns a list of server details for a given user """
return self._items(req, is_detail=True)
+ def _image_id_from_req_data(self, data):
+ raise NotImplementedError()
+
+ def _flavor_id_from_req_data(self, data):
+ raise NotImplementedError()
+
+ def _get_view_builder(self, req):
+ raise NotImplementedError()
+
+ def _limit_items(self, items, req):
+ raise NotImplementedError()
+
+ def _action_rebuild(self, info, request, instance_id):
+ raise NotImplementedError()
+
def _items(self, req, is_detail):
"""Returns a list of servers for a given user.
@@ -743,8 +758,9 @@ class ServerCreateRequestXMLDeserializer(object):
"""Marshal the server attribute of a parsed request"""
server = {}
server_node = self._find_first_child_named(node, 'server')
- for attr in ["name", "imageId", "flavorId"]:
- server[attr] = server_node.getAttribute(attr)
+ for attr in ["name", "imageId", "flavorId", "imageRef", "flavorRef"]:
+ if server_node.getAttribute(attr):
+ server[attr] = server_node.getAttribute(attr)
metadata = self._extract_metadata(server_node)
if metadata is not None:
server["metadata"] = metadata
diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py
index 552db39ee..22d1c260d 100644
--- a/nova/api/openstack/views/limits.py
+++ b/nova/api/openstack/views/limits.py
@@ -23,6 +23,15 @@ from nova.api.openstack import common
class ViewBuilder(object):
"""Openstack API base limits view builder."""
+ def _build_rate_limits(self, rate_limits):
+ raise NotImplementedError()
+
+ def _build_rate_limit(self, rate_limit):
+ raise NotImplementedError()
+
+ def _build_absolute_limits(self, absolute_limit):
+ raise NotImplementedError()
+
def build(self, rate_limits, absolute_limits):
rate_limits = self._build_rate_limits(rate_limits)
absolute_limits = self._build_absolute_limits(absolute_limits)
diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py
index 227ffecdc..af73d8f6d 100644
--- a/nova/api/openstack/zones.py
+++ b/nova/api/openstack/zones.py
@@ -13,7 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+import json
+import urlparse
+
+from nova import crypto
from nova import db
+from nova import exception
from nova import flags
from nova import log as logging
from nova.api.openstack import common
@@ -21,6 +26,12 @@ from nova.scheduler import api
FLAGS = flags.FLAGS
+flags.DEFINE_string('build_plan_encryption_key',
+ None,
+ '128bit (hex) encryption key for scheduler build plans.')
+
+
+LOG = logging.getLogger('nova.api.openstack.zones')
def _filter_keys(item, keys):
@@ -97,3 +108,35 @@ class Controller(common.OpenstackController):
zone_id = int(id)
zone = api.zone_update(context, zone_id, env["zone"])
return dict(zone=_scrub_zone(zone))
+
+ def select(self, req):
+ """Returns a weighted list of costs to create instances
+ of desired capabilities."""
+ ctx = req.environ['nova.context']
+ qs = req.environ['QUERY_STRING']
+ param_dict = urlparse.parse_qs(qs)
+ param_dict.pop("fresh", None)
+ # parse_qs returns a dict where the values are lists,
+ # since query strings can have multiple values for the
+ # same key. We need to convert that to single values.
+ for key in param_dict:
+ param_dict[key] = param_dict[key][0]
+ build_plan = api.select(ctx, specs=param_dict)
+ 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."""
+ if not FLAGS.build_plan_encryption_key:
+ raise exception.FlagNotSet(flag='build_plan_encryption_key')
+
+ 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