Skip to content

Commit db4739f

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Require confirmation to reset server state."
2 parents d123be0 + 25cd117 commit db4739f

File tree

3 files changed

+96
-4
lines changed

3 files changed

+96
-4
lines changed

openstackclient/compute/v2/server.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4481,15 +4481,27 @@ def get_parser(self, prog_name):
44814481
'(repeat option to set multiple properties)'
44824482
),
44834483
)
4484+
parser.add_argument(
4485+
'--auto-approve',
4486+
action='store_true',
4487+
help=_(
4488+
"Allow server state override without asking for confirmation"
4489+
),
4490+
)
44844491
parser.add_argument(
44854492
'--state',
44864493
metavar='<state>',
44874494
choices=['active', 'error'],
44884495
help=_(
4489-
'New server state '
4490-
'**WARNING** This can result in instances that are no longer '
4491-
'usable and should be used with caution '
4492-
'(admin only)'
4496+
'New server state.'
4497+
'**WARNING** Resetting the state is intended to work around '
4498+
'servers stuck in an intermediate state, such as deleting. '
4499+
'If the server is in an error state then this is almost '
4500+
'never the correct command to run and you should prefer hard '
4501+
'reboot where possible. In particular, if the server is in '
4502+
'an error state due to a move operation, setting the state '
4503+
'can result in instances that are no longer usable. Proceed '
4504+
'with caution. (admin only)'
44934505
),
44944506
)
44954507
parser.add_argument(
@@ -4524,6 +4536,20 @@ def get_parser(self, prog_name):
45244536
)
45254537
return parser
45264538

4539+
@staticmethod
4540+
def ask_user_yesno(msg):
4541+
"""Ask user Y/N question
4542+
4543+
:param str msg: question text
4544+
:return bool: User choice
4545+
"""
4546+
while True:
4547+
answer = getpass.getpass('{} [{}]: '.format(msg, 'y/n'))
4548+
if answer in ('y', 'Y', 'yes'):
4549+
return True
4550+
elif answer in ('n', 'N', 'no'):
4551+
return False
4552+
45274553
def take_action(self, parsed_args):
45284554
compute_client = self.app.client_manager.compute
45294555
server = compute_client.find_server(
@@ -4574,6 +4600,17 @@ def take_action(self, parsed_args):
45744600
)
45754601

45764602
if parsed_args.state:
4603+
if not parsed_args.auto_approve:
4604+
if not self.ask_user_yesno(
4605+
_(
4606+
"Resetting the server state can make it much harder "
4607+
"to recover a server from an error state. If the "
4608+
"server is in error status due to a failed move "
4609+
"operation then this is likely not the correct "
4610+
"approach to fix the problem. Do you wish to continue?"
4611+
)
4612+
):
4613+
return
45774614
compute_client.reset_server_state(server, state=parsed_args.state)
45784615

45794616
if parsed_args.root_password:

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7943,6 +7943,7 @@ def test_server_set_with_state(self):
79437943
arglist = [
79447944
'--state',
79457945
'active',
7946+
'--auto-approve',
79467947
self.server.id,
79477948
]
79487949
verifylist = [
@@ -7963,6 +7964,54 @@ def test_server_set_with_state(self):
79637964
self.compute_client.add_tag_to_server.assert_not_called()
79647965
self.assertIsNone(result)
79657966

7967+
def test_server_set_with_state_prompt_y(self):
7968+
arglist = [
7969+
'--state',
7970+
'active',
7971+
self.server.id,
7972+
]
7973+
verifylist = [
7974+
('state', 'active'),
7975+
('server', self.server.id),
7976+
]
7977+
7978+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
7979+
with mock.patch('getpass.getpass', return_value='y'):
7980+
result = self.cmd.take_action(parsed_args)
7981+
7982+
self.compute_client.reset_server_state.assert_called_once_with(
7983+
self.server, state='active'
7984+
)
7985+
self.compute_client.update_server.assert_not_called()
7986+
self.compute_client.set_server_metadata.assert_not_called()
7987+
self.compute_client.change_server_password.assert_not_called()
7988+
self.compute_client.clear_server_password.assert_not_called()
7989+
self.compute_client.add_tag_to_server.assert_not_called()
7990+
self.assertIsNone(result)
7991+
7992+
def test_server_set_with_state_prompt_n(self):
7993+
arglist = [
7994+
'--state',
7995+
'active',
7996+
self.server.id,
7997+
]
7998+
verifylist = [
7999+
('state', 'active'),
8000+
('server', self.server.id),
8001+
]
8002+
8003+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
8004+
with mock.patch('getpass.getpass', return_value='n'):
8005+
result = self.cmd.take_action(parsed_args)
8006+
8007+
self.compute_client.reset_server_state.assert_not_called()
8008+
self.compute_client.update_server.assert_not_called()
8009+
self.compute_client.set_server_metadata.assert_not_called()
8010+
self.compute_client.change_server_password.assert_not_called()
8011+
self.compute_client.clear_server_password.assert_not_called()
8012+
self.compute_client.add_tag_to_server.assert_not_called()
8013+
self.assertIsNone(result)
8014+
79668015
def test_server_set_with_invalid_state(self):
79678016
arglist = [
79688017
'--state',
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
upgrade:
3+
- |
4+
The ``openstack server set`` command has been extended with a new
5+
parameter ``--auto-approve`` and the existing ``--state`` parameter
6+
has been modified to require confirmation before resetting the state.

0 commit comments

Comments
 (0)