Merge "Support compute service force down/up"
This commit is contained in:
commit
4cc539fcc5
doc/source/command-objects
openstackclient
releasenotes/notes
@ -58,6 +58,7 @@ Set service command
|
|||||||
os compute service set
|
os compute service set
|
||||||
[--enable | --disable]
|
[--enable | --disable]
|
||||||
[--disable-reason <reason>]
|
[--disable-reason <reason>]
|
||||||
|
[--up | --down]
|
||||||
<host> <service>
|
<host> <service>
|
||||||
|
|
||||||
.. _compute-service-set:
|
.. _compute-service-set:
|
||||||
@ -73,6 +74,14 @@ Set service command
|
|||||||
|
|
||||||
Reason for disabling the service (in quotes). Should be used with --disable option.
|
Reason for disabling the service (in quotes). Should be used with --disable option.
|
||||||
|
|
||||||
|
.. option:: --up
|
||||||
|
|
||||||
|
Force up service
|
||||||
|
|
||||||
|
.. option:: --down
|
||||||
|
|
||||||
|
Force down service
|
||||||
|
|
||||||
.. describe:: <host>
|
.. describe:: <host>
|
||||||
|
|
||||||
Name of host
|
Name of host
|
||||||
|
@ -20,6 +20,7 @@ from osc_lib import exceptions
|
|||||||
from osc_lib import utils
|
from osc_lib import utils
|
||||||
|
|
||||||
from openstackclient.i18n import _
|
from openstackclient.i18n import _
|
||||||
|
from openstackclient.i18n import _LE
|
||||||
|
|
||||||
|
|
||||||
class DeleteService(command.Command):
|
class DeleteService(command.Command):
|
||||||
@ -127,6 +128,17 @@ class SetService(command.Command):
|
|||||||
help=_("Reason for disabling the service (in quotas). "
|
help=_("Reason for disabling the service (in quotas). "
|
||||||
"Should be used with --disable option.")
|
"Should be used with --disable option.")
|
||||||
)
|
)
|
||||||
|
up_down_group = parser.add_mutually_exclusive_group()
|
||||||
|
up_down_group.add_argument(
|
||||||
|
'--up',
|
||||||
|
action='store_true',
|
||||||
|
help=_('Force up service'),
|
||||||
|
)
|
||||||
|
up_down_group.add_argument(
|
||||||
|
'--down',
|
||||||
|
action='store_true',
|
||||||
|
help=_('Force down service'),
|
||||||
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
@ -139,20 +151,45 @@ class SetService(command.Command):
|
|||||||
"--disable specified.")
|
"--disable specified.")
|
||||||
raise exceptions.CommandError(msg)
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
|
result = 0
|
||||||
enabled = None
|
enabled = None
|
||||||
if parsed_args.enable:
|
try:
|
||||||
enabled = True
|
if parsed_args.enable:
|
||||||
if parsed_args.disable:
|
enabled = True
|
||||||
enabled = False
|
if parsed_args.disable:
|
||||||
|
enabled = False
|
||||||
|
|
||||||
if enabled is None:
|
if enabled is not None:
|
||||||
return
|
if enabled:
|
||||||
elif enabled:
|
cs.enable(parsed_args.host, parsed_args.service)
|
||||||
cs.enable(parsed_args.host, parsed_args.service)
|
else:
|
||||||
else:
|
if parsed_args.disable_reason:
|
||||||
if parsed_args.disable_reason:
|
cs.disable_log_reason(parsed_args.host,
|
||||||
cs.disable_log_reason(parsed_args.host,
|
parsed_args.service,
|
||||||
parsed_args.service,
|
parsed_args.disable_reason)
|
||||||
parsed_args.disable_reason)
|
else:
|
||||||
else:
|
cs.disable(parsed_args.host, parsed_args.service)
|
||||||
cs.disable(parsed_args.host, parsed_args.service)
|
except Exception:
|
||||||
|
status = "enabled" if enabled else "disabled"
|
||||||
|
self.log.error(_LE("Failed to set service status to %s"), status)
|
||||||
|
result += 1
|
||||||
|
|
||||||
|
force_down = None
|
||||||
|
try:
|
||||||
|
if parsed_args.down:
|
||||||
|
force_down = True
|
||||||
|
if parsed_args.up:
|
||||||
|
force_down = False
|
||||||
|
if force_down is not None:
|
||||||
|
cs.force_down(parsed_args.host, parsed_args.service,
|
||||||
|
force_down=force_down)
|
||||||
|
except Exception:
|
||||||
|
state = "down" if force_down else "up"
|
||||||
|
self.log.error(_LE("Failed to set service state to %s"), state)
|
||||||
|
result += 1
|
||||||
|
|
||||||
|
if result > 0:
|
||||||
|
msg = _("Compute service %(service)s of host %(host)s failed to "
|
||||||
|
"set.") % {"service": parsed_args.service,
|
||||||
|
"host": parsed_args.host}
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
from osc_lib import exceptions
|
from osc_lib import exceptions
|
||||||
|
|
||||||
from openstackclient.compute.v2 import service
|
from openstackclient.compute.v2 import service
|
||||||
@ -225,8 +227,12 @@ class TestServiceSet(TestService):
|
|||||||
('service', self.service.binary),
|
('service', self.service.binary),
|
||||||
]
|
]
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
try:
|
||||||
parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
|
self.fail("CommandError should be raised.")
|
||||||
|
except exceptions.CommandError as e:
|
||||||
|
self.assertEqual("Cannot specify option --disable-reason without "
|
||||||
|
"--disable specified.", str(e))
|
||||||
|
|
||||||
def test_service_set_enable_with_disable_reason(self):
|
def test_service_set_enable_with_disable_reason(self):
|
||||||
reason = 'earthquake'
|
reason = 'earthquake'
|
||||||
@ -243,5 +249,93 @@ class TestServiceSet(TestService):
|
|||||||
('service', self.service.binary),
|
('service', self.service.binary),
|
||||||
]
|
]
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
try:
|
||||||
parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
|
self.fail("CommandError should be raised.")
|
||||||
|
except exceptions.CommandError as e:
|
||||||
|
self.assertEqual("Cannot specify option --disable-reason without "
|
||||||
|
"--disable specified.", str(e))
|
||||||
|
|
||||||
|
def test_service_set_state_up(self):
|
||||||
|
arglist = [
|
||||||
|
'--up',
|
||||||
|
self.service.host,
|
||||||
|
self.service.binary,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('up', True),
|
||||||
|
('host', self.service.host),
|
||||||
|
('service', self.service.binary),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
result = self.cmd.take_action(parsed_args)
|
||||||
|
self.service_mock.force_down.assert_called_once_with(
|
||||||
|
self.service.host, self.service.binary, force_down=False)
|
||||||
|
self.assertNotCalled(self.service_mock.enable)
|
||||||
|
self.assertNotCalled(self.service_mock.disable)
|
||||||
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
def test_service_set_state_down(self):
|
||||||
|
arglist = [
|
||||||
|
'--down',
|
||||||
|
self.service.host,
|
||||||
|
self.service.binary,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('down', True),
|
||||||
|
('host', self.service.host),
|
||||||
|
('service', self.service.binary),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
result = self.cmd.take_action(parsed_args)
|
||||||
|
self.service_mock.force_down.assert_called_once_with(
|
||||||
|
self.service.host, self.service.binary, force_down=True)
|
||||||
|
self.assertNotCalled(self.service_mock.enable)
|
||||||
|
self.assertNotCalled(self.service_mock.disable)
|
||||||
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
def test_service_set_enable_and_state_down(self):
|
||||||
|
arglist = [
|
||||||
|
'--enable',
|
||||||
|
'--down',
|
||||||
|
self.service.host,
|
||||||
|
self.service.binary,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('enable', True),
|
||||||
|
('down', True),
|
||||||
|
('host', self.service.host),
|
||||||
|
('service', self.service.binary),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
result = self.cmd.take_action(parsed_args)
|
||||||
|
self.service_mock.enable.assert_called_once_with(
|
||||||
|
self.service.host, self.service.binary)
|
||||||
|
self.service_mock.force_down.assert_called_once_with(
|
||||||
|
self.service.host, self.service.binary, force_down=True)
|
||||||
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
def test_service_set_enable_and_state_down_with_exception(self):
|
||||||
|
arglist = [
|
||||||
|
'--enable',
|
||||||
|
'--down',
|
||||||
|
self.service.host,
|
||||||
|
self.service.binary,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('enable', True),
|
||||||
|
('down', True),
|
||||||
|
('host', self.service.host),
|
||||||
|
('service', self.service.binary),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
with mock.patch.object(self.cmd.log, 'error') as mock_log:
|
||||||
|
with mock.patch.object(self.service_mock, 'enable',
|
||||||
|
side_effect=Exception()):
|
||||||
|
self.assertRaises(exceptions.CommandError,
|
||||||
|
self.cmd.take_action, parsed_args)
|
||||||
|
mock_log.assert_called_once_with(
|
||||||
|
"Failed to set service status to %s", "enabled")
|
||||||
|
self.service_mock.force_down.assert_called_once_with(
|
||||||
|
self.service.host, self.service.binary, force_down=True)
|
||||||
|
5
releasenotes/notes/bug-1589348-4a612a4efc7ed0e5.yaml
Normal file
5
releasenotes/notes/bug-1589348-4a612a4efc7ed0e5.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add options ``--up`` and ``--down`` for compute v2 ``compute service set``
|
||||||
|
command to support force up/down compute service.
|
||||||
|
[Bug `1589348 <https://bugs.launchpad.net/python-openstackclient/+bug/1589348>`_]
|
Loading…
x
Reference in New Issue
Block a user