Merge "Migrate tempest jobs to focal"
diff --git a/releasenotes/notes/add-keystone-ep-clients-eeefd0904fbbe151.yaml b/releasenotes/notes/add-keystone-ep-clients-eeefd0904fbbe151.yaml
new file mode 100644
index 0000000..2b407ae
--- /dev/null
+++ b/releasenotes/notes/add-keystone-ep-clients-eeefd0904fbbe151.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Added missing client methods for keystone's OS-ENDPOINT-POLICY and
+ OS-EP-FILTER APIs.
diff --git a/releasenotes/notes/tempest-victoria-release-27000c02edc5a112.yaml b/releasenotes/notes/tempest-victoria-release-27000c02edc5a112.yaml
new file mode 100644
index 0000000..bb91213
--- /dev/null
+++ b/releasenotes/notes/tempest-victoria-release-27000c02edc5a112.yaml
@@ -0,0 +1,16 @@
+prelude: |
+ This release is to tag the Tempest for OpenStack Victoria release.
+ This release marks the start of Victoria release support in Tempest.
+ After this release, Tempest will support below OpenStack Releases:
+
+ * Victoria
+ * Ussuri
+ * Train
+ * Stein
+
+ Current development of Tempest is for OpenStack Wallaby development
+ cycle. Every Tempest commit is also tested against master during
+ the Wallaby cycle. However, this does not necessarily mean that using
+ Tempest as of this tag will work against a Victoria (or future release)
+ cloud.
+ To be on safe side, use this tag to test the OpenStack Victoria release.
diff --git a/requirements.txt b/requirements.txt
index d8738f0..abc0bce 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,7 +5,7 @@
cliff!=2.9.0,>=2.8.0 # Apache-2.0
jsonschema>=3.2.0 # MIT
testtools>=2.2.0 # MIT
-paramiko>=2.0.0 # LGPLv2.1+
+paramiko>=2.7.0 # LGPLv2.1+
netaddr>=0.7.18 # BSD
oslo.concurrency>=3.26.0 # Apache-2.0
oslo.config>=5.2.0 # Apache-2.0
diff --git a/tempest/api/volume/admin/test_encrypted_volumes_extend.py b/tempest/api/volume/admin/test_encrypted_volumes_extend.py
new file mode 100644
index 0000000..7339179
--- /dev/null
+++ b/tempest/api/volume/admin/test_encrypted_volumes_extend.py
@@ -0,0 +1,35 @@
+# 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 testtools
+
+from tempest.api.volume import base
+from tempest.api.volume import test_volumes_extend as extend
+from tempest.common import utils
+from tempest import config
+from tempest.lib import decorators
+
+CONF = config.CONF
+
+
+class EncryptedVolumesExtendAttachedTest(extend.BaseVolumesExtendAttachedTest,
+ base.BaseVolumeAdminTest):
+ """Tests extending the size of an attached encrypted volume."""
+
+ @decorators.idempotent_id('e93243ec-7c37-4b5b-a099-ebf052c13216')
+ @testtools.skipUnless(
+ CONF.volume_feature_enabled.extend_attached_encrypted_volume,
+ "Attached encrypted volume extend is disabled.")
+ @utils.services('compute')
+ def test_extend_attached_encrypted_volume_luksv1(self):
+ volume = self.create_encrypted_volume(encryption_provider="luks")
+ self._test_extend_attached_volume(volume)
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 7af5927..c538e60 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -302,6 +302,27 @@
cls.addClassResourceCleanup(cls.clear_volume_type, volume_type['id'])
return volume_type
+ def create_encryption_type(self, type_id=None, provider=None,
+ key_size=None, cipher=None,
+ control_location=None):
+ if not type_id:
+ volume_type = self.create_volume_type()
+ type_id = volume_type['id']
+ self.admin_encryption_types_client.create_encryption_type(
+ type_id, provider=provider, key_size=key_size, cipher=cipher,
+ control_location=control_location)
+
+ def create_encrypted_volume(self, encryption_provider, key_size=256,
+ cipher='aes-xts-plain64',
+ control_location='front-end'):
+ volume_type = self.create_volume_type()
+ self.create_encryption_type(type_id=volume_type['id'],
+ provider=encryption_provider,
+ key_size=key_size,
+ cipher=cipher,
+ control_location=control_location)
+ return self.create_volume(volume_type=volume_type['name'])
+
def create_group_type(self, name=None, **kwargs):
"""Create a test group-type"""
name = name or data_utils.rand_name(
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index 041823d..7441f1d 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -61,7 +61,7 @@
self.assertEqual(extend_size, resized_volume['size'])
-class VolumesExtendAttachedTest(base.BaseVolumeTest):
+class BaseVolumesExtendAttachedTest(base.BaseVolumeTest):
"""Tests extending the size of an attached volume."""
create_default_network = True
@@ -100,14 +100,9 @@
event['finish_time']):
return event
- @decorators.idempotent_id('301f5a30-1c6f-4ea0-be1a-91fd28d44354')
- @testtools.skipUnless(CONF.volume_feature_enabled.extend_attached_volume,
- "Attached volume extend is disabled.")
- @utils.services('compute')
- def test_extend_attached_volume(self):
+ def _test_extend_attached_volume(self, volume):
"""This is a happy path test which does the following:
- * Create a volume at the configured volume_size.
* Create a server instance.
* Attach the volume to the server.
* Wait for the volume status to be "in-use".
@@ -119,8 +114,6 @@
if we timeout waiting for the instance action event to show up, or
if the action on the server fails.
"""
- # Create a test volume. Will be automatically cleaned up on teardown.
- volume = self.create_volume()
# Create a test server. Will be automatically cleaned up on teardown.
server = self.create_server()
# Attach the volume to the server and wait for the volume status to be
@@ -182,3 +175,14 @@
"%(request_id)s." %
{'result': event['result'],
'request_id': action['request_id']})
+
+
+class VolumesExtendAttachedTest(BaseVolumesExtendAttachedTest):
+
+ @decorators.idempotent_id('301f5a30-1c6f-4ea0-be1a-91fd28d44354')
+ @testtools.skipUnless(CONF.volume_feature_enabled.extend_attached_volume,
+ "Attached volume extend is disabled.")
+ @utils.services('compute')
+ def test_extend_attached_volume(self):
+ volume = self.create_volume()
+ self._test_extend_attached_volume(volume)
diff --git a/tempest/config.py b/tempest/config.py
index a632dee..36ad405 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1012,7 +1012,15 @@
'which is currently attached to a server instance? This '
'depends on the 3.42 volume API microversion and the '
'2.51 compute API microversion. Also, not all volume or '
- 'compute backends support this operation.')
+ 'compute backends support this operation.'),
+ cfg.BoolOpt('extend_attached_encrypted_volume',
+ default=False,
+ help='Does the cloud support extending the size of an '
+ 'encrypted volume which is currently attached to a '
+ 'server instance? This depends on the 3.42 volume API '
+ 'microversion and the 2.51 compute API microversion. '
+ 'Also, not all volume or compute backends support this '
+ 'operation.')
]
diff --git a/tempest/lib/services/identity/v3/endpoint_filter_client.py b/tempest/lib/services/identity/v3/endpoint_filter_client.py
index ce84869..2d5c8c9 100644
--- a/tempest/lib/services/identity/v3/endpoint_filter_client.py
+++ b/tempest/lib/services/identity/v3/endpoint_filter_client.py
@@ -66,3 +66,57 @@
% (project_id, endpoint_id))
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
+
+ def list_endpoint_groups_for_project(self, project_id):
+ """List Endpoint Groups Associated with Project."""
+ resp, body = self.get(
+ self.ep_filter + '/projects/%s/endpoint_groups'
+ % project_id)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_projects_for_endpoint_group(self, endpoint_group_id):
+ """List Projects Associated with Endpoint Group."""
+ resp, body = self.get(
+ self.ep_filter + '/endpoint_groups/%s/projects'
+ % endpoint_group_id)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_endpoints_for_endpoint_group(self, endpoint_group_id):
+ """List Endpoints Associated with Endpoint Group."""
+ resp, body = self.get(
+ self.ep_filter + '/endpoint_groups/%s/endpoints'
+ % endpoint_group_id)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def add_endpoint_group_to_project(self, endpoint_group_id, project_id):
+ """Create Endpoint Group to Project Association."""
+ body = None
+ resp, body = self.put(
+ self.ep_filter + '/endpoint_groups/%s/projects/%s'
+ % (endpoint_group_id, project_id), body)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def show_endpoint_group_for_project(self, endpoint_group_id, project_id):
+ """Get Endpoint Group to Project Association."""
+ resp, body = self.get(
+ self.ep_filter + '/endpoint_groups/%s/projects/%s'
+ % (endpoint_group_id, project_id))
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_endpoint_group_from_project(
+ self, endpoint_group_id, project_id):
+ """Delete Endpoint Group to Project Association."""
+ resp, body = self.delete(
+ self.ep_filter + '/endpoint_groups/%s/projects/%s'
+ % (endpoint_group_id, project_id))
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/identity/v3/policies_client.py b/tempest/lib/services/identity/v3/policies_client.py
index 31c0d18..41def38 100644
--- a/tempest/lib/services/identity/v3/policies_client.py
+++ b/tempest/lib/services/identity/v3/policies_client.py
@@ -185,3 +185,27 @@
resp, body = self.delete(url)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
+
+ def list_endpoints_for_policy(self, policy_id):
+ """List policy and service endpoint associations.
+
+ API reference:
+ https://docs.openstack.org/api-ref/identity/v3-ext/#list-policy-and-service-endpoint-associations
+ """
+ url = "policies/{0}/OS-ENDPOINT-POLICY/endpoints".format(policy_id)
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def show_policy_for_endpoint(self, endpoint_id):
+ """Show the effective policy associated with an endpoint
+
+ API reference:
+ https://docs.openstack.org/api-ref/identity/v3-ext/#show-the-effective-policy-associated-with-an-endpoint
+ """
+ url = "endpoints/{0}/OS-ENDPOINT-POLICY/policy".format(endpoint_id)
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py b/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py
index 7faf6a0..e5f7a66 100644
--- a/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py
@@ -83,6 +83,36 @@
}
}
+ FAKE_LIST_ENDPOINT_GROUPS_FOR_PROJECT = {
+ "endpoint_groups": [
+ {
+ "endpoint_group": {
+ "description": "endpoint group description #2",
+ "filters": {
+ "interface": "admin"
+ },
+ "id": "3de68c",
+ "name": "endpoint group name #2"
+ }
+ }
+ ],
+ "links": {
+ "self": "https://url/identity/v3/OS-EP-FILTER/endpoint_groups",
+ }
+ }
+
+ FAKE_PROJECT_INFO = {
+ "project": {
+ "domain_id": "1789d1",
+ "id": "263fd9",
+ "links": {
+ "self": "http://example.com/identity/v3/projects/263fd9"
+ },
+ "name": "project name #1",
+ "description": "project description #1"
+ }
+ }
+
def setUp(self):
super(TestEndPointsFilterClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -137,6 +167,52 @@
project_id=3,
endpoint_id=4)
+ def _test_list_endpoint_groups_for_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_endpoint_groups_for_project,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_ENDPOINT_GROUPS_FOR_PROJECT,
+ bytes_body,
+ status=200,
+ project_id=3)
+
+ def _test_list_projects_for_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_projects_for_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_PROJECTS_FOR_ENDPOINTS,
+ bytes_body,
+ status=200,
+ endpoint_group_id=5)
+
+ def _test_list_endpoints_for_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_endpoints_for_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_ENDPOINTS_FOR_PROJECTS,
+ bytes_body,
+ status=200,
+ endpoint_group_id=5)
+
+ def _test_add_endpoint_group_to_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.add_endpoint_group_to_project,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ {},
+ bytes_body,
+ status=204,
+ endpoint_group_id=5,
+ project_id=6)
+
+ def _test_show_endpoint_group_for_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_endpoint_group_for_project,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_PROJECT_INFO,
+ bytes_body,
+ endpoint_group_id=5,
+ project_id=6)
+
def test_add_endpoint_to_project_with_str_body(self):
self._test_add_endpoint_to_project()
@@ -163,3 +239,43 @@
def test_delete_endpoint_from_project(self):
self._test_delete_endpoint_from_project()
+
+ def test_list_endpoint_groups_for_project_with_str_body(self):
+ self._test_list_endpoint_groups_for_project()
+
+ def test_list_endpoint_groups_for_project_with_bytes_body(self):
+ self._test_list_endpoint_groups_for_project(bytes_body=True)
+
+ def test_list_projects_for_endpoint_group_with_str_body(self):
+ self._test_list_projects_for_endpoint_group()
+
+ def test_list_projects_for_endpoint_group_with_bytes_body(self):
+ self._test_list_projects_for_endpoint_group(bytes_body=True)
+
+ def test_list_endpoints_for_endpoint_group_with_str_body(self):
+ self._test_list_endpoints_for_endpoint_group()
+
+ def test_list_endpoints_for_endpoint_group_with_bytes_body(self):
+ self._test_list_endpoints_for_endpoint_group(bytes_body=True)
+
+ def test_add_endpoint_group_to_project_with_str_body(self):
+ self._test_add_endpoint_group_to_project()
+
+ def test_add_endpoint_group_to_project_with_bytes_body(self):
+ self._test_add_endpoint_group_to_project(bytes_body=True)
+
+ def test_show_endpoint_group_for_project_with_str_body(self):
+ self._test_show_endpoint_group_for_project()
+
+ def test_show_endpoint_group_for_project_with_bytes_body(self):
+ self._test_show_endpoint_group_for_project(bytes_body=True)
+
+ def test_delete_endpoint_group_from_project(self):
+ self.check_service_client_function(
+ self.client.delete_endpoint_group_from_project,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ False,
+ status=204,
+ endpoint_group_id=5,
+ project_id=5)
diff --git a/tempest/tests/lib/services/identity/v3/test_policies_client.py b/tempest/tests/lib/services/identity/v3/test_policies_client.py
index 0237475..4fc800a 100644
--- a/tempest/tests/lib/services/identity/v3/test_policies_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_policies_client.py
@@ -44,6 +44,34 @@
}
}
+ FAKE_ENDPOINT_INFO = {
+ "endpoints": [
+ {
+ "id": "1",
+ "interface": "public",
+ "links": {
+ "self": "http://example.com/identity/v3/endpoints/1"
+ },
+ "region": "north",
+ "service_id": "9242e05f0c23467bbd1cf1f7a6e5e596",
+ "url": "http://example.com/identity/"
+ },
+ {
+ "id": "1",
+ "interface": "internal",
+ "links": {
+ "self": "http://example.com/identity/v3/endpoints/1"
+ },
+ "region": "south",
+ "service_id": "9242e05f0c23467bbd1cf1f7a6e5e596",
+ "url": "http://example.com/identity/"
+ }
+ ],
+ "links": {
+ "self": "http://exmp.com/identity/v3/OS-ENDPOINT-POLICY/policies/1"
+ }
+ }
+
FAKE_LIST_POLICIES = {
"links": {
"next": None,
@@ -238,3 +266,33 @@
service_id=self.FAKE_SERVICE_ID,
region_id=self.FAKE_REGION_ID,
status=204)
+
+ def _test_list_endpoints_for_policy(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_endpoints_for_policy,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_ENDPOINT_INFO,
+ bytes_body,
+ policy_id=self.FAKE_POLICY_ID,
+ status=200)
+
+ def test_list_endpoints_for_policy_with_str_body(self):
+ self._test_list_endpoints_for_policy()
+
+ def test_list_endpoints_for_policy_with_bytes_body(self):
+ self._test_list_endpoints_for_policy(bytes_body=True)
+
+ def _test_list_policy_for_endpoint(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_policy_for_endpoint,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_POLICY_INFO,
+ bytes_body,
+ endpoint_id=self.FAKE_ENDPOINT_ID,
+ status=200)
+
+ def test_list_policy_for_endpoint_with_str_body(self):
+ self._test_list_policy_for_endpoint()
+
+ def test_list_policy_for_endpoint_with_bytes_body(self):
+ self._test_list_policy_for_endpoint(bytes_body=True)