Skip to content

Commit 417a7ad

Browse files
pshchelocvieri
andcommitted
Allow server rebuild --wait for SHUTOFF servers
currently the command is waiting only for ACTIVE server status, but if the server was SHUTOFF before, it will be SHUTOFF after rebuild as well, so the command is stuck in waiting forever. Additionally, we now also pre-validate the server status on client side, and raise an error if the server to be rebuilt is not in ACTIVE, ERROR or SHUTOFF state. Change-Id: If90a4bbba9a7ecd972f8b594c52fee4f75a0ae5e Co-Authored-By: Oleksiy Molchanov <omolchanov@mirantis.com> Story: 2010751 Task: 48005
1 parent 3c9afe6 commit 417a7ad

3 files changed

Lines changed: 105 additions & 0 deletions

File tree

openstackclient/compute/v2/server.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3536,6 +3536,15 @@ def _show_progress(progress):
35363536
'future release.'
35373537
)
35383538

3539+
status = getattr(server, 'status', '').lower()
3540+
if status == 'shutoff':
3541+
success_status = ['shutoff']
3542+
elif status in ('error', 'active'):
3543+
success_status = ['active']
3544+
else:
3545+
msg = _("The server status is not ACTIVE, SHUTOFF or ERROR.")
3546+
raise exceptions.CommandError(msg)
3547+
35393548
try:
35403549
server = server.rebuild(image, parsed_args.password, **kwargs)
35413550
finally:
@@ -3547,6 +3556,7 @@ def _show_progress(progress):
35473556
compute_client.servers.get,
35483557
server.id,
35493558
callback=_show_progress,
3559+
success_status=success_status,
35503560
):
35513561
self.app.stdout.write(_('Complete\n'))
35523562
else:

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

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6250,6 +6250,7 @@ def setUp(self):
62506250

62516251
# Fake the server to be rebuilt. The IDs of them should be the same.
62526252
attrs['id'] = new_server.id
6253+
attrs['status'] = 'ACTIVE'
62536254
methods = {
62546255
'rebuild': new_server,
62556256
}
@@ -6448,6 +6449,7 @@ def test_rebuild_with_wait_ok(self, mock_wait_for_status):
64486449
self.servers_mock.get,
64496450
self.server.id,
64506451
callback=mock.ANY,
6452+
success_status=['active'],
64516453
# **kwargs
64526454
)
64536455

@@ -6473,12 +6475,91 @@ def test_rebuild_with_wait_fails(self, mock_wait_for_status):
64736475
self.servers_mock.get,
64746476
self.server.id,
64756477
callback=mock.ANY,
6478+
success_status=['active'],
64766479
)
64776480

64786481
self.servers_mock.get.assert_called_with(self.server.id)
64796482
self.get_image_mock.assert_called_with(self.image.id)
64806483
self.server.rebuild.assert_called_with(self.image, None)
64816484

6485+
@mock.patch.object(common_utils, 'wait_for_status', return_value=True)
6486+
def test_rebuild_with_wait_shutoff_status(self, mock_wait_for_status):
6487+
self.server.status = 'SHUTOFF'
6488+
arglist = [
6489+
'--wait',
6490+
self.server.id,
6491+
]
6492+
verifylist = [
6493+
('wait', True),
6494+
('server', self.server.id),
6495+
]
6496+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
6497+
6498+
# Get the command object to test.
6499+
self.cmd.take_action(parsed_args)
6500+
6501+
# kwargs = dict(success_status=['active', 'verify_resize'],)
6502+
6503+
mock_wait_for_status.assert_called_once_with(
6504+
self.servers_mock.get,
6505+
self.server.id,
6506+
callback=mock.ANY,
6507+
success_status=['shutoff'],
6508+
# **kwargs
6509+
)
6510+
6511+
self.servers_mock.get.assert_called_with(self.server.id)
6512+
self.get_image_mock.assert_called_with(self.image.id)
6513+
self.server.rebuild.assert_called_with(self.image, None)
6514+
6515+
@mock.patch.object(common_utils, 'wait_for_status', return_value=True)
6516+
def test_rebuild_with_wait_error_status(self, mock_wait_for_status):
6517+
self.server.status = 'ERROR'
6518+
arglist = [
6519+
'--wait',
6520+
self.server.id,
6521+
]
6522+
verifylist = [
6523+
('wait', True),
6524+
('server', self.server.id),
6525+
]
6526+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
6527+
6528+
# Get the command object to test.
6529+
self.cmd.take_action(parsed_args)
6530+
6531+
# kwargs = dict(success_status=['active', 'verify_resize'],)
6532+
6533+
mock_wait_for_status.assert_called_once_with(
6534+
self.servers_mock.get,
6535+
self.server.id,
6536+
callback=mock.ANY,
6537+
success_status=['active'],
6538+
# **kwargs
6539+
)
6540+
6541+
self.servers_mock.get.assert_called_with(self.server.id)
6542+
self.get_image_mock.assert_called_with(self.image.id)
6543+
self.server.rebuild.assert_called_with(self.image, None)
6544+
6545+
def test_rebuild_wrong_status_fails(self):
6546+
self.server.status = 'SHELVED'
6547+
arglist = [
6548+
self.server.id,
6549+
]
6550+
verifylist = [
6551+
('server', self.server.id),
6552+
]
6553+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
6554+
6555+
self.assertRaises(
6556+
exceptions.CommandError, self.cmd.take_action, parsed_args
6557+
)
6558+
6559+
self.servers_mock.get.assert_called_with(self.server.id)
6560+
self.get_image_mock.assert_called_with(self.image.id)
6561+
self.server.rebuild.assert_not_called()
6562+
64826563
def test_rebuild_with_property(self):
64836564
arglist = [
64846565
self.server.id,
@@ -6837,6 +6918,7 @@ def setUp(self):
68376918

68386919
# Fake the server to be rebuilt. The IDs of them should be the same.
68396920
attrs['id'] = new_server.id
6921+
attrs['status'] = 'ACTIVE'
68406922
methods = {
68416923
'rebuild': new_server,
68426924
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
features:
3+
- |
4+
``openstack server rebuild`` command now fails early if the server is
5+
not in a state supported for rebuild - either ``ACTIVE``, ``ERROR`` or
6+
``SHUTOFF``.
7+
See `OpenStack Compute API reference for server rebuild action
8+
<https://docs.openstack.org/api-ref/compute/?expanded=rebuild-server-rebuild-action-detail#rebuild-server-rebuild-action>`_.
9+
fixes:
10+
- |
11+
``openstack server rebuild --wait`` now properly works for servers in
12+
``SHUTOFF`` state without hanging.
13+
[Story `2010751 <https://storyboard.openstack.org/#!/story/2010751>`_]

0 commit comments

Comments
 (0)