Add tempest tests for shared zones
This patch adds API and scenario test coverage for the shard zones feature. Author: Igor Malinovskiy <u.glide@gmail.com> Co-Authored-By: Sergey Drozdov <sergey.drozdov.dev@gmail.com, sergey.drozdov93@thehutgroup.com> Co-Authored-By: Michael Johnson <johnsomor@gmail.com> Change-Id: I53a1e4676c5bbb63bee0c4bb91eac03c95dd3a3c Partial-Bug: #1714088 Depends-On: https://review.opendev.org/726334changes/70/730370/17
parent
73065cdaca
commit
a84e3194ad
|
@ -19,6 +19,7 @@ from .json.ptr_client import PtrClient
|
|||
from .json.quotas_client import QuotasClient
|
||||
from .json.recordset_client import RecordsetClient
|
||||
from .json.service_client import ServiceClient
|
||||
from .json.shared_zones_client import SharedZonesClient
|
||||
from .json.tld_client import TldClient
|
||||
from .json.transfer_accepts_client import TransferAcceptClient
|
||||
from .json.transfer_request_client import TransferRequestClient
|
||||
|
@ -30,6 +31,6 @@ from .json.api_version_client import ApiVersionClient
|
|||
|
||||
__all__ = ['BlacklistsClient', 'DesignateLimitClient', 'PoolClient',
|
||||
'PtrClient', 'QuotasClient', 'RecordsetClient', 'ServiceClient',
|
||||
'TldClient', 'TransferAcceptClient', 'TransferRequestClient',
|
||||
'TsigkeyClient', 'ZonesClient', 'ZoneExportsClient',
|
||||
'ZoneImportsClient', 'ApiVersionClient']
|
||||
'SharedZonesClient', 'TldClient', 'TransferAcceptClient',
|
||||
'TransferRequestClient', 'TsigkeyClient', 'ZonesClient',
|
||||
'ZoneExportsClient', 'ZoneImportsClient', 'ApiVersionClient']
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
# Copyright 2020 Cloudification GmbH. 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 designate_tempest_plugin.services.dns.v2.json import base
|
||||
|
||||
|
||||
class SharedZonesClient(base.DnsClientV2Base):
|
||||
|
||||
@base.handle_errors
|
||||
def create_zone_share(self, zone_id, target_project_id):
|
||||
"""Create a new zone share for a project ID.
|
||||
|
||||
:param zone_id: Zone UUID to share
|
||||
:param target_project_id: Project ID that will gain access to specified
|
||||
zone
|
||||
:return: Zone share dict
|
||||
"""
|
||||
resp, body = self._create_request(
|
||||
'zones/{}/shares'.format(zone_id),
|
||||
data={'target_project_id': target_project_id})
|
||||
|
||||
# Endpoint should Return a HTTP 201
|
||||
self.expected_success(201, resp.status)
|
||||
|
||||
return resp, body
|
||||
|
||||
@base.handle_errors
|
||||
def show_zone_share(self, zone_id, zone_share_id):
|
||||
"""Get the zone share object
|
||||
|
||||
:param zone_id: Zone UUID for the share
|
||||
:param zone_share_id: The zone share ID
|
||||
:return: Zone share dict
|
||||
"""
|
||||
return self._show_request('zones/{}/shares'.format(zone_id),
|
||||
zone_share_id)
|
||||
|
||||
@base.handle_errors
|
||||
def list_zone_shares(self, zone_id, params=None, headers=None):
|
||||
"""List zone shares
|
||||
|
||||
:param zone_id: Zone UUID to query for the shares
|
||||
:param params: A Python dict that represents the query parameters to
|
||||
include in the request URI.
|
||||
:return: Zone shares list.
|
||||
"""
|
||||
return self._list_request('zones/{}/shares'.format(zone_id),
|
||||
params=params, headers=headers)
|
||||
|
||||
@base.handle_errors
|
||||
def delete_zone_share(self, zone_id, zone_share_id):
|
||||
"""Deletes the zone share
|
||||
|
||||
:param zone_id: Zone UUID for the share
|
||||
:param zone_share_id: The zone share ID
|
||||
:return: None
|
||||
"""
|
||||
resp, body = self._delete_request('zones/{}/shares'.format(zone_id),
|
||||
zone_share_id)
|
||||
|
||||
# Endpoint should Return a HTTP 204 - No Content
|
||||
self.expected_success(204, resp.status)
|
||||
|
||||
return resp, body
|
|
@ -0,0 +1,282 @@
|
|||
# Copyright 2020 Cloudification GmbH. 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 oslo_log import log as logging
|
||||
from oslo_utils import uuidutils
|
||||
from oslo_utils import versionutils
|
||||
from tempest import config
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
|
||||
from designate_tempest_plugin.tests import base
|
||||
from designate_tempest_plugin import data_utils as dns_data_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class BaseSharedZoneTest(base.BaseDnsV2Test):
|
||||
|
||||
credentials = ['admin', 'system_admin', 'system_reader', 'primary', 'alt',
|
||||
'project_reader', 'project_member', ['demo', 'member']]
|
||||
|
||||
excluded_keys = ['links']
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(BaseSharedZoneTest, cls).resource_setup()
|
||||
|
||||
if not versionutils.is_compatible('2.1', cls.api_version,
|
||||
same_major=False):
|
||||
raise cls.skipException(
|
||||
'The shared zones API tests require Designate API version '
|
||||
'2.1 or newer. Skipping Shared Zones API tests.')
|
||||
|
||||
# Make sure we have an allowed TLD available
|
||||
tld_name = dns_data_utils.rand_zone_name(name="APISharedZoneTest")
|
||||
cls.tld_name = f".{tld_name}"
|
||||
cls.class_tld = cls.admin_tld_client.create_tld(tld_name=tld_name[:-1])
|
||||
|
||||
# All the shared zone tests need a zone, create one to share
|
||||
zone_name = dns_data_utils.rand_zone_name(name="TestZone",
|
||||
suffix=cls.tld_name)
|
||||
LOG.info('Create a zone: %s', zone_name)
|
||||
cls.zone = cls.zones_client.create_zone(name=zone_name)[1]
|
||||
|
||||
@classmethod
|
||||
def resource_cleanup(cls):
|
||||
cls.zones_client.delete_zone(
|
||||
cls.zone['id'], ignore_errors=lib_exc.NotFound)
|
||||
cls.admin_tld_client.delete_tld(cls.class_tld[1]['id'])
|
||||
super(BaseSharedZoneTest, cls).resource_cleanup()
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(BaseSharedZoneTest, cls).setup_clients()
|
||||
|
||||
if CONF.enforce_scope.designate:
|
||||
cls.admin_tld_client = cls.os_system_admin.dns_v2.TldClient()
|
||||
else:
|
||||
cls.admin_tld_client = cls.os_admin.dns_v2.TldClient()
|
||||
cls.alt_zone_client = cls.os_alt.dns_v2.ZonesClient()
|
||||
cls.demo_zone_client = cls.os_demo.dns_v2.ZonesClient()
|
||||
cls.share_zone_client = cls.os_primary.dns_v2.SharedZonesClient()
|
||||
cls.alt_share_zone_client = cls.os_alt.dns_v2.SharedZonesClient()
|
||||
|
||||
|
||||
class SharedZonesTest(BaseSharedZoneTest):
|
||||
|
||||
@classmethod
|
||||
def setup_credentials(cls):
|
||||
# Do not create network resources for these test.
|
||||
cls.set_network_resources()
|
||||
super(SharedZonesTest, cls).setup_credentials()
|
||||
|
||||
@decorators.idempotent_id('982a7780-a460-4c13-97df-b4855bf19c7b')
|
||||
def test_create_zone_share(self):
|
||||
# Test RBAC
|
||||
expected_allowed = ['os_admin', 'os_primary', 'os_alt']
|
||||
if CONF.dns_feature_enabled.enforce_new_defaults:
|
||||
expected_allowed.append('os_system_admin')
|
||||
expected_allowed.append('os_project_member')
|
||||
self.check_CUD_RBAC_enforcement(
|
||||
'SharedZonesClient', 'create_zone_share', expected_allowed, True,
|
||||
self.zone['id'], self.alt_zone_client.project_id)
|
||||
|
||||
# Test a basic API create a zone share
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
self.assertTrue(uuidutils.is_uuid_like(shared_zone['id']))
|
||||
self.assertEqual(self.zone['id'], shared_zone['zone_id'])
|
||||
self.assertEqual(self.share_zone_client.project_id,
|
||||
shared_zone['project_id'])
|
||||
self.assertEqual(self.alt_zone_client.project_id,
|
||||
shared_zone['target_project_id'])
|
||||
self.assertIsNotNone(shared_zone['created_at'])
|
||||
self.assertIsNone(shared_zone['updated_at'])
|
||||
self.assertIsNotNone(shared_zone['links'])
|
||||
|
||||
@decorators.idempotent_id('0edecb9b-4890-433c-8195-0935271efc9a')
|
||||
def test_show_shared_zone(self):
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
# Test RBAC
|
||||
expected_allowed = ['os_admin', 'os_primary', 'os_alt']
|
||||
if CONF.dns_feature_enabled.enforce_new_defaults:
|
||||
expected_allowed.append('os_system_admin')
|
||||
expected_allowed.append('os_system_reader')
|
||||
expected_allowed.append('os_project_member')
|
||||
expected_allowed.append('os_project_reader')
|
||||
self.check_CUD_RBAC_enforcement(
|
||||
'SharedZonesClient', 'show_zone_share', expected_allowed, True,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
# Test show zone share
|
||||
LOG.info('Fetch the zone share')
|
||||
body = self.share_zone_client.show_zone_share(self.zone['id'],
|
||||
shared_zone['id'])[1]
|
||||
|
||||
LOG.info('Ensure the fetched response matches the zone share')
|
||||
self.assertExpected(shared_zone, body, self.excluded_keys)
|
||||
|
||||
@decorators.idempotent_id('a18a8577-9d02-492a-a869-4ff7d6f4f89b')
|
||||
def test_delete_zone_share(self):
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'],
|
||||
ignore_errors=lib_exc.NotFound)
|
||||
|
||||
# Test RBAC
|
||||
expected_allowed = ['os_admin', 'os_primary']
|
||||
if CONF.dns_feature_enabled.enforce_new_defaults:
|
||||
expected_allowed.append('os_system_admin')
|
||||
expected_allowed.append('os_project_member')
|
||||
self.check_CUD_RBAC_enforcement(
|
||||
'SharedZonesClient', 'delete_zone_share', expected_allowed, True,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
# Test zone share delete
|
||||
LOG.info('Delete zone share')
|
||||
self.share_zone_client.delete_zone_share(self.zone['id'],
|
||||
shared_zone['id'])
|
||||
|
||||
LOG.info('Ensure the zone share was deleted')
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.share_zone_client.show_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
@decorators.idempotent_id('707bfa4f-f15b-4486-ba5c-0e5991f0f3a5')
|
||||
def test_list_zone_shares(self):
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
# Test RBAC
|
||||
expected_allowed = ['os_admin', 'os_primary', 'os_alt']
|
||||
if CONF.dns_feature_enabled.enforce_new_defaults:
|
||||
expected_allowed.append('os_system_admin')
|
||||
expected_allowed.append('os_system_reader')
|
||||
expected_allowed.append('os_project_member')
|
||||
expected_allowed.append('os_project_reader')
|
||||
self.check_CUD_RBAC_enforcement(
|
||||
'SharedZonesClient', 'list_zone_shares', expected_allowed, True,
|
||||
self.zone['id'])
|
||||
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.demo_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
LOG.info('List zone shares')
|
||||
body = self.share_zone_client.list_zone_shares(self.zone['id'])[1]
|
||||
|
||||
self.assertEqual(2, len(body['shared_zones']))
|
||||
targets = []
|
||||
for share in body['shared_zones']:
|
||||
targets.append(share['target_project_id'])
|
||||
self.assertIn(self.alt_zone_client.project_id, targets)
|
||||
self.assertIn(self.demo_zone_client.project_id, targets)
|
||||
|
||||
|
||||
class NegativeSharedZonesTest(BaseSharedZoneTest):
|
||||
|
||||
@classmethod
|
||||
def setup_credentials(cls):
|
||||
# Do not create network resources for these test.
|
||||
cls.set_network_resources()
|
||||
super(NegativeSharedZonesTest, cls).setup_credentials()
|
||||
|
||||
@decorators.idempotent_id('4389a12b-8609-493c-9640-d3c67b625022')
|
||||
def test_target_project_cannot_delete_zone(self):
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
LOG.info('Ensure target project cannot delete zone')
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.alt_zone_client.delete_zone,
|
||||
self.zone['id'])
|
||||
|
||||
@decorators.idempotent_id('5c5e8551-1398-447d-a490-9cf1b16de129')
|
||||
def test_target_project_cannot_show_zone(self):
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
LOG.info('Ensure target project cannot show zone')
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.alt_zone_client.show_zone,
|
||||
self.zone['id'])
|
||||
|
||||
@decorators.idempotent_id('ab9bf257-ea5d-4362-973e-767055a316dd')
|
||||
def test_target_project_cannot_list_zone(self):
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
LOG.info('Ensure target project cannot see the zone in list zones')
|
||||
body = self.alt_zone_client.list_zones()[1]
|
||||
self.assertEqual([], body['zones'])
|
||||
|
||||
@decorators.idempotent_id('f4354b5c-8dbb-4bb9-8025-f65f8f2b21fb')
|
||||
def test_target_project_cannot_update_zone(self):
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
LOG.info('Ensure target project cannot update the zone')
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.alt_zone_client.update_zone,
|
||||
self.zone['id'], ttl=5)
|
||||
|
||||
@decorators.idempotent_id('4389a12b-8609-493c-9640-d3c67b625022')
|
||||
def test_target_project_share_permissions(self):
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
LOG.info('Ensure target project cannot share shared zone')
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.alt_share_zone_client.create_zone_share,
|
||||
self.zone['id'],
|
||||
self.demo_zone_client.project_id)
|
||||
|
||||
@decorators.idempotent_id('abc0f820-ae27-4e85-8f00-0b8e8abf3ae9')
|
||||
def test_target_project_cannot_subzone(self):
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
self.zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
self.zone['id'], shared_zone['id'])
|
||||
|
||||
LOG.info('Ensure target project cannot create sub-zones')
|
||||
sub_zone_name = "test.{}".format(self.zone['name'])
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.alt_zone_client.create_zone,
|
||||
name=sub_zone_name)
|
|
@ -13,6 +13,7 @@
|
|||
# under the License.
|
||||
import uuid
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import versionutils
|
||||
from tempest import config
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib.common.utils import data_utils
|
||||
|
@ -20,7 +21,6 @@ from tempest.lib import exceptions as lib_exc
|
|||
|
||||
|
||||
from designate_tempest_plugin.common import constants as const
|
||||
|
||||
from designate_tempest_plugin import data_utils as dns_data_utils
|
||||
from designate_tempest_plugin.tests import base
|
||||
|
||||
|
@ -72,6 +72,8 @@ class ZonesTest(BaseZonesTest):
|
|||
else:
|
||||
cls.pool_client = cls.os_admin.dns_v2.PoolClient()
|
||||
cls.recordset_client = cls.os_primary.dns_v2.RecordsetClient()
|
||||
cls.alt_zone_client = cls.os_alt.dns_v2.ZonesClient()
|
||||
cls.share_zone_client = cls.os_primary.dns_v2.SharedZonesClient()
|
||||
|
||||
@decorators.idempotent_id('9d2e20fc-e56f-4a62-9c61-9752a9ec615c')
|
||||
def test_create_zones(self):
|
||||
|
@ -218,6 +220,49 @@ class ZonesTest(BaseZonesTest):
|
|||
self.assertEqual(const.DELETE, body['action'])
|
||||
self.assertEqual(const.PENDING, body['status'])
|
||||
|
||||
@decorators.idempotent_id('bf2ee5c1-67b5-47dc-9902-ddb5b0e03e37')
|
||||
def test_delete_zone_with_shares(self):
|
||||
|
||||
if not versionutils.is_compatible('2.1', self.api_version,
|
||||
same_major=False):
|
||||
raise self.skipException(
|
||||
'Zone share tests require Designate API version 2.1 or newer. '
|
||||
'Skipping test_delete_zone_with_shares test.')
|
||||
|
||||
LOG.info('Create a zone')
|
||||
zone_name = dns_data_utils.rand_zone_name(
|
||||
name="delete_zones_with_shares", suffix=self.tld_name)
|
||||
zone = self.zones_client.create_zone(name=zone_name)[1]
|
||||
self.addCleanup(self.wait_zone_delete, self.zones_client, zone['id'],
|
||||
ignore_errors=lib_exc.NotFound)
|
||||
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
zone['id'], self.alt_zone_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
zone['id'], shared_zone['id'],
|
||||
ignore_errors=lib_exc.NotFound)
|
||||
|
||||
LOG.info('Attempt to delete the zone with shares')
|
||||
self.assertRaises(lib_exc.BadRequest, self.zones_client.delete_zone,
|
||||
zone['id'])
|
||||
|
||||
LOG.info('Make sure the zone share is still present')
|
||||
check_share = self.share_zone_client.show_zone_share(
|
||||
zone['id'], shared_zone['id'])[1]
|
||||
self.assertEqual(shared_zone['id'], check_share['id'])
|
||||
|
||||
LOG.info('Delete the zone using delete-shares')
|
||||
body = self.zones_client.delete_zone(
|
||||
zone['id'], headers={'x-designate-delete-shares': True})[1]
|
||||
|
||||
LOG.info('Ensure we respond with DELETE+PENDING')
|
||||
self.assertEqual(const.DELETE, body['action'])
|
||||
self.assertEqual(const.PENDING, body['status'])
|
||||
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.share_zone_client.show_zone_share,
|
||||
zone['id'], shared_zone['id'])
|
||||
|
||||
@decorators.idempotent_id('5bfa3cfe-5bc8-443b-bf48-cfba44cbb247')
|
||||
def test_list_zones(self):
|
||||
LOG.info('Create a zone')
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
# Copyright 2023 Red Hat
|
||||
#
|
||||
# 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 oslo_log import log as logging
|
||||
from oslo_utils import versionutils
|
||||
from tempest import config
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
|
||||
from designate_tempest_plugin import data_utils as dns_data_utils
|
||||
from designate_tempest_plugin.tests import base
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SharedZonesTest(base.BaseDnsV2Test):
|
||||
credentials = ['primary', 'admin', 'system_admin', 'alt',
|
||||
['demo', 'member']]
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(SharedZonesTest, cls).setup_clients()
|
||||
if CONF.enforce_scope.designate:
|
||||
cls.admin_tld_client = cls.os_system_admin.dns_v2.TldClient()
|
||||
else:
|
||||
cls.admin_tld_client = cls.os_admin.dns_v2.TldClient()
|
||||
cls.share_zone_client = cls.os_primary.dns_v2.SharedZonesClient()
|
||||
cls.rec_client = cls.os_primary.dns_v2.RecordsetClient()
|
||||
cls.alt_rec_client = cls.os_alt.dns_v2.RecordsetClient()
|
||||
cls.demo_rec_client = cls.os_demo.dns_v2.RecordsetClient()
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharedZonesTest, cls).resource_setup()
|
||||
|
||||
if not versionutils.is_compatible('2.1', cls.api_version,
|
||||
same_major=False):
|
||||
raise cls.skipException(
|
||||
'The shared zones scenario tests require Designate API '
|
||||
'version 2.1 or newer. Skipping Shared Zones scenario tests.')
|
||||
|
||||
# Make sure we have an allowed TLD available
|
||||
tld_name = dns_data_utils.rand_zone_name(name='SharedZonesTest')
|
||||
cls.tld_name = f'.{tld_name}'
|
||||
cls.class_tld = cls.admin_tld_client.create_tld(tld_name=tld_name[:-1])
|
||||
|
||||
@classmethod
|
||||
def resource_cleanup(cls):
|
||||
cls.admin_tld_client.delete_tld(cls.class_tld[1]['id'])
|
||||
super(SharedZonesTest, cls).resource_cleanup()
|
||||
|
||||
@decorators.attr(type='slow')
|
||||
@decorators.idempotent_id('b0fad45d-25ec-49b9-89a8-10b0e3c8b14c')
|
||||
def test_zone_share_CRUD_recordset(self):
|
||||
# Create a zone to share with the alt credential
|
||||
zone_name = dns_data_utils.rand_zone_name(name='TestZone',
|
||||
suffix=self.tld_name)
|
||||
LOG.info('Create a zone: %s', zone_name)
|
||||
zone = self.zones_client.create_zone(name=zone_name)[1]
|
||||
self.addCleanup(self.wait_zone_delete, self.zones_client, zone['id'],
|
||||
ignore_errors=lib_exc.NotFound)
|
||||
|
||||
recordset_data = dns_data_utils.rand_recordset_data(
|
||||
record_type='A', zone_name=zone['name'])
|
||||
|
||||
# Check that the alt user has no access to the zone before the share
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.alt_rec_client.create_recordset,
|
||||
zone['id'], recordset_data)
|
||||
|
||||
# Check that the demo user has no access to the zone before the share
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.demo_rec_client.create_recordset,
|
||||
zone['id'], recordset_data)
|
||||
|
||||
# Share the zone with the alt credential
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
zone['id'], self.alt_rec_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
zone['id'], shared_zone['id'])
|
||||
|
||||
# Check that the demo user has no access to the zone after the share
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.demo_rec_client.create_recordset,
|
||||
zone['id'], recordset_data)
|
||||
|
||||
# Check that the alt user can create a recordset on the shared zone
|
||||
recordset = self.alt_rec_client.create_recordset(zone['id'],
|
||||
recordset_data)[1]
|
||||
self.addCleanup(self.wait_recordset_delete, self.alt_rec_client,
|
||||
zone['id'], recordset['id'], ignore_errors=lib_exc.NotFound)
|
||||
|
||||
# Check that the demo user cannot see the alt recordset
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.demo_rec_client.show_recordset,
|
||||
zone['id'], recordset['id'])
|
||||
|
||||
# Check that the alt user can see the alt recordset
|
||||
show_recordset = self.alt_rec_client.show_recordset(
|
||||
zone['id'], recordset['id'])[1]
|
||||
|
||||
self.assertEqual(recordset['id'], show_recordset['id'])
|
||||
|
||||
# Check that the zone owner can see the alt recordset
|
||||
show_recordset = self.rec_client.show_recordset(zone['id'],
|
||||
recordset['id'])[1]
|
||||
|
||||
self.assertEqual(recordset['id'], show_recordset['id'])
|
||||
|
||||
recordset_data = {
|
||||
'ttl': dns_data_utils.rand_ttl(start=recordset['ttl'] + 1)
|
||||
}
|
||||
|
||||
# Check that the demo user cannot update the recordset created by alt
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.demo_rec_client.update_recordset,
|
||||
zone['id'], recordset['id'], recordset_data)
|
||||
|
||||
# Check that the alt user can update a recordset on the shared zone
|
||||
update = self.alt_rec_client.update_recordset(zone['id'],
|
||||
recordset['id'], recordset_data)[1]
|
||||
|
||||
self.assertNotEqual(recordset['ttl'], update['ttl'])
|
||||
|
||||
recordset_data = {
|
||||
'ttl': dns_data_utils.rand_ttl(start=update['ttl'] + 1)
|
||||
}
|
||||
|
||||
# Check that the zone owner can update a recordset on the shared zone
|
||||
primary_update = self.rec_client.update_recordset(zone['id'],
|
||||
recordset['id'], recordset_data)[1]
|
||||
|
||||
self.assertNotEqual(update['ttl'], primary_update['ttl'])
|
||||
|
||||
# Check that the demo user cannot delete the alt recordset
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.demo_rec_client.delete_recordset,
|
||||
zone['id'], recordset['id'])
|
||||
|
||||
# Check that the alt user can delete it's recordset
|
||||
self.alt_rec_client.delete_recordset(zone['id'], recordset['id'])
|
||||
|
||||
LOG.info('Ensure successful deletion of Recordset')
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.alt_rec_client.show_recordset,
|
||||
zone['id'], recordset['id'])
|
||||
|
||||
@decorators.attr(type='slow')
|
||||
@decorators.idempotent_id('de03b4d3-3ccf-4291-a920-89e2694bba22')
|
||||
def test_zone_owner_can_delete_shared_recordset(self):
|
||||
# Create a zone to share with the alt credential
|
||||
zone_name = dns_data_utils.rand_zone_name(name='TestZone',
|
||||
suffix=self.tld_name)
|
||||
LOG.info('Create a zone: %s', zone_name)
|
||||
zone = self.zones_client.create_zone(name=zone_name)[1]
|
||||
self.addCleanup(self.wait_zone_delete, self.zones_client, zone['id'],
|
||||
ignore_errors=lib_exc.NotFound)
|
||||
|
||||
recordset_data = dns_data_utils.rand_recordset_data(
|
||||
record_type='A', zone_name=zone['name'])
|
||||
|
||||
# Share the zone with the alt credential
|
||||
shared_zone = self.share_zone_client.create_zone_share(
|
||||
zone['id'], self.alt_rec_client.project_id)[1]
|
||||
self.addCleanup(self.share_zone_client.delete_zone_share,
|
||||
zone['id'], shared_zone['id'])
|
||||
|
||||
# Check that the alt user can create a recordset on the shared zone
|
||||
recordset = self.alt_rec_client.create_recordset(zone['id'],
|
||||
recordset_data)[1]
|
||||
self.addCleanup(self.wait_recordset_delete, self.alt_rec_client,
|
||||
zone['id'], recordset['id'], ignore_errors=lib_exc.NotFound)
|
||||
|
||||
# Check that the alt user can see the alt recordset
|
||||
show_recordset = self.alt_rec_client.show_recordset(
|
||||
zone['id'], recordset['id'])[1]
|
||||
|
||||
self.assertEqual(recordset['id'], show_recordset['id'])
|
||||
|
||||
# Check that the zone owner can delete the recordset
|
||||
self.rec_client.delete_recordset(zone['id'], recordset['id'])
|
||||
|
||||
LOG.info('Ensure successful deletion of Recordset')
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.alt_rec_client.show_recordset,
|
||||
zone['id'], recordset['id'])
|
|
@ -5,5 +5,6 @@
|
|||
dnspython>=1.16.0 # http://www.dnspython.org/LICENSE
|
||||
ddt>=1.0.1 # MIT
|
||||
oslo.serialization>=2.25.0 # Apache-2.0
|
||||
oslo.utils>=3.33.0 # Apache-2.0
|
||||
testtools>=2.2.0 # MIT
|
||||
tempest>=17.1.0 # Apache-2.0
|
||||
|
|
Loading…
Reference in New Issue