Merge "Prepare the Manager class for tempest.lib"
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 5e1c20b..5615cf3 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -63,9 +63,8 @@
extra_specs = {spec_key_with_prefix: backend_name_key}
else:
extra_specs = {spec_key_without_prefix: backend_name_key}
- self.type = self.admin_volume_types_client.create_volume_type(
- name=type_name, extra_specs=extra_specs)['volume_type']
- self.volume_type_id_list.append(self.type['id'])
+ self.type = self.create_volume_type(name=type_name,
+ extra_specs=extra_specs)
params = {self.name_field: vol_name, 'volume_type': type_name}
@@ -92,11 +91,6 @@
cls.admin_volume_client.delete_volume(volume_id)
cls.admin_volume_client.wait_for_resource_deletion(volume_id)
- # volume types deletion
- volume_type_id_list = getattr(cls, 'volume_type_id_list', [])
- for volume_type_id in volume_type_id_list:
- cls.admin_volume_types_client.delete_volume_type(volume_type_id)
-
super(VolumeMultiBackendV2Test, cls).resource_cleanup()
@test.idempotent_id('c1a41f3f-9dad-493e-9f09-3ff197d477cc')
diff --git a/tempest/api/volume/admin/test_qos.py b/tempest/api/volume/admin/test_qos.py
index 68e57f5..9402668 100644
--- a/tempest/api/volume/admin/test_qos.py
+++ b/tempest/api/volume/admin/test_qos.py
@@ -50,14 +50,6 @@
list_qos = self.admin_volume_qos_client.list_qos()['qos_specs']
self.assertNotIn(body, list_qos)
- def _create_test_volume_type(self):
- vol_type_name = utils.rand_name("volume-type")
- vol_type = self.admin_volume_types_client.create_volume_type(
- name=vol_type_name)['volume_type']
- self.addCleanup(self.admin_volume_types_client.delete_volume_type,
- vol_type['id'])
- return vol_type
-
def _test_associate_qos(self, vol_type_id):
self.admin_volume_qos_client.associate_qos(
self.created_qos['id'], vol_type_id)
@@ -146,7 +138,7 @@
# create a test volume-type
vol_type = []
for _ in range(0, 3):
- vol_type.append(self._create_test_volume_type())
+ vol_type.append(self.create_volume_type())
# associate the qos-specs with volume-types
for i in range(0, 3):
diff --git a/tempest/api/volume/admin/test_volume_type_access.py b/tempest/api/volume/admin/test_volume_type_access.py
new file mode 100644
index 0000000..fac71a8
--- /dev/null
+++ b/tempest/api/volume/admin/test_volume_type_access.py
@@ -0,0 +1,94 @@
+# Copyright 2016 OpenStack Foundation
+# 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.
+
+import operator
+
+from tempest.api.volume import base
+from tempest.common import waiters
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+
+
+class VolumeTypesAccessV2Test(base.BaseVolumeAdminTest):
+
+ credentials = ['primary', 'alt', 'admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super(VolumeTypesAccessV2Test, cls).setup_clients()
+ cls.alt_client = cls.os_alt.volumes_client
+
+ @test.idempotent_id('d4dd0027-835f-4554-a6e5-50903fb79184')
+ def test_volume_type_access_add(self):
+ # Creating a NON public volume type
+ params = {'os-volume-type-access:is_public': False}
+ volume_type = self.create_volume_type(**params)
+
+ # Try creating a volume from volume type in primary tenant
+ self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
+ volume_type=volume_type['id'])
+
+ # Adding volume type access for primary tenant
+ self.admin_volume_types_client.add_type_access(
+ volume_type['id'], project=self.volumes_client.tenant_id)
+ self.addCleanup(self.admin_volume_types_client.remove_type_access,
+ volume_type['id'],
+ project=self.volumes_client.tenant_id)
+
+ # Creating a volume from primary tenant
+ volume = self.volumes_client.create_volume(
+ volume_type=volume_type['id'])['volume']
+ self.addCleanup(self.delete_volume, self.volumes_client, volume['id'])
+ waiters.wait_for_volume_status(self.volumes_client, volume['id'],
+ 'available')
+
+ # Validating the created volume is based on the volume type
+ self.assertEqual(volume_type['name'], volume['volume_type'])
+
+ @test.idempotent_id('5220eb28-a435-43ce-baaf-ed46f0e95159')
+ def test_volume_type_access_list(self):
+ # Creating a NON public volume type
+ params = {'os-volume-type-access:is_public': False}
+ volume_type = self.create_volume_type(**params)
+
+ # Adding volume type access for primary tenant
+ self.admin_volume_types_client.add_type_access(
+ volume_type['id'], project=self.volumes_client.tenant_id)
+ self.addCleanup(self.admin_volume_types_client.remove_type_access,
+ volume_type['id'],
+ project=self.volumes_client.tenant_id)
+
+ # Adding volume type access for alt tenant
+ self.admin_volume_types_client.add_type_access(
+ volume_type['id'], project=self.alt_client.tenant_id)
+ self.addCleanup(self.admin_volume_types_client.remove_type_access,
+ volume_type['id'],
+ project=self.alt_client.tenant_id)
+
+ # List tenant access for the given volume type
+ type_access_list = self.admin_volume_types_client.list_type_access(
+ volume_type['id'])['volume_type_access']
+ volume_type_ids = [
+ vol_type['volume_type_id'] for vol_type in type_access_list
+ ]
+
+ # Validating volume type available for only two tenants
+ self.assertEqual(2, volume_type_ids.count(volume_type['id']))
+
+ # Validating the permitted tenants are the expected tenants
+ self.assertIn(self.volumes_client.tenant_id,
+ map(operator.itemgetter('project_id'), type_access_list))
+ self.assertIn(self.alt_client.tenant_id,
+ map(operator.itemgetter('project_id'), type_access_list))
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 9023037..27f6ccb 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -44,12 +44,10 @@
# Create two volume_types
for i in range(2):
vol_type_name = data_utils.rand_name("volume-type")
- vol_type = self.admin_volume_types_client.create_volume_type(
+ vol_type = self.create_volume_type(
name=vol_type_name,
- extra_specs=extra_specs)['volume_type']
+ extra_specs=extra_specs)
volume_types.append(vol_type)
- self.addCleanup(self.admin_volume_types_client.delete_volume_type,
- vol_type['id'])
params = {self.name_field: vol_name,
'volume_type': volume_types[0]['id']}
@@ -94,12 +92,10 @@
vendor = CONF.volume.vendor_name
extra_specs = {"storage_protocol": proto,
"vendor_name": vendor}
- body = self.admin_volume_types_client.create_volume_type(
+ body = self.create_volume_type(
name=name,
- extra_specs=extra_specs)['volume_type']
+ extra_specs=extra_specs)
self.assertIn('id', body)
- self.addCleanup(self.admin_volume_types_client.delete_volume_type,
- body['id'])
self.assertIn('name', body)
self.assertEqual(body['name'], name,
"The created volume_type name is not equal "
@@ -124,11 +120,7 @@
provider = "LuksEncryptor"
control_location = "front-end"
name = data_utils.rand_name("volume-type")
- body = self.admin_volume_types_client.create_volume_type(
- name=name)['volume_type']
- self.addCleanup(self.admin_volume_types_client.delete_volume_type,
- body['id'])
-
+ body = self.create_volume_type(name=name)
# Create encryption type
encryption_type = \
self.admin_volume_types_client.create_encryption_type(
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py
index b5c5d15..9e49b94 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -24,14 +24,7 @@
def resource_setup(cls):
super(VolumeTypesExtraSpecsV2Test, cls).resource_setup()
vol_type_name = data_utils.rand_name('Volume-type')
- cls.volume_type = \
- cls.admin_volume_types_client.create_volume_type(
- name=vol_type_name)['volume_type']
-
- @classmethod
- def resource_cleanup(cls):
- cls.admin_volume_types_client.delete_volume_type(cls.volume_type['id'])
- super(VolumeTypesExtraSpecsV2Test, cls).resource_cleanup()
+ cls.volume_type = cls.create_volume_type(name=vol_type_name)
@test.idempotent_id('b42923e9-0452-4945-be5b-d362ae533e60')
def test_volume_type_extra_specs_list(self):
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
index c7c3e1a..2193aa6 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -26,14 +26,8 @@
super(ExtraSpecsNegativeV2Test, cls).resource_setup()
vol_type_name = data_utils.rand_name('Volume-type')
cls.extra_specs = {"spec1": "val1"}
- cls.volume_type = cls.admin_volume_types_client.create_volume_type(
- name=vol_type_name,
- extra_specs=cls.extra_specs)['volume_type']
-
- @classmethod
- def resource_cleanup(cls):
- cls.admin_volume_types_client.delete_volume_type(cls.volume_type['id'])
- super(ExtraSpecsNegativeV2Test, cls).resource_cleanup()
+ cls.volume_type = cls.create_volume_type(name=vol_type_name,
+ extra_specs=cls.extra_specs)
@test.idempotent_id('08961d20-5cbb-4910-ac0f-89ad6dbb2da1')
def test_update_no_body(self):
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 665036b..e9be529 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -214,11 +214,13 @@
super(BaseVolumeAdminTest, cls).resource_setup()
cls.qos_specs = []
+ cls.volume_types = []
@classmethod
def resource_cleanup(cls):
cls.clear_qos_specs()
super(BaseVolumeAdminTest, cls).resource_cleanup()
+ cls.clear_volume_types()
@classmethod
def create_test_qos_specs(cls, name=None, consumer=None, **kwargs):
@@ -231,6 +233,15 @@
return qos_specs
@classmethod
+ def create_volume_type(cls, name=None, **kwargs):
+ """Create a test volume-type"""
+ name = name or data_utils.rand_name('volume-type')
+ volume_type = cls.admin_volume_types_client.create_volume_type(
+ name=name, **kwargs)['volume_type']
+ cls.volume_types.append(volume_type['id'])
+ return volume_type
+
+ @classmethod
def clear_qos_specs(cls):
for qos_id in cls.qos_specs:
test_utils.call_and_ignore_notfound_exc(
@@ -239,3 +250,17 @@
for qos_id in cls.qos_specs:
test_utils.call_and_ignore_notfound_exc(
cls.admin_volume_qos_client.wait_for_resource_deletion, qos_id)
+
+ @classmethod
+ def clear_volume_types(cls):
+ for vol_type in cls.volume_types:
+ test_utils.call_and_ignore_notfound_exc(
+ cls.admin_volume_types_client.delete_volume_type, vol_type)
+
+ for vol_type in cls.volume_types:
+ # Resource dictionary uses for is_resource_deleted method,
+ # to distinguish between volume-type to encryption-type.
+ resource = {'id': vol_type, 'type': 'volume-type'}
+ test_utils.call_and_ignore_notfound_exc(
+ cls.admin_volume_types_client.wait_for_resource_deletion,
+ resource)
diff --git a/tempest/services/volume/base/admin/base_types_client.py b/tempest/services/volume/base/admin/base_types_client.py
index 95ddff6..e4d9014 100644
--- a/tempest/services/volume/base/admin/base_types_client.py
+++ b/tempest/services/volume/base/admin/base_types_client.py
@@ -179,3 +179,37 @@
"/types/%s/encryption/provider" % str(vol_type_id))
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
+
+ def add_type_access(self, volume_type_id, **kwargs):
+ """Adds volume type access for the given project.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html
+ #createVolumeTypeAccessExt
+ """
+ post_body = json.dumps({'addProjectAccess': kwargs})
+ url = 'types/%s/action' % (volume_type_id)
+ resp, body = self.post(url, post_body)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def remove_type_access(self, volume_type_id, **kwargs):
+ """Removes volume type access for the given project.
+
+ Available params: see http://developer.openstack.org/
+ api-ref-blockstorage-v2.html
+ #removeVolumeTypeAccessExt
+ """
+ post_body = json.dumps({'removeProjectAccess': kwargs})
+ url = 'types/%s/action' % (volume_type_id)
+ resp, body = self.post(url, post_body)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_type_access(self, volume_type_id):
+ """Print access information about the given volume type."""
+ url = 'types/%s/os-volume-type-access' % (volume_type_id)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/test-requirements.txt b/test-requirements.txt
index 763f0ba..a5b0d29 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,7 +1,7 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-hacking<0.11,>=0.10.0
+hacking<0.12,>=0.11.0 # Apache-2.0
# needed for doc build
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
python-subunit>=0.0.18 # Apache-2.0/BSD