Try to do unlock when delete userid failed
Right now, if delete userid failed due to image lock or device lock, zvm driver has a looping call to check lock status with 10 minutes timeout. Normaly, the image or device was locked by disk related actions which could not be unlocked in short time. So turn to call image_unlock_dm try to unlock it. Then try to delete the vm again. Change-Id: I848d042231757d8673700e3db2b46f8fc9757596
This commit is contained in:
@@ -1969,87 +1969,25 @@ class ZVMInstanceTestCases(ZVMTestCase):
|
||||
self.assertRaises(exception.ZVMXCATDeployNodeFailed,
|
||||
self._instance.deploy_node, 'fakeimg', '/fake/file')
|
||||
|
||||
def test_delete_userid_is_locked(self):
|
||||
resp = {'error': [['Return Code: 400\nReason Code: 16\n']]}
|
||||
|
||||
self.mox.StubOutWithMock(zvmutils, 'xcat_request')
|
||||
self.mox.StubOutWithMock(self._instance, '_wait_for_unlock')
|
||||
zvmutils.xcat_request("DELETE", mox.IgnoreArg()).AndRaise(
|
||||
exception.ZVMXCATInternalError(msg=str(resp)))
|
||||
self._instance._wait_for_unlock('fakehcp')
|
||||
zvmutils.xcat_request("DELETE", mox.IgnoreArg())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@mock.patch('nova.virt.zvm.instance.ZVMInstance.unlock_userid')
|
||||
@mock.patch('nova.virt.zvm.instance.ZVMInstance._delete_userid')
|
||||
def test_delete_userid_is_locked(self, delete_uid, unlock_uid):
|
||||
delete_uid.side_effect = [exception.ZVMXCATInternalError(
|
||||
'Return Code: 400\nReason Code: 12\n'),
|
||||
None]
|
||||
self._instance.delete_userid('fakehcp', {})
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_delete_userid_is_locked_and_notexist(self):
|
||||
resp = {'error': [['Return Code: 400\nReason Code: 16\n']]}
|
||||
|
||||
self.mox.StubOutWithMock(self._instance, 'delete_xcat_node')
|
||||
self.mox.StubOutWithMock(zvmutils, 'xcat_request')
|
||||
self.mox.StubOutWithMock(self._instance, '_wait_for_unlock')
|
||||
zvmutils.xcat_request("DELETE", mox.IgnoreArg()).AndRaise(
|
||||
exception.ZVMXCATInternalError(msg=str(resp)))
|
||||
self._instance._wait_for_unlock('fakehcp')
|
||||
|
||||
resp = {'error': [['Return Code: 400\nReason Code: 4\n']]}
|
||||
zvmutils.xcat_request("DELETE", mox.IgnoreArg()).AndRaise(
|
||||
exception.ZVMXCATInternalError(msg=str(resp)))
|
||||
self._instance.delete_xcat_node()
|
||||
self.mox.ReplayAll()
|
||||
delete_uid.assert_called()
|
||||
unlock_uid.assert_called_once_with('fakehcp')
|
||||
|
||||
@mock.patch('nova.virt.zvm.instance.ZVMInstance.unlock_devices')
|
||||
@mock.patch('nova.virt.zvm.instance.ZVMInstance._delete_userid')
|
||||
def test_delete_userid_device_is_locked(self, delete_uid, unlock_dev):
|
||||
delete_uid.side_effect = [exception.ZVMXCATInternalError(
|
||||
'Return Code: 408\nReason Code: 12\n'),
|
||||
None]
|
||||
self._instance.delete_userid('fakehcp', {})
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_delete_userid_400012(self):
|
||||
resp = {'error': [['Return Code: 400\nReason Code: 12\n']]}
|
||||
|
||||
self.mox.StubOutWithMock(zvmutils, 'xcat_request')
|
||||
self.mox.StubOutWithMock(self._instance, '_wait_for_unlock')
|
||||
zvmutils.xcat_request("DELETE", mox.IgnoreArg()).AndRaise(
|
||||
exception.ZVMXCATInternalError(msg=str(resp)))
|
||||
self._instance._wait_for_unlock('fakehcp')
|
||||
zvmutils.xcat_request("DELETE", mox.IgnoreArg())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self._instance.delete_userid('fakehcp', {})
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_is_locked_true(self):
|
||||
resp = {'data': [['os000001: os000001 is locked']]}
|
||||
|
||||
self.mox.StubOutWithMock(zvmutils, 'xdsh')
|
||||
execstr = "/opt/zhcp/bin/smcli Image_Lock_Query_DM -T os000001"
|
||||
zvmutils.xdsh('fakehcp', execstr).AndReturn(resp)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
locked = self._instance.is_locked('fakehcp')
|
||||
self.mox.VerifyAll()
|
||||
|
||||
self.assertTrue(locked)
|
||||
|
||||
def test_is_locked_false(self):
|
||||
resp = {'data': [['os000001: os000001 is Unlocked...']]}
|
||||
|
||||
self.mox.StubOutWithMock(zvmutils, 'xdsh')
|
||||
execstr = "/opt/zhcp/bin/smcli Image_Lock_Query_DM -T os000001"
|
||||
zvmutils.xdsh('fakehcp', execstr).AndReturn(resp)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
locked = self._instance.is_locked('fakehcp')
|
||||
self.mox.VerifyAll()
|
||||
|
||||
self.assertFalse(locked)
|
||||
|
||||
def test_wait_for_unlock(self):
|
||||
self.mox.StubOutWithMock(self._instance, 'is_locked')
|
||||
self._instance.is_locked('fakehcp').AndReturn(True)
|
||||
self._instance.is_locked('fakehcp').AndReturn(False)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self._instance._wait_for_unlock('fakehcp', 1)
|
||||
self.mox.VerifyAll()
|
||||
delete_uid.assert_called()
|
||||
unlock_dev.assert_called_once_with('fakehcp')
|
||||
|
||||
def test_modify_storage_format(self):
|
||||
mem = self._instance._modify_storage_format('0')
|
||||
@@ -2166,6 +2104,24 @@ class ZVMInstanceTestCases(ZVMTestCase):
|
||||
self.assertEqual(0, inst_info.cpu_time_ns)
|
||||
self.assertEqual(1048576, inst_info.max_mem_kb)
|
||||
|
||||
@mock.patch('nova.virt.zvm.utils.xdsh')
|
||||
@mock.patch('nova.virt.zvm.instance.ZVMInstance.get_userid')
|
||||
def test_unlock_devices(self, get_uid, xdsh):
|
||||
get_uid.return_value = 'fakeuid'
|
||||
xdshv1 = {'data': [['Locked type: DEVICE\nDevice address: 0100\n'
|
||||
'Device locked by: fake\nDevice address: 0101\n'
|
||||
'Device locked by: fake']]}
|
||||
xdsh.side_effect = [xdshv1, None, None]
|
||||
self._instance.unlock_devices('fakezhcp')
|
||||
|
||||
get_uid.assert_called_with()
|
||||
xdsh.assert_any_call('fakezhcp',
|
||||
'/opt/zhcp/bin/smcli Image_Lock_Query_DM -T fakeuid')
|
||||
xdsh.assert_any_call('fakezhcp',
|
||||
'/opt/zhcp/bin/smcli Image_Unlock_DM -T fakeuid -v 0100')
|
||||
xdsh.assert_any_call('fakezhcp',
|
||||
'/opt/zhcp/bin/smcli Image_Unlock_DM -T fakeuid -v 0101')
|
||||
|
||||
|
||||
class ZVMXCATConnectionTestCases(test.TestCase):
|
||||
"""Test cases for xCAT connection."""
|
||||
|
||||
@@ -14,14 +14,11 @@
|
||||
|
||||
|
||||
import binascii
|
||||
import datetime
|
||||
import six
|
||||
import time
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import loopingcall
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from nova.compute import power_state
|
||||
from nova import exception as nova_exception
|
||||
@@ -460,29 +457,35 @@ class ZVMInstance(object):
|
||||
url = self._xcat_url.chvm('/' + self._name)
|
||||
zvmutils.xcat_request("PUT", url, body)
|
||||
|
||||
def is_locked(self, zhcp_node):
|
||||
cmd = "/opt/zhcp/bin/smcli Image_Lock_Query_DM -T %s" % self._name
|
||||
def get_userid(self):
|
||||
return zvmutils.get_userid(self._name)
|
||||
|
||||
def unlock_userid(self, zhcp_node):
|
||||
_uid = self.get_userid()
|
||||
cmd = "/opt/zhcp/bin/smcli Image_Unlock_DM -T %s" % _uid
|
||||
zvmutils.xdsh(zhcp_node, cmd)
|
||||
|
||||
def unlock_devices(self, zhcp_node):
|
||||
_uid = self.get_userid()
|
||||
cmd = "/opt/zhcp/bin/smcli Image_Lock_Query_DM -T %s" % _uid
|
||||
resp = zvmutils.xdsh(zhcp_node, cmd)
|
||||
with zvmutils.expect_invalid_xcat_resp_data(resp):
|
||||
resp_str = resp['data'][0][0]
|
||||
|
||||
return "is Unlocked..." not in str(resp)
|
||||
if resp_str.__contains__("is Unlocked..."):
|
||||
# unlocked automatically, do nothing
|
||||
return
|
||||
|
||||
def _wait_for_unlock(self, zhcp_node, interval=60, timeout=300):
|
||||
LOG.debug("Waiting for unlock instance %s", self._name)
|
||||
def _unlock_device(vdev):
|
||||
cmd = ("/opt/zhcp/bin/smcli Image_Unlock_DM -T %(uid)s -v %(vdev)s"
|
||||
% {'uid': _uid, 'vdev': vdev})
|
||||
zvmutils.xdsh(zhcp_node, cmd)
|
||||
|
||||
def _wait_unlock(expiration):
|
||||
if timeutils.utcnow() > expiration:
|
||||
LOG.debug("Waiting for unlock instance %s timeout", self._name)
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
if not self.is_locked(zhcp_node):
|
||||
LOG.debug("Instance %s is unlocked", self._name)
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
expiration = timeutils.utcnow() + datetime.timedelta(seconds=timeout)
|
||||
|
||||
timer = loopingcall.FixedIntervalLoopingCall(_wait_unlock,
|
||||
expiration)
|
||||
timer.start(interval=interval).wait()
|
||||
resp_list = resp_str.split('\n')
|
||||
for s in resp_list:
|
||||
if s.__contains__('Device address:'):
|
||||
vdev = s.rpartition(':')[2].strip()
|
||||
_unlock_device(vdev)
|
||||
|
||||
def _delete_userid(self, url):
|
||||
try:
|
||||
@@ -511,15 +514,19 @@ class ZVMInstance(object):
|
||||
except exception.ZVMXCATInternalError as err:
|
||||
emsg = err.format_message()
|
||||
if (emsg.__contains__("Return Code: 400") and
|
||||
(emsg.__contains__("Reason Code: 16") or
|
||||
emsg.__contains__("Reason Code: 12"))):
|
||||
# The vm or vm device was locked. Unlock before deleting
|
||||
self._wait_for_unlock(zhcp_node)
|
||||
self._delete_userid(url)
|
||||
emsg.__contains__("Reason Code: 12")):
|
||||
# The vm was locked. Unlock before deleting
|
||||
self.unlock_userid(zhcp_node)
|
||||
elif (emsg.__contains__("Return Code: 408") and
|
||||
emsg.__contains__("Reason Code: 12")):
|
||||
# The vm device was locked. Unlock the device before deleting
|
||||
self.unlock_devices(zhcp_node)
|
||||
else:
|
||||
LOG.debug("exception not able to handle in delete_userid "
|
||||
"%s", self._name)
|
||||
raise err
|
||||
# delete the vm after unlock
|
||||
self._delete_userid(url)
|
||||
except exception.ZVMXCATRequestFailed as err:
|
||||
emsg = err.format_message()
|
||||
if (emsg.__contains__("Invalid nodes and/or groups") and
|
||||
|
||||
Reference in New Issue
Block a user