summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Leafe <ed@leafe.com>2011-08-01 21:06:47 +0000
committerEd Leafe <ed@leafe.com>2011-08-01 21:06:47 +0000
commit85795ff1f8b6a0ff3de634828208d6debd91692f (patch)
treefb25bb919bfefafca361f1a01f336e3cd935785c
parentbdcfaa5b927a096f507fb0f7e2d81989173957f8 (diff)
downloadnova-85795ff1f8b6a0ff3de634828208d6debd91692f.tar.gz
nova-85795ff1f8b6a0ff3de634828208d6debd91692f.tar.xz
nova-85795ff1f8b6a0ff3de634828208d6debd91692f.zip
Added option for rebooting or shutting down a host.
-rw-r--r--nova/api/openstack/contrib/hosts.py15
-rw-r--r--nova/compute/api.py5
-rw-r--r--nova/compute/manager.py8
-rw-r--r--nova/tests/test_hosts.py9
-rw-r--r--nova/virt/driver.py4
-rw-r--r--nova/virt/fake.py4
-rw-r--r--nova/virt/hyperv.py4
-rw-r--r--nova/virt/libvirt/connection.py4
-rw-r--r--nova/virt/vmwareapi_conn.py4
-rw-r--r--nova/virt/xenapi/vmops.py8
-rw-r--r--nova/virt/xenapi_conn.py4
-rwxr-xr-xplugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost25
12 files changed, 92 insertions, 2 deletions
diff --git a/nova/api/openstack/contrib/hosts.py b/nova/api/openstack/contrib/hosts.py
index 55e57e1a4..b6a4bdb77 100644
--- a/nova/api/openstack/contrib/hosts.py
+++ b/nova/api/openstack/contrib/hosts.py
@@ -78,6 +78,12 @@ class HostController(object):
else:
explanation = _("Invalid status: '%s'") % raw_val
raise webob.exc.HTTPBadRequest(explanation=explanation)
+ elif key == "powerstate":
+ if val in ("reboot", "shutdown"):
+ return self._set_powerstate(req, id, val)
+ else:
+ explanation = _("Invalid powerstate: '%s'") % raw_val
+ raise webob.exc.HTTPBadRequest(explanation=explanation)
else:
explanation = _("Invalid update setting: '%s'") % raw_key
raise webob.exc.HTTPBadRequest(explanation=explanation)
@@ -91,6 +97,15 @@ class HostController(object):
enabled=enabled)
return {"host": host, "status": result}
+ def _set_powerstate(self, req, host, state):
+ """Reboots or shuts down the host."""
+ context = req.environ['nova.context']
+ LOG.audit(_("Changing powerstate of host %(host)s to %(state)s.")
+ % locals())
+ result = self.compute_api.set_host_powerstate(context, host=host,
+ state=state)
+ return {"host": host, "powerstate": result}
+
class Hosts(extensions.ExtensionDescriptor):
def get_name(self):
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 8f7b3c3ef..bd17fdf31 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -998,6 +998,11 @@ class API(base.Base):
return self._call_compute_message("set_host_enabled", context,
instance_id=None, host=host, params={"enabled": enabled})
+ def set_host_powerstate(self, context, host, state):
+ """Reboots or shuts down the host."""
+ return self._call_compute_message("set_host_powerstate", context,
+ instance_id=None, host=host, params={"state": state})
+
@scheduler_api.reroute_compute("diagnostics")
def get_diagnostics(self, context, instance_id):
"""Retrieve diagnostics for the given instance."""
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index a2d84cd76..d0f9a81f4 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -1,4 +1,4 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
+: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
@@ -928,6 +928,12 @@ class ComputeManager(manager.SchedulerDependentManager):
result))
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
+ def set_host_powerstate(self, context, instance_id=None, host=None,
+ state=None):
+ """Reboots or shuts down the host."""
+ return self.driver.set_host_powerstate(host, state)
+
+ @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
def set_host_enabled(self, context, instance_id=None, host=None,
enabled=None):
"""Sets the specified host's ability to accept new instances."""
diff --git a/nova/tests/test_hosts.py b/nova/tests/test_hosts.py
index 548f81f8b..ad057f429 100644
--- a/nova/tests/test_hosts.py
+++ b/nova/tests/test_hosts.py
@@ -48,6 +48,13 @@ def stub_set_host_enabled(context, host, enabled):
return status
+def stub_set_host_powerstate(context, host, state):
+ # We'll simulate success and failure by assuming
+ # that 'host_c1' always succeeds, and 'host_c2'
+ # always fails
+ return state if host == "host_c1" else "running"
+
+
class FakeRequest(object):
environ = {"nova.context": context.get_admin_context()}
@@ -62,6 +69,8 @@ class HostTestCase(test.TestCase):
self.stubs.Set(scheduler_api, 'get_host_list', stub_get_host_list)
self.stubs.Set(self.controller.compute_api, 'set_host_enabled',
stub_set_host_enabled)
+ self.stubs.Set(self.controller.compute_api, 'set_host_powerstate',
+ stub_set_host_powerstate)
def test_list_hosts(self):
"""Verify that the compute hosts are returned."""
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index b219fb2cb..bbb17480d 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -251,6 +251,10 @@ class ComputeDriver(object):
"""Poll for rescued instances"""
raise NotImplementedError()
+ def set_host_powerstate(self, host, state):
+ """Reboots or shuts down the host."""
+ raise NotImplementedError()
+
def set_host_enabled(self, host, enabled):
"""Sets the specified host's ability to accept new instances."""
raise NotImplementedError()
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 26bc421c0..6dc6552d7 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -515,6 +515,10 @@ class FakeConnection(driver.ComputeDriver):
"""Return fake Host Status of ram, disk, network."""
return self.host_status
+ def set_host_powerstate(self, host, state):
+ """Reboots or shuts down the host."""
+ pass
+
def set_host_enabled(self, host, enabled):
"""Sets the specified host's ability to accept new instances."""
pass
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index c26fe108b..119def38b 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -498,6 +498,10 @@ class HyperVConnection(driver.ComputeDriver):
"""See xenapi_conn.py implementation."""
pass
+ def set_host_powerstate(self, host, state):
+ """Reboots or shuts down the host."""
+ pass
+
def set_host_enabled(self, host, enabled):
"""Sets the specified host's ability to accept new instances."""
pass
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index 17c328a83..ae1a16d44 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -1583,6 +1583,10 @@ class LibvirtConnection(driver.ComputeDriver):
"""See xenapi_conn.py implementation."""
pass
+ def set_host_powerstate(self, host, state):
+ """Reboots or shuts down the host."""
+ pass
+
def set_host_enabled(self, host, enabled):
"""Sets the specified host's ability to accept new instances."""
pass
diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py
index ce57847b2..af547821f 100644
--- a/nova/virt/vmwareapi_conn.py
+++ b/nova/virt/vmwareapi_conn.py
@@ -190,6 +190,10 @@ class VMWareESXConnection(driver.ComputeDriver):
"""This method is supported only by libvirt."""
return
+ def set_host_powerstate(self, host, state):
+ """Reboots or shuts down the host."""
+ pass
+
def set_host_enabled(self, host, enabled):
"""Sets the specified host's ability to accept new instances."""
pass
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 7e02e1def..8e57042f9 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -1023,6 +1023,14 @@ class VMOps(object):
# TODO: implement this!
return 'http://fakeajaxconsole/fake_url'
+ def set_host_powerstate(self, host, state):
+ """Reboots or shuts down the host."""
+ args = {"state": json.dumps(state)}
+ methods = {"reboot": "host_reboot", "shutdown": "host_shutdown"}
+ json_resp = self._call_xenhost(methods[state], args)
+ resp = json.loads(json_resp)
+ return resp["powerstate"]
+
def set_host_enabled(self, host, enabled):
"""Sets the specified host's ability to accept new instances."""
args = {"enabled": json.dumps(enabled)}
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index cc18ed83c..5ac837a17 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -334,6 +334,10 @@ class XenAPIConnection(driver.ComputeDriver):
True, run the update first."""
return self.HostState.get_host_stats(refresh=refresh)
+ def set_host_powerstate(self, host, state):
+ """Reboots or shuts down the host."""
+ return self._vmops.set_host_powerstate(host, state)
+
def set_host_enabled(self, host, enabled):
"""Sets the specified host's ability to accept new instances."""
return self._vmops.set_host_enabled(host, enabled)
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
index 292bbce12..5a5122b4a 100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
@@ -103,6 +103,27 @@ def set_host_enabled(self, arg_dict):
return {"status": status}
+def _powerstate(state):
+ host_uuid = _get_host_uuid()
+ cmd = "xe host-disable uuid=%(host_uuid)s" % locals()
+ _run_command(cmd)
+ cmd = "xe host-%(state)s uuid=%(host_uuid)s" % locals()
+ _run_command(cmd)
+ return {"powerstate": state}
+
+
+@jsonify
+def host_reboot(self, arg_dict):
+ """Reboots the host."""
+ return _powerstate("reboot")
+
+
+@jsonify
+def host_shutdown(self, arg_dict):
+ """Reboots the host."""
+ return _powerstate("shutdown")
+
+
@jsonify
def host_data(self, arg_dict):
"""Runs the commands on the xenstore host to return the current status
@@ -217,4 +238,6 @@ def cleanup(dct):
if __name__ == "__main__":
XenAPIPlugin.dispatch(
{"host_data": host_data,
- "set_host_enabled": set_host_enabled})
+ "set_host_enabled": set_host_enabled,
+ "host_shutdown": host_shutdown,
+ "host_reboot": host_reboot})