Merge "Fix compute service set handling for 2.53+"

This commit is contained in:
Zuul 2019-08-20 17:53:33 +00:00 committed by Gerrit Code Review
commit b0ec909160
3 changed files with 162 additions and 11 deletions

View File

@ -163,6 +163,33 @@ class SetService(command.Command):
)
return parser
@staticmethod
def _find_service_by_host_and_binary(cs, host, binary):
"""Utility method to find a compute service by host and binary
:param host: the name of the compute service host
:param binary: the compute service binary, e.g. nova-compute
:returns: novaclient.v2.services.Service dict-like object
:raises: CommandError if no or multiple results were found
"""
services = cs.list(host=host, binary=binary)
# Did we find anything?
if not len(services):
msg = _('Compute service for host "%(host)s" and binary '
'"%(binary)s" not found.') % {
'host': host, 'binary': binary}
raise exceptions.CommandError(msg)
# Did we find more than one result? This should not happen but let's
# be safe.
if len(services) > 1:
# TODO(mriedem): If we have an --id option for 2.53+ then we can
# say to use that option to uniquely identify the service.
msg = _('Multiple compute services found for host "%(host)s" and '
'binary "%(binary)s". Unable to proceed.') % {
'host': host, 'binary': binary}
raise exceptions.CommandError(msg)
return services[0]
def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute
cs = compute_client.services
@ -173,6 +200,20 @@ class SetService(command.Command):
"--disable specified.")
raise exceptions.CommandError(msg)
# Starting with microversion 2.53, there is a single
# PUT /os-services/{service_id} API for updating nova-compute
# services. If 2.53+ is used we need to find the nova-compute
# service using the --host and --service (binary) values.
requires_service_id = (
compute_client.api_version >= api_versions.APIVersion('2.53'))
service_id = None
if requires_service_id:
# TODO(mriedem): Add an --id option so users can pass the service
# id (as a uuid) directly rather than make us look it up using
# host/binary.
service_id = SetService._find_service_by_host_and_binary(
cs, parsed_args.host, parsed_args.service).id
result = 0
enabled = None
try:
@ -183,14 +224,21 @@ class SetService(command.Command):
if enabled is not None:
if enabled:
cs.enable(parsed_args.host, parsed_args.service)
args = (service_id,) if requires_service_id else (
parsed_args.host, parsed_args.service)
cs.enable(*args)
else:
if parsed_args.disable_reason:
cs.disable_log_reason(parsed_args.host,
parsed_args.service,
parsed_args.disable_reason)
args = (service_id, parsed_args.disable_reason) if \
requires_service_id else (
parsed_args.host,
parsed_args.service,
parsed_args.disable_reason)
cs.disable_log_reason(*args)
else:
cs.disable(parsed_args.host, parsed_args.service)
args = (service_id,) if requires_service_id else (
parsed_args.host, parsed_args.service)
cs.disable(*args)
except Exception:
status = "enabled" if enabled else "disabled"
LOG.error("Failed to set service status to %s", status)
@ -208,8 +256,9 @@ class SetService(command.Command):
'required')
raise exceptions.CommandError(msg)
try:
cs.force_down(parsed_args.host, parsed_args.service,
force_down=force_down)
args = (service_id, force_down) if requires_service_id else (
parsed_args.host, parsed_args.service, force_down)
cs.force_down(*args)
except Exception:
state = "down" if force_down else "up"
LOG.error("Failed to set service state to %s", state)

View File

@ -17,6 +17,7 @@ import mock
from mock import call
from novaclient import api_versions
from osc_lib import exceptions
import six
from openstackclient.compute.v2 import service
from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
@ -344,7 +345,7 @@ class TestServiceSet(TestService):
'2.11')
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.service.host, self.service.binary, False)
self.assertNotCalled(self.service_mock.enable)
self.assertNotCalled(self.service_mock.disable)
self.assertIsNone(result)
@ -365,7 +366,7 @@ class TestServiceSet(TestService):
'2.11')
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.service.host, self.service.binary, True)
self.assertNotCalled(self.service_mock.enable)
self.assertNotCalled(self.service_mock.disable)
self.assertIsNone(result)
@ -390,7 +391,7 @@ class TestServiceSet(TestService):
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.service.host, self.service.binary, True)
self.assertIsNone(result)
def test_service_set_enable_and_state_down_with_exception(self):
@ -415,4 +416,99 @@ class TestServiceSet(TestService):
self.assertRaises(exceptions.CommandError,
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.service.host, self.service.binary, True)
def test_service_set_2_53_disable_down(self):
# Tests disabling and forcing down a compute service with microversion
# 2.53 which requires looking up the service by host and binary.
arglist = [
'--disable',
'--down',
self.service.host,
self.service.binary,
]
verifylist = [
('disable', True),
('down', True),
('host', self.service.host),
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.53')
service_id = '339478d0-0b95-4a94-be63-d5be05dfeb1c'
self.service_mock.list.return_value = [mock.Mock(id=service_id)]
result = self.cmd.take_action(parsed_args)
self.service_mock.disable.assert_called_once_with(service_id)
self.service_mock.force_down.assert_called_once_with(service_id, True)
self.assertIsNone(result)
def test_service_set_2_53_disable_reason(self):
# Tests disabling with reason a compute service with microversion
# 2.53 which requires looking up the service by host and binary.
reason = 'earthquake'
arglist = [
'--disable',
'--disable-reason', reason,
self.service.host,
self.service.binary,
]
verifylist = [
('disable', True),
('disable_reason', reason),
('host', self.service.host),
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.53')
service_id = '339478d0-0b95-4a94-be63-d5be05dfeb1c'
self.service_mock.list.return_value = [mock.Mock(id=service_id)]
result = self.cmd.take_action(parsed_args)
self.service_mock.disable_log_reason.assert_called_once_with(
service_id, reason)
self.assertIsNone(result)
def test_service_set_2_53_enable_up(self):
# Tests enabling and bringing up a compute service with microversion
# 2.53 which requires looking up the service by host and binary.
arglist = [
'--enable',
'--up',
self.service.host,
self.service.binary,
]
verifylist = [
('enable', True),
('up', True),
('host', self.service.host),
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.53')
service_id = '339478d0-0b95-4a94-be63-d5be05dfeb1c'
self.service_mock.list.return_value = [mock.Mock(id=service_id)]
result = self.cmd.take_action(parsed_args)
self.service_mock.enable.assert_called_once_with(service_id)
self.service_mock.force_down.assert_called_once_with(service_id, False)
self.assertIsNone(result)
def test_service_set_find_service_by_host_and_binary_no_results(self):
# Tests that no compute services are found by host and binary.
self.service_mock.list.return_value = []
ex = self.assertRaises(exceptions.CommandError,
self.cmd._find_service_by_host_and_binary,
self.service_mock, 'fake-host', 'nova-compute')
self.assertIn('Compute service for host "fake-host" and binary '
'"nova-compute" not found.', six.text_type(ex))
def test_service_set_find_service_by_host_and_binary_many_results(self):
# Tests that more than one compute service is found by host and binary.
self.service_mock.list.return_value = [mock.Mock(), mock.Mock()]
ex = self.assertRaises(exceptions.CommandError,
self.cmd._find_service_by_host_and_binary,
self.service_mock, 'fake-host', 'nova-compute')
self.assertIn('Multiple compute services found for host "fake-host" '
'and binary "nova-compute". Unable to proceed.',
six.text_type(ex))

View File

@ -0,0 +1,6 @@
---
fixes:
- |
The ``compute service set`` command now properly handles
``--os-compute-api-version`` 2.53 and greater.
[Story `2005349 <https://storyboard.openstack.org/#!/story/2005349>`_]