diff --git a/trio2o/cinder_apigw/controllers/volume_actions.py b/trio2o/cinder_apigw/controllers/volume_actions.py index a36ac6b..02cd536 100644 --- a/trio2o/cinder_apigw/controllers/volume_actions.py +++ b/trio2o/cinder_apigw/controllers/volume_actions.py @@ -42,7 +42,8 @@ class VolumeActionController(rest.RestController): 'os-reset_status': self._reset_status, 'os-set_image_metadata': self._set_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): @@ -104,6 +105,15 @@ class VolumeActionController(rest.RestController): return self._action(context, pod_name, 'os-extend', {'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): """Update the provided volume with the provided state. diff --git a/trio2o/tests/unit/cinder_apigw/controllers/test_volume_actions.py b/trio2o/tests/unit/cinder_apigw/controllers/test_volume_actions.py index 9e6e39a..4583457 100644 --- a/trio2o/tests/unit/cinder_apigw/controllers/test_volume_actions.py +++ b/trio2o/tests/unit/cinder_apigw/controllers/test_volume_actions.py @@ -196,6 +196,27 @@ class VolumeActionTest(unittest.TestCase): mock_action.assert_called_once_with(url, body=body) 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(HTTPClient, 'post') @patch.object(context, 'extract_context_from_environ')