Add test case for force detach volume

V2 volumes_client in Tempest doesn't contain volume action: force
detach volume. This patch adds the support.

Including:

[1] Add force detach volume api to v2 volumes client
[2] Add release notes
[3] Add unit test for force detach volume api
[3] Add test case: test_force_detach_volume

Change-Id: I172913b7d372225328a3c30299926c599c7d245a
This commit is contained in:
jeremy.zhang 2017-04-25 15:11:15 +08:00
parent 3f06f4b9d7
commit 7b0eaf8f54
4 changed files with 109 additions and 0 deletions

View File

@ -0,0 +1,6 @@
---
features:
- |
Add force detach volume feature API to v2 volumes_client library.
This feature enables the possibility to force a volume to detach, and
roll back an unsuccessful detach operation after you disconnect the volume.

View File

@ -14,7 +14,12 @@
# under the License. # under the License.
from tempest.api.volume import base from tempest.api.volume import base
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators from tempest.lib import decorators
from tempest import test
CONF = config.CONF
class VolumesActionsTest(base.BaseVolumeAdminTest): class VolumesActionsTest(base.BaseVolumeAdminTest):
@ -60,3 +65,36 @@ class VolumesActionsTest(base.BaseVolumeAdminTest):
def test_volume_force_delete_when_volume_is_maintenance(self): def test_volume_force_delete_when_volume_is_maintenance(self):
# test force delete when status of volume is maintenance # test force delete when status of volume is maintenance
self._create_reset_and_force_delete_temp_volume('maintenance') self._create_reset_and_force_delete_temp_volume('maintenance')
@decorators.idempotent_id('d38285d9-929d-478f-96a5-00e66a115b81')
@test.services('compute')
def test_force_detach_volume(self):
# Create a server and a volume
server_id = self.create_server(wait_until='ACTIVE')['id']
volume_id = self.create_volume()['id']
# Attach volume
self.volumes_client.attach_volume(
volume_id,
instance_uuid=server_id,
mountpoint='/dev/%s' % CONF.compute.volume_device_name)
waiters.wait_for_volume_resource_status(self.volumes_client,
volume_id, 'in-use')
self.addCleanup(waiters.wait_for_volume_resource_status,
self.volumes_client, volume_id, 'available')
self.addCleanup(self.volumes_client.detach_volume, volume_id)
attachment = self.volumes_client.show_volume(
volume_id)['volume']['attachments'][0]
# Reset volume's status to error
self.admin_volume_client.reset_volume_status(volume_id, status='error')
# Force detach volume
self.admin_volume_client.force_detach_volume(
volume_id, connector=None,
attachment_id=attachment['attachment_id'])
waiters.wait_for_volume_resource_status(self.volumes_client,
volume_id, 'available')
vol_info = self.volumes_client.show_volume(volume_id)['volume']
self.assertIn('attachments', vol_info)
self.assertEmpty(vol_info['attachments'])

View File

@ -286,6 +286,19 @@ class VolumesClient(rest_client.RestClient):
resp, body = self.post('volumes/%s/action' % volume_id, post_body) resp, body = self.post('volumes/%s/action' % volume_id, post_body)
self.expected_success(202, resp.status) self.expected_success(202, resp.status)
def force_detach_volume(self, volume_id, **kwargs):
"""Force detach a volume.
For a full list of available parameters, please refer to the official
API reference:
https://developer.openstack.org/api-ref/block-storage/v2/#force-detach-volume
"""
post_body = json.dumps({'os-force_detach': kwargs})
url = 'volumes/%s/action' % volume_id
resp, body = self.post(url, post_body)
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
def update_volume_image_metadata(self, volume_id, **kwargs): def update_volume_image_metadata(self, volume_id, **kwargs):
"""Update image metadata for the volume. """Update image metadata for the volume.

View File

@ -0,0 +1,52 @@
# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib.services.volume.v2 import volumes_client
from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib.services import base
class TestVolumesClient(base.BaseServiceTest):
def setUp(self):
super(TestVolumesClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = volumes_client.VolumesClient(fake_auth,
'volume',
'regionOne')
def _test_force_detach_volume(self, bytes_body=False):
kwargs = {
'attachment_id': '6980e295-920f-412e-b189-05c50d605acd',
'connector': {
'initiator': 'iqn.2017-04.org.fake:01'
}
}
self.check_service_client_function(
self.client.force_detach_volume,
'tempest.lib.common.rest_client.RestClient.post',
{},
to_utf=bytes_body,
status=202,
volume_id="a3be971b-8de5-4bdf-bdb8-3d8eb0fb69f8",
**kwargs
)
def test_force_detach_volume_with_str_body(self):
self._test_force_detach_volume()
def test_force_detach_volume_with_bytes_body(self):
self._test_force_detach_volume(bytes_body=True)