diff options
-rw-r--r-- | nova/api/openstack/compute/contrib/hypervisors.py | 43 | ||||
-rw-r--r-- | nova/compute/api.py | 6 | ||||
-rw-r--r-- | nova/compute/manager.py | 7 | ||||
-rw-r--r-- | nova/compute/rpcapi.py | 7 | ||||
-rw-r--r-- | nova/tests/api/openstack/compute/contrib/test_hypervisors.py | 41 | ||||
-rw-r--r-- | nova/tests/compute/test_compute.py | 13 | ||||
-rw-r--r-- | nova/tests/compute/test_rpcapi.py | 3 | ||||
-rw-r--r-- | nova/tests/test_virt_drivers.py | 4 | ||||
-rw-r--r-- | nova/tests/test_xenapi.py | 4 | ||||
-rw-r--r-- | nova/virt/driver.py | 5 | ||||
-rw-r--r-- | nova/virt/xenapi/connection.py | 4 | ||||
-rw-r--r-- | nova/virt/xenapi/fake.py | 2 | ||||
-rw-r--r-- | nova/virt/xenapi/host.py | 5 | ||||
-rwxr-xr-x | plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost | 9 |
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}) |