Skip to content

Commit b0ec909

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Fix compute service set handling for 2.53+"
2 parents 9042668 + 4bd53dc commit b0ec909

3 files changed

Lines changed: 162 additions & 11 deletions

File tree

openstackclient/compute/v2/service.py

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,33 @@ def get_parser(self, prog_name):
163163
)
164164
return parser
165165

166+
@staticmethod
167+
def _find_service_by_host_and_binary(cs, host, binary):
168+
"""Utility method to find a compute service by host and binary
169+
170+
:param host: the name of the compute service host
171+
:param binary: the compute service binary, e.g. nova-compute
172+
:returns: novaclient.v2.services.Service dict-like object
173+
:raises: CommandError if no or multiple results were found
174+
"""
175+
services = cs.list(host=host, binary=binary)
176+
# Did we find anything?
177+
if not len(services):
178+
msg = _('Compute service for host "%(host)s" and binary '
179+
'"%(binary)s" not found.') % {
180+
'host': host, 'binary': binary}
181+
raise exceptions.CommandError(msg)
182+
# Did we find more than one result? This should not happen but let's
183+
# be safe.
184+
if len(services) > 1:
185+
# TODO(mriedem): If we have an --id option for 2.53+ then we can
186+
# say to use that option to uniquely identify the service.
187+
msg = _('Multiple compute services found for host "%(host)s" and '
188+
'binary "%(binary)s". Unable to proceed.') % {
189+
'host': host, 'binary': binary}
190+
raise exceptions.CommandError(msg)
191+
return services[0]
192+
166193
def take_action(self, parsed_args):
167194
compute_client = self.app.client_manager.compute
168195
cs = compute_client.services
@@ -173,6 +200,20 @@ def take_action(self, parsed_args):
173200
"--disable specified.")
174201
raise exceptions.CommandError(msg)
175202

203+
# Starting with microversion 2.53, there is a single
204+
# PUT /os-services/{service_id} API for updating nova-compute
205+
# services. If 2.53+ is used we need to find the nova-compute
206+
# service using the --host and --service (binary) values.
207+
requires_service_id = (
208+
compute_client.api_version >= api_versions.APIVersion('2.53'))
209+
service_id = None
210+
if requires_service_id:
211+
# TODO(mriedem): Add an --id option so users can pass the service
212+
# id (as a uuid) directly rather than make us look it up using
213+
# host/binary.
214+
service_id = SetService._find_service_by_host_and_binary(
215+
cs, parsed_args.host, parsed_args.service).id
216+
176217
result = 0
177218
enabled = None
178219
try:
@@ -183,14 +224,21 @@ def take_action(self, parsed_args):
183224

184225
if enabled is not None:
185226
if enabled:
186-
cs.enable(parsed_args.host, parsed_args.service)
227+
args = (service_id,) if requires_service_id else (
228+
parsed_args.host, parsed_args.service)
229+
cs.enable(*args)
187230
else:
188231
if parsed_args.disable_reason:
189-
cs.disable_log_reason(parsed_args.host,
190-
parsed_args.service,
191-
parsed_args.disable_reason)
232+
args = (service_id, parsed_args.disable_reason) if \
233+
requires_service_id else (
234+
parsed_args.host,
235+
parsed_args.service,
236+
parsed_args.disable_reason)
237+
cs.disable_log_reason(*args)
192238
else:
193-
cs.disable(parsed_args.host, parsed_args.service)
239+
args = (service_id,) if requires_service_id else (
240+
parsed_args.host, parsed_args.service)
241+
cs.disable(*args)
194242
except Exception:
195243
status = "enabled" if enabled else "disabled"
196244
LOG.error("Failed to set service status to %s", status)
@@ -208,8 +256,9 @@ def take_action(self, parsed_args):
208256
'required')
209257
raise exceptions.CommandError(msg)
210258
try:
211-
cs.force_down(parsed_args.host, parsed_args.service,
212-
force_down=force_down)
259+
args = (service_id, force_down) if requires_service_id else (
260+
parsed_args.host, parsed_args.service, force_down)
261+
cs.force_down(*args)
213262
except Exception:
214263
state = "down" if force_down else "up"
215264
LOG.error("Failed to set service state to %s", state)

openstackclient/tests/unit/compute/v2/test_service.py

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from mock import call
1818
from novaclient import api_versions
1919
from osc_lib import exceptions
20+
import six
2021

2122
from openstackclient.compute.v2 import service
2223
from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
@@ -344,7 +345,7 @@ def test_service_set_state_up(self):
344345
'2.11')
345346
result = self.cmd.take_action(parsed_args)
346347
self.service_mock.force_down.assert_called_once_with(
347-
self.service.host, self.service.binary, force_down=False)
348+
self.service.host, self.service.binary, False)
348349
self.assertNotCalled(self.service_mock.enable)
349350
self.assertNotCalled(self.service_mock.disable)
350351
self.assertIsNone(result)
@@ -365,7 +366,7 @@ def test_service_set_state_down(self):
365366
'2.11')
366367
result = self.cmd.take_action(parsed_args)
367368
self.service_mock.force_down.assert_called_once_with(
368-
self.service.host, self.service.binary, force_down=True)
369+
self.service.host, self.service.binary, True)
369370
self.assertNotCalled(self.service_mock.enable)
370371
self.assertNotCalled(self.service_mock.disable)
371372
self.assertIsNone(result)
@@ -390,7 +391,7 @@ def test_service_set_enable_and_state_down(self):
390391
self.service_mock.enable.assert_called_once_with(
391392
self.service.host, self.service.binary)
392393
self.service_mock.force_down.assert_called_once_with(
393-
self.service.host, self.service.binary, force_down=True)
394+
self.service.host, self.service.binary, True)
394395
self.assertIsNone(result)
395396

396397
def test_service_set_enable_and_state_down_with_exception(self):
@@ -415,4 +416,99 @@ def test_service_set_enable_and_state_down_with_exception(self):
415416
self.assertRaises(exceptions.CommandError,
416417
self.cmd.take_action, parsed_args)
417418
self.service_mock.force_down.assert_called_once_with(
418-
self.service.host, self.service.binary, force_down=True)
419+
self.service.host, self.service.binary, True)
420+
421+
def test_service_set_2_53_disable_down(self):
422+
# Tests disabling and forcing down a compute service with microversion
423+
# 2.53 which requires looking up the service by host and binary.
424+
arglist = [
425+
'--disable',
426+
'--down',
427+
self.service.host,
428+
self.service.binary,
429+
]
430+
verifylist = [
431+
('disable', True),
432+
('down', True),
433+
('host', self.service.host),
434+
('service', self.service.binary),
435+
]
436+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
437+
self.app.client_manager.compute.api_version = api_versions.APIVersion(
438+
'2.53')
439+
service_id = '339478d0-0b95-4a94-be63-d5be05dfeb1c'
440+
self.service_mock.list.return_value = [mock.Mock(id=service_id)]
441+
result = self.cmd.take_action(parsed_args)
442+
self.service_mock.disable.assert_called_once_with(service_id)
443+
self.service_mock.force_down.assert_called_once_with(service_id, True)
444+
self.assertIsNone(result)
445+
446+
def test_service_set_2_53_disable_reason(self):
447+
# Tests disabling with reason a compute service with microversion
448+
# 2.53 which requires looking up the service by host and binary.
449+
reason = 'earthquake'
450+
arglist = [
451+
'--disable',
452+
'--disable-reason', reason,
453+
self.service.host,
454+
self.service.binary,
455+
]
456+
verifylist = [
457+
('disable', True),
458+
('disable_reason', reason),
459+
('host', self.service.host),
460+
('service', self.service.binary),
461+
]
462+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
463+
self.app.client_manager.compute.api_version = api_versions.APIVersion(
464+
'2.53')
465+
service_id = '339478d0-0b95-4a94-be63-d5be05dfeb1c'
466+
self.service_mock.list.return_value = [mock.Mock(id=service_id)]
467+
result = self.cmd.take_action(parsed_args)
468+
self.service_mock.disable_log_reason.assert_called_once_with(
469+
service_id, reason)
470+
self.assertIsNone(result)
471+
472+
def test_service_set_2_53_enable_up(self):
473+
# Tests enabling and bringing up a compute service with microversion
474+
# 2.53 which requires looking up the service by host and binary.
475+
arglist = [
476+
'--enable',
477+
'--up',
478+
self.service.host,
479+
self.service.binary,
480+
]
481+
verifylist = [
482+
('enable', True),
483+
('up', True),
484+
('host', self.service.host),
485+
('service', self.service.binary),
486+
]
487+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
488+
self.app.client_manager.compute.api_version = api_versions.APIVersion(
489+
'2.53')
490+
service_id = '339478d0-0b95-4a94-be63-d5be05dfeb1c'
491+
self.service_mock.list.return_value = [mock.Mock(id=service_id)]
492+
result = self.cmd.take_action(parsed_args)
493+
self.service_mock.enable.assert_called_once_with(service_id)
494+
self.service_mock.force_down.assert_called_once_with(service_id, False)
495+
self.assertIsNone(result)
496+
497+
def test_service_set_find_service_by_host_and_binary_no_results(self):
498+
# Tests that no compute services are found by host and binary.
499+
self.service_mock.list.return_value = []
500+
ex = self.assertRaises(exceptions.CommandError,
501+
self.cmd._find_service_by_host_and_binary,
502+
self.service_mock, 'fake-host', 'nova-compute')
503+
self.assertIn('Compute service for host "fake-host" and binary '
504+
'"nova-compute" not found.', six.text_type(ex))
505+
506+
def test_service_set_find_service_by_host_and_binary_many_results(self):
507+
# Tests that more than one compute service is found by host and binary.
508+
self.service_mock.list.return_value = [mock.Mock(), mock.Mock()]
509+
ex = self.assertRaises(exceptions.CommandError,
510+
self.cmd._find_service_by_host_and_binary,
511+
self.service_mock, 'fake-host', 'nova-compute')
512+
self.assertIn('Multiple compute services found for host "fake-host" '
513+
'and binary "nova-compute". Unable to proceed.',
514+
six.text_type(ex))
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
fixes:
3+
- |
4+
The ``compute service set`` command now properly handles
5+
``--os-compute-api-version`` 2.53 and greater.
6+
[Story `2005349 <https://storyboard.openstack.org/#!/story/2005349>`_]

0 commit comments

Comments
 (0)