[Unity] Add `force detach` support

Add support to force detach a volume from all hosts on Unity.

Closes-bug: #1741831
Change-Id: I5f0f3d474b00f3c1f742c1bfa6877911415c32f9
This commit is contained in:
Ryan Liang 2018-01-17 15:00:09 +08:00
parent 9cbb200ec2
commit b44721dfac
7 changed files with 60 additions and 2 deletions

View File

@ -58,6 +58,14 @@ class DetachIsCalled(Exception):
pass
class DetachAllIsCalled(Exception):
pass
class DetachFromIsCalled(Exception):
pass
class LunDeleteIsCalled(Exception):
pass

View File

@ -140,6 +140,12 @@ class MockClient(object):
if host.name == 'host1' and lun_or_snap.get_id() in error_ids:
raise ex.DetachIsCalled()
@staticmethod
def detach_all(lun):
error_ids = ['lun_44']
if lun.get_id() in error_ids:
raise ex.DetachAllIsCalled()
@staticmethod
def get_iscsi_target_info(allowed_ports=None):
return [{'portal': '1.2.3.4:1234', 'iqn': 'iqn.1-1.com.e:c.a.a0'},
@ -443,6 +449,13 @@ class CommonAdapterTest(test.TestCase):
self.assertRaises(ex.DetachIsCalled, f)
def test_terminate_connection_force_detach(self):
def f():
volume = MockOSResource(provider_location='id^lun_44', id='id_44')
self.adapter.terminate_connection(volume, None)
self.assertRaises(ex.DetachAllIsCalled, f)
def test_terminate_connection_snapshot(self):
def f():
connector = {'host': 'host1'}

View File

@ -100,6 +100,11 @@ class MockResource(object):
if lun_or_snap.name == 'detach_failure':
raise ex.DetachIsCalled()
@staticmethod
def detach_from(host):
if host is None:
raise ex.DetachFromIsCalled()
def get_hlu(self, lun):
return self.alu_hlu_map.get(lun.get_id(), None)
@ -446,6 +451,13 @@ class ClientTest(unittest.TestCase):
self.assertRaises(ex.DetachIsCalled, f)
def test_detach_all(self):
def f():
lun = MockResource('lun_44')
self.client.detach_all(lun)
self.assertRaises(ex.DetachFromIsCalled, f)
@mock.patch.object(coordination.Coordinator, 'get_lock')
def test_create_host(self, fake):
self.assertEqual('host2', self.client.create_host('host2').name)

View File

@ -312,8 +312,12 @@ class CommonAdapter(object):
return self._initialize_connection(lun, connector, volume.id)
def _terminate_connection(self, lun_or_snap, connector):
host = self.client.create_host(connector['host'])
self.client.detach(host, lun_or_snap)
is_force_detach = connector is None
if is_force_detach:
self.client.detach_all(lun_or_snap)
else:
host = self.client.create_host(connector['host'])
self.client.detach(host, lun_or_snap)
@cinder_utils.trace
def terminate_connection(self, volume, connector):

View File

@ -253,6 +253,15 @@ class UnityClient(object):
lun_or_snap.update()
host.detach(lun_or_snap)
@staticmethod
def detach_all(lun):
"""Detaches a `UnityLun` from all hosts.
:param lun: `UnityLun` object
"""
lun.update()
lun.detach_from(host=None)
def get_ethernet_ports(self):
return self.system.get_ethernet_port()

View File

@ -301,6 +301,14 @@ For data path, please follow below steps:
- If you create a volume using Cinder and attach it to a VM,
the connection between this VM and volume will be IPv6-based iSCSI.
Force detach volume from all hosts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The user could use `os-force_detach` action to detach a volume from all its
attached hosts.
For more detail, please refer to
https://developer.openstack.org/api-ref/block-storage/v2/?expanded=force-detach-volume-detail#force-detach-volume
Troubleshooting
~~~~~~~~~~~~~~~

View File

@ -0,0 +1,4 @@
---
features:
- |
Add support to force detach a volume from all hosts on Unity.