Skip to content

Commit a272835

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Allow server rebuild --wait for SHUTOFF servers"
2 parents 938850b + 417a7ad commit a272835

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
@@ -6241,6 +6241,7 @@ def setUp(self):
62416241

62426242
# Fake the server to be rebuilt. The IDs of them should be the same.
62436243
attrs['id'] = new_server.id
6244+
attrs['status'] = 'ACTIVE'
62446245
methods = {
62456246
'rebuild': new_server,
62466247
}
@@ -6439,6 +6440,7 @@ def test_rebuild_with_wait_ok(self, mock_wait_for_status):
64396440
self.servers_mock.get,
64406441
self.server.id,
64416442
callback=mock.ANY,
6443+
success_status=['active'],
64426444
# **kwargs
64436445
)
64446446

@@ -6464,12 +6466,91 @@ def test_rebuild_with_wait_fails(self, mock_wait_for_status):
64646466
self.servers_mock.get,
64656467
self.server.id,
64666468
callback=mock.ANY,
6469+
success_status=['active'],
64676470
)
64686471

64696472
self.servers_mock.get.assert_called_with(self.server.id)
64706473
self.get_image_mock.assert_called_with(self.image.id)
64716474
self.server.rebuild.assert_called_with(self.image, None)
64726475

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

68296910
# Fake the server to be rebuilt. The IDs of them should be the same.
68306911
attrs['id'] = new_server.id
6912+
attrs['status'] = 'ACTIVE'
68316913
methods = {
68326914
'rebuild': new_server,
68336915
}
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)