Updated with code changes on LP
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
# Copyright (c) 2011 Openstack, LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Decorator for limiting extensions that should be admin-only."""
|
||||
|
||||
from functools import wraps
|
||||
from nova import flags
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
def admin_only(fnc):
|
||||
@wraps(fnc)
|
||||
def _wrapped(self, *args, **kwargs):
|
||||
if FLAGS.allow_admin_api:
|
||||
return fnc(self, *args, **kwargs)
|
||||
return []
|
||||
_wrapped.func_name = fnc.func_name
|
||||
return _wrapped
|
||||
@@ -24,6 +24,7 @@ from nova import log as logging
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import faults
|
||||
from nova.api.openstack.contrib import admin_only
|
||||
from nova.scheduler import api as scheduler_api
|
||||
|
||||
|
||||
@@ -70,7 +71,7 @@ class HostController(object):
|
||||
key = raw_key.lower().strip()
|
||||
val = raw_val.lower().strip()
|
||||
# NOTE: (dabo) Right now only 'status' can be set, but other
|
||||
# actions may follow.
|
||||
# settings may follow.
|
||||
if key == "status":
|
||||
if val[:6] in ("enable", "disabl"):
|
||||
return self._set_enabled_status(req, id,
|
||||
@@ -78,20 +79,6 @@ class HostController(object):
|
||||
else:
|
||||
explanation = _("Invalid status: '%s'") % raw_val
|
||||
raise webob.exc.HTTPBadRequest(explanation=explanation)
|
||||
elif key == "power_state":
|
||||
if val == "startup":
|
||||
# The only valid values for 'state' are 'reboot' or
|
||||
# 'shutdown'. For completeness' sake there is the
|
||||
# 'startup' option to start up a host, but this is not
|
||||
# technically feasible now, as we run the host on the
|
||||
# XenServer box.
|
||||
msg = _("Host startup on XenServer is not supported.")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
elif 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)
|
||||
@@ -108,12 +95,28 @@ class HostController(object):
|
||||
raise webob.exc.HTTPBadRequest(explanation=result)
|
||||
return {"host": host, "status": result}
|
||||
|
||||
def _set_powerstate(self, req, host, state):
|
||||
def _host_power_action(self, req, host, action):
|
||||
"""Reboots or shuts down the host."""
|
||||
context = req.environ['nova.context']
|
||||
result = self.compute_api.set_host_powerstate(context, host=host,
|
||||
state=state)
|
||||
return {"host": host, "power_state": result}
|
||||
result = self.compute_api.host_power_action(context, host=host,
|
||||
action=action)
|
||||
return {"host": host, "power_action": result}
|
||||
|
||||
def startup(self, req, id):
|
||||
"""The only valid values for 'action' are 'reboot' or
|
||||
'shutdown'. For completeness' sake there is the
|
||||
'startup' option to start up a host, but this is not
|
||||
technically feasible now, as we run the host on the
|
||||
XenServer box.
|
||||
"""
|
||||
msg = _("Host startup on XenServer is not supported.")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
def shutdown(self, req, id):
|
||||
return self._host_power_action(req, host=id, action="shutdown")
|
||||
|
||||
def reboot(self, req, id):
|
||||
return self._host_power_action(req, host=id, action="reboot")
|
||||
|
||||
|
||||
class Hosts(extensions.ExtensionDescriptor):
|
||||
@@ -132,7 +135,10 @@ class Hosts(extensions.ExtensionDescriptor):
|
||||
def get_updated(self):
|
||||
return "2011-06-29T00:00:00+00:00"
|
||||
|
||||
@admin_only.admin_only
|
||||
def get_resources(self):
|
||||
resources = [extensions.ResourceExtension('os-hosts', HostController(),
|
||||
collection_actions={'update': 'PUT'}, member_actions={})]
|
||||
resources = [extensions.ResourceExtension('os-hosts',
|
||||
HostController(), collection_actions={'update': 'PUT'},
|
||||
member_actions={"startup": "GET", "shutdown": "GET",
|
||||
"reboot": "GET"})]
|
||||
return resources
|
||||
|
||||
+4
-4
@@ -999,10 +999,10 @@ 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})
|
||||
def host_power_action(self, context, host, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
return self._call_compute_message("host_power_action", context,
|
||||
instance_id=None, host=host, params={"action": action})
|
||||
|
||||
@scheduler_api.reroute_compute("diagnostics")
|
||||
def get_diagnostics(self, context, instance_id):
|
||||
|
||||
@@ -958,10 +958,10 @@ 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)
|
||||
def host_power_action(self, context, instance_id=None, host=None,
|
||||
action=None):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
return self.driver.host_power_action(host, action)
|
||||
|
||||
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
|
||||
def set_host_enabled(self, context, instance_id=None, host=None,
|
||||
|
||||
+15
-16
@@ -48,8 +48,8 @@ def stub_set_host_enabled(context, host, enabled):
|
||||
return status
|
||||
|
||||
|
||||
def stub_set_host_powerstate(context, host, state):
|
||||
return state
|
||||
def stub_host_power_action(context, host, action):
|
||||
return action
|
||||
|
||||
|
||||
class FakeRequest(object):
|
||||
@@ -66,8 +66,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)
|
||||
self.stubs.Set(self.controller.compute_api, 'host_power_action',
|
||||
stub_host_power_action)
|
||||
|
||||
def test_list_hosts(self):
|
||||
"""Verify that the compute hosts are returned."""
|
||||
@@ -93,19 +93,18 @@ class HostTestCase(test.TestCase):
|
||||
result_c2 = self.controller.update(self.req, "host_c2", body=en_body)
|
||||
self.assertEqual(result_c2["status"], "disabled")
|
||||
|
||||
def test_host_power_state(self):
|
||||
en_body = {"power_state": "reboot"}
|
||||
result_c1 = self.controller.update(self.req, "host_c1", body=en_body)
|
||||
self.assertEqual(result_c1["power_state"], "reboot")
|
||||
# Test invalid power_state
|
||||
en_body = {"power_state": "invalid"}
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
|
||||
self.req, "host_c1", body=en_body)
|
||||
def test_host_startup(self):
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.startup,
|
||||
self.req, "host_c1")
|
||||
|
||||
def test_bad_power_state_value(self):
|
||||
bad_body = {"power_state": "bad"}
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
|
||||
self.req, "host_c1", body=bad_body)
|
||||
def test_host_shutdown(self):
|
||||
result = self.controller.shutdown(self.req, "host_c1")
|
||||
print "RES", result
|
||||
self.assertEqual(result["power_action"], "shutdown")
|
||||
|
||||
def test_host_reboot(self):
|
||||
result = self.controller.reboot(self.req, "host_c1")
|
||||
self.assertEqual(result["power_action"], "reboot")
|
||||
|
||||
def test_bad_status_value(self):
|
||||
bad_body = {"status": "bad"}
|
||||
|
||||
+2
-6
@@ -282,8 +282,8 @@ class ComputeDriver(object):
|
||||
# TODO(Vek): Need to pass context in for access to auth_token
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_host_powerstate(self, host, state):
|
||||
"""Reboots or shuts down the host."""
|
||||
def host_power_action(self, host, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_host_enabled(self, host, enabled):
|
||||
@@ -291,10 +291,6 @@ class ComputeDriver(object):
|
||||
# TODO(Vek): Need to pass context in for access to auth_token
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_power_state(self, host, power_state):
|
||||
"""Reboots, shuts down or starts up the host."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def plug_vifs(self, instance, network_info):
|
||||
"""Plugs in VIFs to networks."""
|
||||
# TODO(Vek): Need to pass context in for access to auth_token
|
||||
|
||||
+2
-2
@@ -512,8 +512,8 @@ 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."""
|
||||
def host_power_action(self, host, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
pass
|
||||
|
||||
def set_host_enabled(self, host, enabled):
|
||||
|
||||
+2
-2
@@ -499,8 +499,8 @@ class HyperVConnection(driver.ComputeDriver):
|
||||
"""See xenapi_conn.py implementation."""
|
||||
pass
|
||||
|
||||
def set_host_powerstate(self, host, state):
|
||||
"""Reboots or shuts down the host."""
|
||||
def host_power_action(self, host, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
pass
|
||||
|
||||
def set_host_enabled(self, host, enabled):
|
||||
|
||||
@@ -1562,8 +1562,8 @@ class LibvirtConnection(driver.ComputeDriver):
|
||||
"""See xenapi_conn.py implementation."""
|
||||
pass
|
||||
|
||||
def set_host_powerstate(self, host, state):
|
||||
"""Reboots or shuts down the host."""
|
||||
def host_power_action(self, host, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
pass
|
||||
|
||||
def set_host_enabled(self, host, enabled):
|
||||
|
||||
@@ -191,8 +191,8 @@ 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."""
|
||||
def host_power_action(self, host, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
pass
|
||||
|
||||
def set_host_enabled(self, host, enabled):
|
||||
|
||||
@@ -1031,13 +1031,13 @@ 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)}
|
||||
def host_power_action(self, host, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
args = {"action": json.dumps(action)}
|
||||
methods = {"reboot": "host_reboot", "shutdown": "host_shutdown"}
|
||||
json_resp = self._call_xenhost(methods[state], args)
|
||||
json_resp = self._call_xenhost(methods[action], args)
|
||||
resp = json.loads(json_resp)
|
||||
return resp["powerstate"]
|
||||
return resp["power_action"]
|
||||
|
||||
def set_host_enabled(self, host, enabled):
|
||||
"""Sets the specified host's ability to accept new instances."""
|
||||
|
||||
@@ -332,9 +332,9 @@ 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 host_power_action(self, host, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
return self._vmops.host_power_action(host, action)
|
||||
|
||||
def set_host_enabled(self, host, enabled):
|
||||
"""Sets the specified host's ability to accept new instances."""
|
||||
|
||||
@@ -103,7 +103,7 @@ def set_host_enabled(self, arg_dict):
|
||||
return {"status": status}
|
||||
|
||||
|
||||
def _powerstate(state):
|
||||
def _power_action(action):
|
||||
host_uuid = _get_host_uuid()
|
||||
# Host must be disabled first
|
||||
result = _run_command("xe host-disable")
|
||||
@@ -115,23 +115,23 @@ def _powerstate(state):
|
||||
raise pluginlib.PluginError(result)
|
||||
cmds = {"reboot": "xe host-reboot", "startup": "xe host-power-on",
|
||||
"shutdown": "xe host-shutdown"}
|
||||
result = _run_command(cmds[state])
|
||||
result = _run_command(cmds[action])
|
||||
# Should be empty string
|
||||
if result:
|
||||
raise pluginlib.PluginError(result)
|
||||
return {"powerstate": state}
|
||||
return {"power_action": action}
|
||||
|
||||
|
||||
@jsonify
|
||||
def host_reboot(self, arg_dict):
|
||||
"""Reboots the host."""
|
||||
return _powerstate("reboot")
|
||||
return _power_action("reboot")
|
||||
|
||||
|
||||
@jsonify
|
||||
def host_shutdown(self, arg_dict):
|
||||
"""Reboots the host."""
|
||||
return _powerstate("shutdown")
|
||||
return _power_action("shutdown")
|
||||
|
||||
|
||||
@jsonify
|
||||
@@ -139,34 +139,7 @@ def host_start(self, arg_dict):
|
||||
"""Starts the host. NOTE: Currently not feasible, since the host
|
||||
runs on the same machine as Xen.
|
||||
"""
|
||||
return _powerstate("startup")
|
||||
|
||||
|
||||
@jsonify
|
||||
def set_power_state(self, arg_dict):
|
||||
"""Reboots or powers off this host. Ideally, we would also like to be
|
||||
able to power *on* a host, but right now this is not technically
|
||||
feasible.
|
||||
"""
|
||||
power_state = arg_dict.get("power_state")
|
||||
if power_state is None:
|
||||
raise pluginlib.PluginError(
|
||||
_("Missing 'power_state' argument to set_power_state"))
|
||||
# Host must be disabled first
|
||||
# result = _run_command("xe host-disable")
|
||||
# if result:
|
||||
# raise pluginlib.PluginError(result)
|
||||
# # All running VMs must be shutdown
|
||||
# result = _run_command("xe vm-shutdown --multiple power-state=running")
|
||||
# if result:
|
||||
# raise pluginlib.PluginError(result)
|
||||
# cmds = {"reboot": "xe host-reboot", "on": "xe host-power-on",
|
||||
# "off": "xe host-shutdown"}
|
||||
# result = _run_command(cmds[power_state])
|
||||
# # Should be empty string
|
||||
# if result:
|
||||
# raise pluginlib.PluginError(result)
|
||||
return {"power_state": power_state}
|
||||
return _power_action("startup")
|
||||
|
||||
|
||||
@jsonify
|
||||
|
||||
Reference in New Issue
Block a user