Implement force detach volume
1.what is the problem? In Trio2o, when a volume is in a stuck 'attaching' or 'detaching', Pod can not detaching it by nova-apigw 'detach volume', so that this volume can not reuse by ohther Pod. In addition, it may cause un-synchronization between the Cinder database and the backend storage. There is an user case in nova[1]. It may also occur on a trio2o Pod. We don't need to worry about its security, because the Cinder api 'os-force-detach' is for safe cleanup. More user case and information about 'force detach' in this document[2]. 2.what is the solution to the problem? We use Cinder api "os-force-detach" to detach it. 3. What the features need to be implemented to the Trio2o to realize the solution? Implement the force detach server action. [1] https://blueprints.launchpad.net/nova/+spec/add-force-detach-to-nova [2] https://github.com/openstack/cinder-specs/blob/master/specs/liberty/implement-force-detach-for-safe-cleanup.rst Change-Id: Iea15c4d9ce469fb640e7e98c1859a18fe12ce7f3
This commit is contained in:
parent
b2c436bfca
commit
98940f1b24
|
@ -42,7 +42,8 @@ class VolumeActionController(rest.RestController):
|
||||||
'os-reset_status': self._reset_status,
|
'os-reset_status': self._reset_status,
|
||||||
'os-set_image_metadata': self._set_image_metadata,
|
'os-set_image_metadata': self._set_image_metadata,
|
||||||
'os-unset_image_metadata': self._unset_image_metadata,
|
'os-unset_image_metadata': self._unset_image_metadata,
|
||||||
'os-show_image_metadata': self._show_image_metadata
|
'os-show_image_metadata': self._show_image_metadata,
|
||||||
|
'os-force_detach': self._force_detach
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_client(self, pod_name=constants.TOP):
|
def _get_client(self, pod_name=constants.TOP):
|
||||||
|
@ -104,6 +105,15 @@ class VolumeActionController(rest.RestController):
|
||||||
return self._action(context, pod_name, 'os-extend',
|
return self._action(context, pod_name, 'os-extend',
|
||||||
{'new_size': new_size})
|
{'new_size': new_size})
|
||||||
|
|
||||||
|
def _force_detach(self, context, pod_name, kw):
|
||||||
|
"""Forces a volume to detach
|
||||||
|
|
||||||
|
:param pod_name: the bottom pod name.
|
||||||
|
:param kw: request body.
|
||||||
|
"""
|
||||||
|
body = kw['os-force_detach']
|
||||||
|
return self._action(context, pod_name, 'os-force_detach', body)
|
||||||
|
|
||||||
def _reset_status(self, context, pod_name, kw):
|
def _reset_status(self, context, pod_name, kw):
|
||||||
"""Update the provided volume with the provided state.
|
"""Update the provided volume with the provided state.
|
||||||
|
|
||||||
|
|
|
@ -196,6 +196,27 @@ class VolumeActionTest(unittest.TestCase):
|
||||||
mock_action.assert_called_once_with(url, body=body)
|
mock_action.assert_called_once_with(url, body=body)
|
||||||
self.assertEqual(202, res.status)
|
self.assertEqual(202, res.status)
|
||||||
|
|
||||||
|
@patch.object(pecan, 'response', new=FakeResponse)
|
||||||
|
@patch.object(HTTPClient, 'post')
|
||||||
|
@patch.object(context, 'extract_context_from_environ')
|
||||||
|
def test_force_detach_volume_action(self, mock_context, mock_action):
|
||||||
|
mock_context.return_value = self.context
|
||||||
|
mock_action.return_value = (FakeResponse(202), None)
|
||||||
|
|
||||||
|
t_pod, b_pods = self._prepare_pod()
|
||||||
|
self._prepare_pod_service(b_pods[0]['pod_id'], constants.ST_CINDER)
|
||||||
|
t_volume_id = self._prepare_volume(b_pods[0])
|
||||||
|
t_server_id = self._prepare_server(b_pods[0])
|
||||||
|
self.controller.volume_id = t_volume_id
|
||||||
|
body = {"os-force_detach": {
|
||||||
|
"attachment_id": t_server_id,
|
||||||
|
"connector": {
|
||||||
|
"initiator": "iqn.2012-07.org.fake:01"}}}
|
||||||
|
res = self.controller.post(**body)
|
||||||
|
url = '/volumes/%s/action' % t_volume_id
|
||||||
|
mock_action.assert_called_once_with(url, body=body)
|
||||||
|
self.assertEqual(202, res.status)
|
||||||
|
|
||||||
@patch.object(pecan, 'response', new=FakeResponse)
|
@patch.object(pecan, 'response', new=FakeResponse)
|
||||||
@patch.object(HTTPClient, 'post')
|
@patch.object(HTTPClient, 'post')
|
||||||
@patch.object(context, 'extract_context_from_environ')
|
@patch.object(context, 'extract_context_from_environ')
|
||||||
|
|
Loading…
Reference in New Issue