summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorSandy Walsh <sandy.walsh@rackspace.com>2010-12-14 04:25:39 -0400
committerSandy Walsh <sandy.walsh@rackspace.com>2010-12-14 04:25:39 -0400
commit90190eb3b4d285cab2e8884045f361ea9441a84a (patch)
tree259e4d8e73a2bd3cf708ed5cb5a7ab9f45a46f41 /nova
parent99ba9bc7c4cd7bdb085e76a8f926ade27d558a84 (diff)
parent911f11139926a772a5d90b8ec65cc4cb7ad850e9 (diff)
fixup after merge with trunk
Diffstat (limited to 'nova')
-rw-r--r--nova/api/ec2/cloud.py6
-rw-r--r--nova/api/openstack/__init__.py9
-rw-r--r--nova/api/openstack/auth.py4
-rw-r--r--nova/api/openstack/images.py9
-rw-r--r--nova/api/openstack/servers.py47
-rw-r--r--nova/compute/instance_types.py4
-rw-r--r--nova/tests/api/openstack/fakes.py13
-rw-r--r--nova/tests/api/openstack/test_auth.py3
-rw-r--r--nova/tests/api/openstack/test_servers.py5
-rw-r--r--nova/tests/cloud_unittest.py13
-rw-r--r--nova/virt/xenapi/vm_utils.py52
-rw-r--r--nova/virt/xenapi/vmops.py12
-rw-r--r--nova/virt/xenapi_conn.py4
13 files changed, 130 insertions, 51 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 05f8c3d0b..ebb13aedc 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -450,13 +450,15 @@ class CloudController(object):
"Timestamp": now,
"output": base64.b64encode(output)}
- def describe_volumes(self, context, **kwargs):
+ def describe_volumes(self, context, volume_id=None, **kwargs):
if context.user.is_admin():
volumes = db.volume_get_all(context)
else:
volumes = db.volume_get_all_by_project(context, context.project_id)
- volumes = [self._format_volume(context, v) for v in volumes]
+ # NOTE(vish): volume_id is an optional list of volume ids to filter by.
+ volumes = [self._format_volume(context, v) for v in volumes
+ if volume_id is None or v['ec2_id'] in volume_id]
return {'volumeSet': volumes}
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index 24042b42b..210df8d24 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -30,6 +30,7 @@ import webob.dec
import webob.exc
import webob
+from nova import context
from nova import flags
from nova import utils
from nova import wsgi
@@ -88,9 +89,7 @@ class AuthMiddleware(wsgi.Middleware):
if not user:
return faults.Fault(webob.exc.HTTPUnauthorized())
- if 'nova.context' not in req.environ:
- req.environ['nova.context'] = {}
- req.environ['nova.context']['user'] = user
+ req.environ['nova.context'] = context.RequestContext(user, user)
return self.application
@@ -125,12 +124,12 @@ class RateLimitingMiddleware(wsgi.Middleware):
If the request should be rate limited, return a 413 status with a
Retry-After header giving the time when the request would succeed.
"""
- user_id = req.environ['nova.context']['user']['id']
action_name = self.get_action_name(req)
if not action_name:
# Not rate limited
return self.application
- delay = self.get_delay(action_name, user_id)
+ delay = self.get_delay(action_name,
+ req.environ['nova.context'].user_id)
if delay:
# TODO(gundlach): Get the retry-after format correct.
exc = webob.exc.HTTPRequestEntityTooLarge(
diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py
index 205035915..fcda97ab1 100644
--- a/nova/api/openstack/auth.py
+++ b/nova/api/openstack/auth.py
@@ -74,9 +74,7 @@ class BasicApiAuthManager(object):
if delta.days >= 2:
self.db.auth_destroy_token(self.context, token)
else:
- #TODO(gundlach): Why not just return dict(id=token.user_id)?
- user = self.auth.get_user(token.user_id)
- return {'id': 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/images.py b/nova/api/openstack/images.py
index cdbdc9bdd..4a0a8e6f1 100644
--- a/nova/api/openstack/images.py
+++ b/nova/api/openstack/images.py
@@ -17,7 +17,6 @@
from webob import exc
-from nova import context
from nova import flags
from nova import utils
from nova import wsgi
@@ -47,10 +46,8 @@ class Controller(wsgi.Controller):
def detail(self, req):
"""Return all public images in detail."""
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
try:
- images = self._service.detail(ctxt)
+ images = self._service.detail(req.environ['nova.context'])
images = nova.api.openstack.limited(images, req)
except NotImplementedError:
# Emulate detail() using repeated calls to show()
@@ -61,9 +58,7 @@ class Controller(wsgi.Controller):
def show(self, req, id):
"""Return data about the given image id."""
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
- return dict(image=self._service.show(ctxt, id))
+ return dict(image=self._service.show(req.environ['nova.context'], id))
def delete(self, req, id):
# Only public images are supported for now.
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index ade0d7eb9..dcd959ae7 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -20,7 +20,6 @@ import traceback
from webob import exc
-from nova import context
from nova import exception
from nova import wsgi
from nova.api.openstack import faults
@@ -97,29 +96,26 @@ class Controller(wsgi.Controller):
entity_maker - either _entity_detail or _entity_inst
"""
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
- instance_list = self.compute_api.get_instances(ctxt)
+ instance_list = self.compute_api.get_instances(
+ req.environ['nova.context'])
limited_list = nova.api.openstack.limited(instance_list, req)
res = [entity_maker(inst)['server'] for inst in limited_list]
return _entity_list(res)
def show(self, req, id):
""" Returns server details by server id """
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
- inst = self.compute_api.get_instance(ctxt, int(id))
- if inst:
- if inst.user_id == user_id:
- return _entity_detail(inst)
- raise faults.Fault(exc.HTTPNotFound())
+ try:
+ instance = self.compute_api.get_instance(
+ req.environ['nova.context'], int(id))
+ return _entity_detail(instance)
+ except exception.NotFound:
+ return faults.Fault(exc.HTTPNotFound())
def delete(self, req, id):
""" Destroys a server """
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
try:
- self.compute_api.delete_instance(ctxt, int(id))
+ self.compute_api.delete_instance(req.environ['nova.context'],
+ int(id))
except exception.NotFound:
return faults.Fault(exc.HTTPNotFound())
return exc.HTTPAccepted()
@@ -130,10 +126,10 @@ class Controller(wsgi.Controller):
if not env:
return faults.Fault(exc.HTTPUnprocessableEntity())
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
- key_pair = auth_manager.AuthManager.get_key_pairs(ctxt)[0]
- instances = self.compute_api.create_instances(ctxt,
+ key_pair = auth_manager.AuthManager.get_key_pairs(
+ req.environ['nova.context'])[0]
+ instances = self.compute_api.create_instances(
+ req.environ['nova.context'],
instance_types.get_by_flavor_id(env['server']['flavorId']),
env['server']['imageId'],
display_name=env['server']['name'],
@@ -144,8 +140,6 @@ class Controller(wsgi.Controller):
def update(self, req, id):
""" Updates the server name or password """
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
inst_dict = self._deserialize(req.body, req)
if not inst_dict:
return faults.Fault(exc.HTTPUnprocessableEntity())
@@ -157,7 +151,8 @@ class Controller(wsgi.Controller):
update_dict['display_name'] = inst_dict['server']['name']
try:
- self.compute_api.update_instance(ctxt, instance['id'],
+ self.compute_api.update_instance(req.environ['nova.context'],
+ instance['id'],
**update_dict)
except exception.NotFound:
return faults.Fault(exc.HTTPNotFound())
@@ -166,8 +161,6 @@ class Controller(wsgi.Controller):
def action(self, req, id):
""" Multi-purpose method used to reboot, rebuild, and
resize a server """
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
input_dict = self._deserialize(req.body, req)
try:
reboot_type = input_dict['reboot']['type']
@@ -176,15 +169,14 @@ class Controller(wsgi.Controller):
try:
# TODO(gundlach): pass reboot_type, support soft reboot in
# virt driver
- self.compute_api.reboot(ctxt, id)
+ self.compute_api.reboot(req.environ['nova.context'], id)
except:
return faults.Fault(exc.HTTPUnprocessableEntity())
return exc.HTTPAccepted()
def pause(self, req, id):
""" Permit Admins to Pause the server. """
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
+ ctxt = req.environ['nova.context']
try:
self.compute_api.pause(ctxt, id)
except:
@@ -195,8 +187,7 @@ class Controller(wsgi.Controller):
def unpause(self, req, id):
""" Permit Admins to Unpause the server. """
- user_id = req.environ['nova.context']['user']['id']
- ctxt = context.RequestContext(user_id, user_id)
+ ctxt = req.environ['nova.context']
try:
self.compute_api.unpause(ctxt, id)
except:
diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py
index a2679e0fc..6e47170bd 100644
--- a/nova/compute/instance_types.py
+++ b/nova/compute/instance_types.py
@@ -22,6 +22,7 @@ The built-in instance properties.
"""
from nova import flags
+from nova import exception
FLAGS = flags.FLAGS
INSTANCE_TYPES = {
@@ -37,8 +38,7 @@ def get_by_type(instance_type):
if instance_type is None:
return FLAGS.default_instance_type
if instance_type not in INSTANCE_TYPES:
- raise exception.ApiError("Unknown instance type: %s",
- instance_type)
+ raise exception.ApiError("Unknown instance type: %s" % instance_type)
return instance_type
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index c3f129a32..21b8aac1c 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -24,9 +24,10 @@ import webob
import webob.dec
from nova import auth
-from nova import utils
-from nova import flags
+from nova import context
from nova import exception as exc
+from nova import flags
+from nova import utils
import nova.api.openstack.auth
from nova.image import service
from nova.image import glance
@@ -58,7 +59,7 @@ def fake_auth_init(self):
@webob.dec.wsgify
def fake_wsgi(self, req):
- req.environ['nova.context'] = dict(user=dict(id=1))
+ req.environ['nova.context'] = context.RequestContext(1, 1)
if req.body:
req.environ['inst_dict'] = json.loads(req.body)
return self.application
@@ -171,6 +172,12 @@ class FakeToken(object):
setattr(self, k, v)
+class FakeRequestContext(object):
+ def __init__(self, user, project):
+ self.user_id = 1
+ self.project_id = 1
+
+
class FakeAuthDatabase(object):
data = {}
diff --git a/nova/tests/api/openstack/test_auth.py b/nova/tests/api/openstack/test_auth.py
index 14e720be4..7b427c2db 100644
--- a/nova/tests/api/openstack/test_auth.py
+++ b/nova/tests/api/openstack/test_auth.py
@@ -26,6 +26,7 @@ import nova.api
import nova.api.openstack.auth
import nova.auth.manager
from nova import auth
+from nova import context
from nova.tests.api.openstack import fakes
@@ -35,6 +36,7 @@ class Test(unittest.TestCase):
self.stubs = stubout.StubOutForTesting()
self.stubs.Set(nova.api.openstack.auth.BasicApiAuthManager,
'__init__', fakes.fake_auth_init)
+ self.stubs.Set(context, 'RequestContext', fakes.FakeRequestContext)
fakes.FakeAuthManager.auth_data = {}
fakes.FakeAuthDatabase.data = {}
fakes.stub_out_rate_limiting(self.stubs)
@@ -131,6 +133,7 @@ class TestLimiter(unittest.TestCase):
self.stubs = stubout.StubOutForTesting()
self.stubs.Set(nova.api.openstack.auth.BasicApiAuthManager,
'__init__', fakes.fake_auth_init)
+ self.stubs.Set(context, 'RequestContext', fakes.FakeRequestContext)
fakes.FakeAuthManager.auth_data = {}
fakes.FakeAuthDatabase.data = {}
fakes.stub_out_networking(self.stubs)
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 636da30fd..8e48017d0 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -84,7 +84,10 @@ class ServersTest(unittest.TestCase):
instance_address)
self.stubs.Set(nova.db.api, 'instance_get_floating_address',
instance_address)
- self.stubs.Set(nova.compute.api.ComputeAPI, 'pause', fake_compute_api)
+ self.stubs.Set(nova.compute.api.ComputeAPI, 'pause',
+ fake_compute_api)
+ self.stubs.Set(nova.compute.api.ComputeAPI, 'unpause',
+ fake_compute_api)
self.allow_admin = FLAGS.allow_admin_api
def tearDown(self):
diff --git a/nova/tests/cloud_unittest.py b/nova/tests/cloud_unittest.py
index 9886a2449..770c94219 100644
--- a/nova/tests/cloud_unittest.py
+++ b/nova/tests/cloud_unittest.py
@@ -126,6 +126,19 @@ class CloudTestCase(test.TrialTestCase):
db.instance_destroy(self.context, inst['id'])
db.floating_ip_destroy(self.context, address)
+ def test_describe_volumes(self):
+ """Makes sure describe_volumes works and filters results."""
+ vol1 = db.volume_create(self.context, {})
+ vol2 = db.volume_create(self.context, {})
+ result = self.cloud.describe_volumes(self.context)
+ self.assertEqual(len(result['volumeSet']), 2)
+ result = self.cloud.describe_volumes(self.context,
+ volume_id=[vol2['ec2_id']])
+ self.assertEqual(len(result['volumeSet']), 1)
+ self.assertEqual(result['volumeSet'][0]['volumeId'], vol2['ec2_id'])
+ db.volume_destroy(self.context, vol1['id'])
+ db.volume_destroy(self.context, vol2['id'])
+
def test_console_output(self):
image_id = FLAGS.default_image
instance_type = FLAGS.default_instance_type
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 99d484ca2..77edb576e 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -20,15 +20,21 @@ their attributes like VDIs, VIFs, as well as their lookup functions.
"""
import logging
+import urllib
from twisted.internet import defer
+from xml.dom import minidom
+from nova import flags
from nova import utils
+
from nova.auth.manager import AuthManager
from nova.compute import instance_types
from nova.compute import power_state
from nova.virt import images
+FLAGS = flags.FLAGS
+
XENAPI_POWER_STATE = {
'Halted': power_state.SHUTDOWN,
'Running': power_state.RUNNING,
@@ -44,6 +50,15 @@ class VMHelper():
The class that wraps the helper methods together.
"""
def __init__(self):
+ return
+
+ @classmethod
+ def late_import(cls):
+ """
+ Load the XenAPI module in for helper class, if required.
+ This is to avoid to install the XenAPI library when other
+ hypervisors are used
+ """
global XenAPI
if XenAPI is None:
XenAPI = __import__('XenAPI')
@@ -214,3 +229,40 @@ class VMHelper():
'mem': long(record['memory_dynamic_max']) >> 10,
'num_cpu': record['VCPUs_max'],
'cpu_time': 0}
+
+ @classmethod
+ def compile_diagnostics(cls, session, record):
+ """Compile VM diagnostics data"""
+ try:
+ host = session.get_xenapi_host()
+ host_ip = session.get_xenapi().host.get_record(host)["address"]
+ metrics = session.get_xenapi().VM_guest_metrics.get_record(
+ record["guest_metrics"])
+ diags = {
+ "Kernel": metrics["os_version"]["uname"],
+ "Distro": metrics["os_version"]["name"]}
+ xml = get_rrd(host_ip, record["uuid"])
+ if xml:
+ rrd = minidom.parseString(xml)
+ for i, node in enumerate(rrd.firstChild.childNodes):
+ # We don't want all of the extra garbage
+ if i >= 3 and i <= 11:
+ ref = node.childNodes
+ # Name and Value
+ diags[ref[0].firstChild.data] = ref[6].firstChild.data
+ return diags
+ except XenAPI.Failure as e:
+ return {"Unable to retrieve diagnostics": e}
+
+
+def get_rrd(host, uuid):
+ """Return the VM RRD XML as a string"""
+ try:
+ xml = urllib.urlopen("http://%s:%s@%s/vm_rrd?uuid=%s" % (
+ FLAGS.xenapi_connection_username,
+ FLAGS.xenapi_connection_password,
+ host,
+ uuid))
+ return xml.read()
+ except IOError:
+ return None
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 03ee3dd58..7c5db0b73 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -24,6 +24,7 @@ from twisted.internet import defer
from nova import db
from nova import context
+
from nova.auth.manager import AuthManager
from nova.virt.xenapi.network_utils import NetworkHelper
from nova.virt.xenapi.vm_utils import VMHelper
@@ -40,6 +41,8 @@ class VMOps(object):
if XenAPI is None:
XenAPI = __import__('XenAPI')
self._session = session
+ # Load XenAPI module in the helper class
+ VMHelper.late_import()
def list_instances(self):
""" List VM instances """
@@ -152,6 +155,15 @@ class VMOps(object):
rec = self._session.get_xenapi().VM.get_record(vm)
return VMHelper.compile_info(rec)
+ @defer.inlineCallbacks
+ def get_diagnostics(self, instance_id):
+ """Return data about VM diagnostics"""
+ vm = yield VMHelper.lookup(self._session, instance_id)
+ if vm is None:
+ raise Exception("instance not present %s" % instance_id)
+ rec = yield self._session.get_xenapi().VM.get_record(vm)
+ defer.returnValue(VMHelper.compile_diagnostics(self._session, rec))
+
def get_console_output(self, instance):
""" Return snapshot of console """
# TODO: implement this to fix pylint!
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index bcfb48323..ebd572258 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -134,6 +134,10 @@ class XenAPIConnection(object):
""" Return data about VM instance """
return self._vmops.get_info(instance_id)
+ def get_diagnostics(self, instance_id):
+ """Return data about VM diagnostics"""
+ return self._vmops.get_diagnostics(instance_id)
+
def get_console_output(self, instance):
""" Return snapshot of console """
return self._vmops.get_console_output(instance)