Disallow host-unlock if a lock operation is in progress
If host-unlock is issued while a host-lock or host-lock force operation is already in progress, restore the original host action and reject the host-unlock in order to allow the lock operation to terminate normally. Change-Id: Ib82da93aa4a55f5cd3f41ab904745bea7c4e3afb Closes-Bug: 1847330 Signed-off-by: John Kung <john.kung@windriver.com>
This commit is contained in:
parent
64bdd3e869
commit
d70d45669d
|
@ -4350,17 +4350,30 @@ class HostController(rest.RestController):
|
|||
if action == constants.UNLOCK_ACTION:
|
||||
# Set ihost_action in DB as early as possible as we need
|
||||
# it as a synchronization point for things like lvg/pv
|
||||
# deletion which is not allowed when ihost is unlokced
|
||||
# deletion which is not allowed when host is unlocked
|
||||
# or in the process of unlocking.
|
||||
rc = self.update_ihost_action(action, hostupdate)
|
||||
if rc:
|
||||
pecan.request.dbapi.ihost_update(hostupdate.ihost_orig['uuid'],
|
||||
hostupdate.ihost_val_prenotify)
|
||||
host_action_orig = \
|
||||
hostupdate.ihost_orig.get('ihost_action', "")
|
||||
try:
|
||||
self.check_unlock(hostupdate, force_unlock)
|
||||
except exception.HostLocking:
|
||||
msg = _("Host unlock rejected due to in progress action %s"
|
||||
% host_action_orig.strip('-'))
|
||||
self.update_ihost_action(host_action_orig, hostupdate)
|
||||
pecan.request.dbapi.ihost_update(
|
||||
hostupdate.ihost_orig['uuid'],
|
||||
hostupdate.ihost_val_prenotify)
|
||||
# raise as a Client side exception
|
||||
raise wsme.exc.ClientSideError(msg)
|
||||
except Exception:
|
||||
LOG.info("host unlock check didn't pass, "
|
||||
"so set the ihost_action back to None and re-raise the exception")
|
||||
"so set the ihost_action (%s) back to None "
|
||||
"and re-raise the exception" %
|
||||
host_action_orig)
|
||||
self.update_ihost_action(None, hostupdate)
|
||||
pecan.request.dbapi.ihost_update(hostupdate.ihost_orig['uuid'],
|
||||
hostupdate.ihost_val_prenotify)
|
||||
|
@ -5006,9 +5019,16 @@ class HostController(rest.RestController):
|
|||
|
||||
# Semantic Check: Avoid Unlock of Unlocked Host
|
||||
if hostupdate.ihost_orig['administrative'] == constants.ADMIN_UNLOCKED:
|
||||
raise wsme.exc.ClientSideError(
|
||||
_("Avoiding 'unlock' action on already "
|
||||
"'unlocked' host %s" % hostupdate.ihost_orig['hostname']))
|
||||
host_action = hostupdate.ihost_orig['ihost_action'] or ""
|
||||
if (host_action.startswith(constants.LOCK_ACTION) or
|
||||
host_action.startswith(constants.FORCE_LOCK_ACTION)):
|
||||
raise exception.HostLocking(
|
||||
host=hostupdate.ihost_orig['hostname'],
|
||||
action=host_action.strip('-'))
|
||||
else:
|
||||
raise wsme.exc.ClientSideError(
|
||||
_("Avoiding 'unlock' action on already "
|
||||
"'unlocked' host %s" % hostupdate.ihost_orig['hostname']))
|
||||
|
||||
# Semantic Check: Action Dependency: Power-Off / Unlock case
|
||||
if (hostupdate.ihost_orig['availability'] ==
|
||||
|
|
|
@ -806,6 +806,11 @@ class RouteNotFoundByName(NotFound):
|
|||
"could not be found.")
|
||||
|
||||
|
||||
class HostLocking(SysinvException):
|
||||
message = _("Unable to complete the action because "
|
||||
"host %(host)s is undergoing action %(action)s.")
|
||||
|
||||
|
||||
class HostLocked(SysinvException):
|
||||
message = _("Unable to complete the action %(action)s because "
|
||||
"Host %(host)s is in administrative state = unlocked.")
|
||||
|
|
|
@ -757,6 +757,86 @@ class TestPatch(TestHost):
|
|||
result = self.get_json('/ihosts/%s' % w0_host['hostname'])
|
||||
self.assertEqual(constants.NONE_ACTION, result['action'])
|
||||
|
||||
def test_unlock_action_worker_while_locking(self):
|
||||
# Create controller-0
|
||||
self._create_controller_0(
|
||||
invprovision=constants.PROVISIONED,
|
||||
administrative=constants.ADMIN_UNLOCKED,
|
||||
operational=constants.OPERATIONAL_ENABLED,
|
||||
availability=constants.AVAILABILITY_ONLINE)
|
||||
|
||||
# Create worker-0
|
||||
w0_host = self._create_worker(
|
||||
mgmt_ip='192.168.204.5',
|
||||
invprovision=constants.PROVISIONED,
|
||||
administrative=constants.ADMIN_UNLOCKED,
|
||||
operational=constants.OPERATIONAL_ENABLED,
|
||||
availability=constants.AVAILABILITY_AVAILABLE,
|
||||
ihost_action=constants.LOCK_ACTION)
|
||||
self._create_test_host_platform_interface(w0_host)
|
||||
self._create_test_host_cpus(
|
||||
w0_host, platform=1, vswitch=2, application=12)
|
||||
|
||||
# Unlock worker host while lock action in progress
|
||||
response = self._patch_host_action(w0_host['hostname'],
|
||||
constants.UNLOCK_ACTION,
|
||||
'sysinv-test',
|
||||
expect_errors=True)
|
||||
|
||||
# Verify that the unlock was not sent to the VIM
|
||||
self.mock_vim_api_host_action.assert_not_called()
|
||||
# Verify that the host was not modified in maintenance
|
||||
self.mock_mtce_api_host_modify.assert_not_called()
|
||||
|
||||
self.assertEqual(response.content_type, 'application/json')
|
||||
self.assertEqual(http_client.BAD_REQUEST, response.status_int)
|
||||
self.assertIn('Host unlock rejected due to in progress action %s' %
|
||||
constants.LOCK_ACTION,
|
||||
response.json['error_message'])
|
||||
|
||||
result = self.get_json('/ihosts/%s' % w0_host['hostname'])
|
||||
self.assertEqual(constants.LOCK_ACTION, result['ihost_action'])
|
||||
|
||||
def test_unlock_action_worker_while_force_locking(self):
|
||||
# Create controller-0
|
||||
self._create_controller_0(
|
||||
invprovision=constants.PROVISIONED,
|
||||
administrative=constants.ADMIN_UNLOCKED,
|
||||
operational=constants.OPERATIONAL_ENABLED,
|
||||
availability=constants.AVAILABILITY_ONLINE)
|
||||
|
||||
# Create worker-0
|
||||
w0_host = self._create_worker(
|
||||
mgmt_ip='192.168.204.5',
|
||||
invprovision=constants.PROVISIONED,
|
||||
administrative=constants.ADMIN_UNLOCKED,
|
||||
operational=constants.OPERATIONAL_ENABLED,
|
||||
availability=constants.AVAILABILITY_AVAILABLE,
|
||||
ihost_action=constants.FORCE_LOCK_ACTION)
|
||||
self._create_test_host_platform_interface(w0_host)
|
||||
self._create_test_host_cpus(
|
||||
w0_host, platform=1, vswitch=2, application=12)
|
||||
|
||||
# Unlock worker host while lock action in progress
|
||||
response = self._patch_host_action(w0_host['hostname'],
|
||||
constants.UNLOCK_ACTION,
|
||||
'sysinv-test',
|
||||
expect_errors=True)
|
||||
|
||||
# Verify that the unlock was not sent to the VIM
|
||||
self.mock_vim_api_host_action.assert_not_called()
|
||||
# Verify that the host was not modified in maintenance
|
||||
self.mock_mtce_api_host_modify.assert_not_called()
|
||||
|
||||
self.assertEqual(response.content_type, 'application/json')
|
||||
self.assertEqual(http_client.BAD_REQUEST, response.status_int)
|
||||
self.assertIn('Host unlock rejected due to in progress action %s' %
|
||||
constants.FORCE_LOCK_ACTION,
|
||||
response.json['error_message'])
|
||||
|
||||
result = self.get_json('/ihosts/%s' % w0_host['hostname'])
|
||||
self.assertEqual(constants.FORCE_LOCK_ACTION, result['ihost_action'])
|
||||
|
||||
def test_lock_action_worker(self):
|
||||
# Create controller-0
|
||||
self._create_controller_0(
|
||||
|
|
Loading…
Reference in New Issue