From 39739158b0cf10a775fd3899e35df7f53b4c9336 Mon Sep 17 00:00:00 2001 From: Carlos Goncalves Date: Wed, 27 May 2015 08:32:31 +0200 Subject: [PATCH] Support forcing service down Extending Nova CLI to support forcing service to be set/unset as down, as specified in blueprint mark-host-down. Depends-On: I612582ba7b70bb6d167aa68bdfc47faa3b7b85ed Depends-On: I39f1a84c100726f87a4dc464dd9922d66efdb53f Implements: blueprint support-force-down-service Change-Id: I2b80ac32a95fe80363b4ad95d8d89fff097935a3 --- novaclient/__init__.py | 2 +- novaclient/tests/unit/v2/fakes.py | 6 ++++++ novaclient/tests/unit/v2/test_services.py | 26 +++++++++++++++++++++++ novaclient/v2/services.py | 19 +++++++++++++++++ novaclient/v2/shell.py | 15 +++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/novaclient/__init__.py b/novaclient/__init__.py index a52cedc8a..5e6ccb0bb 100644 --- a/novaclient/__init__.py +++ b/novaclient/__init__.py @@ -20,4 +20,4 @@ from novaclient import api_versions __version__ = pbr.version.VersionInfo('python-novaclient').version_string() API_MIN_VERSION = api_versions.APIVersion("2.1") -API_MAX_VERSION = api_versions.APIVersion("2.2") +API_MAX_VERSION = api_versions.APIVersion("2.11") diff --git a/novaclient/tests/unit/v2/fakes.py b/novaclient/tests/unit/v2/fakes.py index 4a2cf8886..6814461d1 100644 --- a/novaclient/tests/unit/v2/fakes.py +++ b/novaclient/tests/unit/v2/fakes.py @@ -1677,6 +1677,12 @@ class FakeHTTPClient(base_client.HTTPClient): def delete_os_services_1(self, **kw): return (204, {}, None) + def put_os_services_force_down(self, body, **kw): + return (200, {}, {'service': { + 'host': body['host'], + 'binary': body['binary'], + 'forced_down': False}}) + # # Fixed IPs # diff --git a/novaclient/tests/unit/v2/test_services.py b/novaclient/tests/unit/v2/test_services.py index 2724342d4..f7ab553a0 100644 --- a/novaclient/tests/unit/v2/test_services.py +++ b/novaclient/tests/unit/v2/test_services.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +from novaclient import api_versions from novaclient.tests.unit import utils from novaclient.tests.unit.v2 import fakes from novaclient.v2 import services @@ -97,3 +98,28 @@ class ServicesTest(utils.TestCase): self.cs.assert_called('PUT', '/os-services/disable-log-reason', values) self.assertIsInstance(service, self._get_service_type()) self.assertEqual('disabled', service.status) + + +class ServicesV211TestCase(ServicesTest): + def setUp(self): + super(ServicesV211TestCase, self).setUp() + self.cs.api_version = api_versions.APIVersion("2.11") + + def _update_body(self, host, binary, disabled_reason=None, + force_down=None): + body = {"host": host, + "binary": binary} + if disabled_reason is not None: + body["disabled_reason"] = disabled_reason + if force_down is not None: + body["forced_down"] = force_down + return body + + def test_services_force_down(self): + service = self.cs.services.force_down( + 'compute1', 'nova-compute', False) + values = self._update_body("compute1", "nova-compute", + force_down=False) + self.cs.assert_called('PUT', '/os-services/force-down', values) + self.assertIsInstance(service, self._get_service_type()) + self.assertEqual(False, service.forced_down) diff --git a/novaclient/v2/services.py b/novaclient/v2/services.py index d51fa3ebf..fcf800938 100644 --- a/novaclient/v2/services.py +++ b/novaclient/v2/services.py @@ -16,6 +16,7 @@ """ service interface """ +from novaclient import api_versions from novaclient import base @@ -48,6 +49,7 @@ class ServiceManager(base.ManagerWithFind): url = "%s?%s" % (url, "&".join(filters)) return self._list(url, "services") + @api_versions.wraps("2.0", "2.10") def _update_body(self, host, binary, disabled_reason=None): body = {"host": host, "binary": binary} @@ -55,6 +57,17 @@ class ServiceManager(base.ManagerWithFind): body["disabled_reason"] = disabled_reason return body + @api_versions.wraps("2.11") + def _update_body(self, host, binary, disabled_reason=None, + force_down=None): + body = {"host": host, + "binary": binary} + if disabled_reason is not None: + body["disabled_reason"] = disabled_reason + if force_down is not None: + body["forced_down"] = force_down + return body + def enable(self, host, binary): """Enable the service specified by hostname and binary.""" body = self._update_body(host, binary) @@ -73,3 +86,9 @@ class ServiceManager(base.ManagerWithFind): def delete(self, service_id): """Delete a service.""" return self._delete("/os-services/%s" % service_id) + + @api_versions.wraps("2.11") + def force_down(self, host, binary, force_down=None): + """Force service state to down specified by hostname and binary.""" + body = self._update_body(host, binary, force_down=force_down) + return self._update("/os-services/force-down", body, "service") diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py index 5ad0014d1..9e840a70d 100644 --- a/novaclient/v2/shell.py +++ b/novaclient/v2/shell.py @@ -3568,6 +3568,21 @@ def do_service_disable(cs, args): utils.print_list([result], ['Host', 'Binary', 'Status']) +@api_versions.wraps("2.11") +@cliutils.arg('host', metavar='', help=_('Name of host.')) +@cliutils.arg('binary', metavar='', help=_('Service binary.')) +@cliutils.arg( + '--unset', + dest='force_down', + help=_("Unset the force state down of service"), + action='store_false', + default=True) +def do_service_force_down(cs, args): + """Force service to down.""" + result = cs.services.force_down(args.host, args.binary, args.force_down) + utils.print_list([result], ['Host', 'Binary', 'Forced down']) + + @cliutils.arg('id', metavar='', help=_('Id of service.')) def do_service_delete(cs, args): """Delete the service."""