summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-07-05 22:20:58 +0000
committerGerrit Code Review <review@openstack.org>2012-07-05 22:20:58 +0000
commitefa69b44ccdacc788a39b893d46168a725c95ec2 (patch)
treea87defd95abff8ee5c746abd38acb7b81f96b0e8
parent6335e66e1c1a825c28cb7beb46ef913401693bae (diff)
parent6222385d837f90f769c94f21d003999741c4f800 (diff)
downloadnova-efa69b44ccdacc788a39b893d46168a725c95ec2.tar.gz
nova-efa69b44ccdacc788a39b893d46168a725c95ec2.tar.xz
nova-efa69b44ccdacc788a39b893d46168a725c95ec2.zip
Merge "Get hypervisor uptime."
-rw-r--r--nova/api/openstack/compute/contrib/hypervisors.py43
-rw-r--r--nova/compute/api.py6
-rw-r--r--nova/compute/manager.py7
-rw-r--r--nova/compute/rpcapi.py7
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_hypervisors.py41
-rw-r--r--nova/tests/compute/test_compute.py13
-rw-r--r--nova/tests/compute/test_rpcapi.py3
-rw-r--r--nova/tests/test_virt_drivers.py4
-rw-r--r--nova/tests/test_xenapi.py4
-rw-r--r--nova/virt/driver.py5
-rw-r--r--nova/virt/xenapi/connection.py4
-rw-r--r--nova/virt/xenapi/fake.py2
-rw-r--r--nova/virt/xenapi/host.py5
-rwxr-xr-xplugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost9
14 files changed, 148 insertions, 5 deletions
diff --git a/nova/api/openstack/compute/contrib/hypervisors.py b/nova/api/openstack/compute/contrib/hypervisors.py
index 084d87575..49b050871 100644
--- a/nova/api/openstack/compute/contrib/hypervisors.py
+++ b/nova/api/openstack/compute/contrib/hypervisors.py
@@ -20,6 +20,7 @@ import webob.exc
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
+from nova.compute import api as compute_api
from nova import db
from nova import exception
from nova.openstack.common import log as logging
@@ -79,6 +80,14 @@ class HypervisorTemplate(xmlutil.TemplateBuilder):
return xmlutil.MasterTemplate(root, 1)
+class HypervisorUptimeTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('hypervisor', selector='hypervisor')
+ make_hypervisor(root, False)
+ root.set('uptime')
+ return xmlutil.MasterTemplate(root, 1)
+
+
class HypervisorServersTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('hypervisors')
@@ -98,7 +107,11 @@ class HypervisorServersTemplate(xmlutil.TemplateBuilder):
class HypervisorsController(object):
"""The Hypervisors API controller for the OpenStack API."""
- def _view_hypervisor(self, hypervisor, detail, servers=None):
+ def __init__(self):
+ self.api = compute_api.HostAPI()
+ super(HypervisorsController, self).__init__()
+
+ def _view_hypervisor(self, hypervisor, detail, servers=None, **kwargs):
hyp_dict = {
'id': hypervisor['id'],
'hypervisor_hostname': hypervisor['hypervisor_hostname'],
@@ -121,6 +134,10 @@ class HypervisorsController(object):
hyp_dict['servers'] = [dict(name=serv['name'], uuid=serv['uuid'])
for serv in servers]
+ # Add any additional info
+ if kwargs:
+ hyp_dict.update(kwargs)
+
return hyp_dict
@wsgi.serializers(xml=HypervisorIndexTemplate)
@@ -148,6 +165,26 @@ class HypervisorsController(object):
raise webob.exc.HTTPNotFound(explanation=msg)
return dict(hypervisor=self._view_hypervisor(hyp, True))
+ @wsgi.serializers(xml=HypervisorUptimeTemplate)
+ def uptime(self, req, id):
+ context = req.environ['nova.context']
+ authorize(context)
+ try:
+ hyp = db.compute_node_get(context, int(id))
+ except (ValueError, exception.ComputeHostNotFound):
+ msg = _("Hypervisor with ID '%s' could not be found.") % id
+ raise webob.exc.HTTPNotFound(explanation=msg)
+
+ # Get the uptime
+ try:
+ uptime = self.api.get_host_uptime(context, hyp)
+ except NotImplementedError:
+ msg = _("Virt driver does not implement uptime function.")
+ raise webob.exc.HTTPNotImplemented(explanation=msg)
+
+ return dict(hypervisor=self._view_hypervisor(hyp, False,
+ uptime=uptime))
+
@wsgi.serializers(xml=HypervisorIndexTemplate)
def search(self, req, id):
context = req.environ['nova.context']
@@ -187,6 +224,8 @@ class Hypervisors(extensions.ExtensionDescriptor):
resources = [extensions.ResourceExtension('os-hypervisors',
HypervisorsController(),
collection_actions={'detail': 'GET'},
- member_actions={'search': 'GET', 'servers': 'GET'})]
+ member_actions={'uptime': 'GET',
+ 'search': 'GET',
+ 'servers': 'GET'})]
return resources
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 771ed8b17..70528271f 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -1662,6 +1662,12 @@ class HostAPI(base.Base):
return self.compute_rpcapi.set_host_enabled(context, enabled=enabled,
host=host)
+ def get_host_uptime(self, context, host):
+ """Returns the result of calling "uptime" on the target host."""
+ # NOTE(comstud): No instance_uuid argument to this compute manager
+ # call
+ return self.compute_rpcapi.get_host_uptime(context, host=host)
+
def host_power_action(self, context, host, action):
"""Reboots, shuts down or powers up the host."""
# NOTE(comstud): No instance_uuid argument to this compute manager
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index fce50ee4a..a9e9e1562 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -228,7 +228,7 @@ def _get_additional_capabilities():
class ComputeManager(manager.SchedulerDependentManager):
"""Manages the running instances from creation to destruction."""
- RPC_API_VERSION = '1.0'
+ RPC_API_VERSION = '1.1'
def __init__(self, compute_driver=None, *args, **kwargs):
"""Load configuration options and connect to the hypervisor."""
@@ -1593,6 +1593,11 @@ class ComputeManager(manager.SchedulerDependentManager):
return self.driver.set_host_enabled(host, enabled)
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
+ def get_host_uptime(self, context, host):
+ """Returns the result of calling "uptime" on the target host."""
+ return self.driver.get_host_uptime(host)
+
+ @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
@wrap_instance_fault
def get_diagnostics(self, context, instance_uuid):
"""Retrieve diagnostics for an instance on this host."""
diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py
index 7a531fcf5..116b2d34b 100644
--- a/nova/compute/rpcapi.py
+++ b/nova/compute/rpcapi.py
@@ -54,9 +54,10 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy):
API version history:
1.0 - Initial version.
+ 1.1 - Adds get_host_uptime()
'''
- RPC_API_VERSION = '1.0'
+ RPC_API_VERSION = '1.1'
def __init__(self):
super(ComputeAPI, self).__init__(topic=FLAGS.compute_topic,
@@ -313,6 +314,10 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy):
return self.call(ctxt, self.make_msg('set_host_enabled',
enabled=enabled), topic)
+ def get_host_uptime(self, ctxt, host):
+ topic = _compute_topic(self.topic, ctxt, host, None)
+ return self.call(ctxt, self.make_msg('get_host_uptime'), topic)
+
def snapshot_instance(self, ctxt, instance, image_id, image_type,
backup_type, rotation):
self.cast(ctxt, self.make_msg('snapshot_instance',
diff --git a/nova/tests/api/openstack/compute/contrib/test_hypervisors.py b/nova/tests/api/openstack/compute/contrib/test_hypervisors.py
index b00497ecc..6a9a1fc25 100644
--- a/nova/tests/api/openstack/compute/contrib/test_hypervisors.py
+++ b/nova/tests/api/openstack/compute/contrib/test_hypervisors.py
@@ -231,6 +231,36 @@ class HypervisorsTest(test.TestCase):
cpu_info='cpu_info',
disk_available_least=100)))
+ def test_uptime_noid(self):
+ req = fakes.HTTPRequest.blank('/v2/fake/os-hypervisors/3')
+ self.assertRaises(exc.HTTPNotFound, self.controller.show, req, '3')
+
+ def test_uptime_notimplemented(self):
+ def fake_get_host_uptime(context, hyp):
+ raise exc.HTTPNotImplemented()
+
+ self.stubs.Set(self.controller.api, 'get_host_uptime',
+ fake_get_host_uptime)
+
+ req = fakes.HTTPRequest.blank('/v2/fake/os-hypervisors/1')
+ self.assertRaises(exc.HTTPNotImplemented,
+ self.controller.uptime, req, '1')
+
+ def test_uptime_implemented(self):
+ def fake_get_host_uptime(context, hyp):
+ return "fake uptime"
+
+ self.stubs.Set(self.controller.api, 'get_host_uptime',
+ fake_get_host_uptime)
+
+ req = fakes.HTTPRequest.blank('/v2/fake/os-hypervisors/1')
+ result = self.controller.uptime(req, '1')
+
+ self.assertEqual(result, dict(hypervisor=dict(
+ id=1,
+ hypervisor_hostname="hyper1",
+ uptime="fake uptime")))
+
def test_search(self):
req = fakes.HTTPRequest.blank('/v2/fake/os-hypervisors/hyper/search')
result = self.controller.search(req, 'hyper')
@@ -374,6 +404,17 @@ class HypervisorsSerializersTest(test.TestCase):
self.compare_to_exemplar(exemplar['hypervisor'], tree)
+ def test_uptime_serializer(self):
+ serializer = hypervisors.HypervisorUptimeTemplate()
+ exemplar = dict(hypervisor=dict(
+ hypervisor_hostname="hyper1",
+ id=1,
+ uptime='fake uptime'))
+ text = serializer.serialize(exemplar)
+ tree = etree.fromstring(text)
+
+ self.compare_to_exemplar(exemplar['hypervisor'], tree)
+
def test_servers_serializer(self):
serializer = hypervisors.HypervisorServersTemplate()
exemplar = dict(hypervisors=[
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index bd7db1c37..784054d0e 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -4057,6 +4057,19 @@ class ComputeHostAPITestCase(BaseTestCase):
'args': {'enabled': 'fake_enabled'},
'version': compute_rpcapi.ComputeAPI.RPC_API_VERSION})
+ def test_get_host_uptime(self):
+ ctxt = context.RequestContext('fake', 'fake')
+ call_info = {}
+ self._rpc_call_stub(call_info)
+
+ self.host_api.get_host_uptime(ctxt, 'fake_host')
+ self.assertEqual(call_info['context'], ctxt)
+ self.assertEqual(call_info['topic'], 'compute.fake_host')
+ self.assertEqual(call_info['msg'],
+ {'method': 'get_host_uptime',
+ 'args': {},
+ 'version': compute_rpcapi.ComputeAPI.RPC_API_VERSION})
+
def test_host_power_action(self):
ctxt = context.RequestContext('fake', 'fake')
call_info = {}
diff --git a/nova/tests/compute/test_rpcapi.py b/nova/tests/compute/test_rpcapi.py
index 37427477f..4f606c7b5 100644
--- a/nova/tests/compute/test_rpcapi.py
+++ b/nova/tests/compute/test_rpcapi.py
@@ -281,6 +281,9 @@ class ComputeRpcAPITestCase(test.TestCase):
self._test_compute_api('set_host_enabled', 'call',
enabled='enabled', host='host')
+ def test_get_host_uptime(self):
+ self._test_compute_api('get_host_uptime', 'call', host='host')
+
def test_snapshot_instance(self):
self._test_compute_api('snapshot_instance', 'cast',
instance=self.fake_instance, image_id='id', image_type='type',
diff --git a/nova/tests/test_virt_drivers.py b/nova/tests/test_virt_drivers.py
index 56efc75f9..e95d15ae5 100644
--- a/nova/tests/test_virt_drivers.py
+++ b/nova/tests/test_virt_drivers.py
@@ -522,6 +522,10 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase):
self.connection.set_host_enabled('a useless argument?', True)
@catch_notimplementederror
+ def test_get_host_uptime(self):
+ self.connection.get_host_uptime('a useless argument?')
+
+ @catch_notimplementederror
def test_host_power_action_reboot(self):
self.connection.host_power_action('a useless argument?', 'reboot')
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index e39049d34..3138ef0b9 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -1162,6 +1162,10 @@ class XenAPIHostTestCase(stubs.XenAPITestBase):
def test_set_enable_host_disable(self):
self._test_host_action(self.conn.set_host_enabled, False, 'disabled')
+ def test_get_host_uptime(self):
+ result = self.conn.get_host_uptime('host')
+ self.assertEqual(result, 'fake uptime')
+
class XenAPIAutoDiskConfigTestCase(stubs.XenAPITestBase):
def setUp(self):
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index d01fc7898..ad73b1896 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -548,6 +548,11 @@ class ComputeDriver(object):
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
+ def get_host_uptime(self, host):
+ """Returns the result of calling "uptime" on the target host."""
+ # TODO(Vek): Need to pass context in for access to auth_token
+ raise NotImplementedError()
+
def plug_vifs(self, instance, network_info):
"""Plug VIFs into networks."""
# TODO(Vek): Need to pass context in for access to auth_token
diff --git a/nova/virt/xenapi/connection.py b/nova/virt/xenapi/connection.py
index 4d29b7ed8..6db5e5b73 100644
--- a/nova/virt/xenapi/connection.py
+++ b/nova/virt/xenapi/connection.py
@@ -474,6 +474,10 @@ class XenAPIDriver(driver.ComputeDriver):
"""Sets the specified host's ability to accept new instances."""
return self._host.set_host_enabled(host, enabled)
+ def get_host_uptime(self, host):
+ """Returns the result of calling "uptime" on the target host."""
+ return self._host.get_host_uptime(host)
+
def host_maintenance_mode(self, host, mode):
"""Start/Stop host maintenance window. On start, it triggers
guest VMs evacuation."""
diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py
index 48c9c1083..72008a69d 100644
--- a/nova/virt/xenapi/fake.py
+++ b/nova/virt/xenapi/fake.py
@@ -522,6 +522,8 @@ class SessionBase(object):
elif (plugin, method) == ('xenhost', 'set_host_enabled'):
enabled = 'enabled' if _5.get('enabled') == 'true' else 'disabled'
return jsonutils.dumps({"status": enabled})
+ elif (plugin, method) == ('xenhost', 'host_uptime'):
+ return jsonutils.dumps({"uptime": "fake uptime"})
else:
raise Exception('No simulation in host_call_plugin for %s,%s' %
(plugin, method))
diff --git a/nova/virt/xenapi/host.py b/nova/virt/xenapi/host.py
index 4633695fd..6594600d5 100644
--- a/nova/virt/xenapi/host.py
+++ b/nova/virt/xenapi/host.py
@@ -116,6 +116,11 @@ class Host(object):
response = call_xenhost(self._session, "set_host_enabled", args)
return response.get("status", response)
+ def get_host_uptime(self, _host):
+ """Returns the result of calling "uptime" on the target host."""
+ response = call_xenhost(self._session, "host_uptime", {})
+ return response.get("uptime", response)
+
class HostState(object):
"""Manages information about the XenServer host this compute
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
index d7effba19..4006de420 100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
@@ -339,6 +339,12 @@ def parse_response(resp):
return data
+@jsonify
+def host_uptime(self, arg_dict):
+ """Returns the result of the uptime command on the xenhost."""
+ return {"uptime": _run_command('uptime')}
+
+
def cleanup(dct):
"""Take the raw KV pairs returned and translate them into the
appropriate types, discarding any we don't need.
@@ -432,4 +438,5 @@ if __name__ == "__main__":
"host_join": host_join,
"get_config": get_config,
"set_config": set_config,
- "iptables_config": iptables_config})
+ "iptables_config": iptables_config,
+ "host_uptime": host_uptime})