Add designate-manage pool scenario tests
So far we did not test designate-manage pool commands with real end-user
scenarios.
This patch adds designate-manage pool scenario tests.
Change-Id: Iaf848350a502b8f1697b495ee645a09a00974f24
diff --git a/designate_tempest_plugin/config.py b/designate_tempest_plugin/config.py
index 4f880e2..2a8e25e 100644
--- a/designate_tempest_plugin/config.py
+++ b/designate_tempest_plugin/config.py
@@ -98,6 +98,11 @@
'the new keystone default roles? This configuration '
'value should be same as designate.conf: '
'[oslo_policy].enforce_new_defaults option.'),
+ cfg.BoolOpt('test_multipool_with_delete_opt',
+ default=False,
+ help="Is multipool feature being tested with --delete option?"
+ "If it is, it might delete pools that were created in "
+ "other tests."),
]
# Extending this enforce_scope group defined in tempest
diff --git a/designate_tempest_plugin/tests/api/v2/test_pool.py b/designate_tempest_plugin/tests/api/v2/test_pool.py
index 0e7753e..ba19623 100644
--- a/designate_tempest_plugin/tests/api/v2/test_pool.py
+++ b/designate_tempest_plugin/tests/api/v2/test_pool.py
@@ -14,6 +14,7 @@
from operator import itemgetter
+import testtools
from oslo_log import log as logging
from tempest import config
from tempest.lib import decorators
@@ -51,6 +52,10 @@
cls.admin_client = cls.os_admin.dns_v2.PoolClient()
@decorators.idempotent_id('69257f7c-b3d5-4e1b-998e-0677ad12f125')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
def test_create_pool(self):
pool_data = {
"name": "Example Pool",
@@ -79,6 +84,10 @@
project_id=pool_data["project_id"])
@decorators.idempotent_id('e80eb70a-8ee5-40eb-b06e-599597a8ab7e')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
def test_show_pool(self):
LOG.info('Create a pool')
_, pool = self.admin_client.create_pool(project_id="1")
@@ -106,6 +115,10 @@
headers=self.all_projects_header)
@decorators.idempotent_id('d8c4c377-5d88-452d-a4d2-c004d72e1abe')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
def test_delete_pool(self):
LOG.info('Create a pool')
_, pool = self.admin_client.create_pool(project_id="1")
@@ -128,6 +141,10 @@
'PoolClient', 'delete_pool', expected_allowed, False, pool['id'])
@decorators.idempotent_id('77c85b40-83b2-4c17-9fbf-e6d516cfce90')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
def test_list_pools(self):
LOG.info('Create a pool')
_, pool = self.admin_client.create_pool(project_id="1")
@@ -150,6 +167,10 @@
headers=self.all_projects_header)
@decorators.idempotent_id('fdcc84ce-af65-4af6-a5fc-6c50acbea0f0')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
def test_update_pool(self):
LOG.info('Create a pool')
_, pool = self.admin_client.create_pool(project_id="1")
@@ -302,6 +323,10 @@
ns_records=[{"hostname": "ns1.example.org.", "priority": -1}])
@decorators.idempotent_id('cc378e4c-ac05-11eb-ae06-74e5f9e2a801')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
# Note: Update pool API is deprecated for removal.
def test_update_pool_with_invalid_name(self):
LOG.info('Create a pool')
@@ -317,6 +342,10 @@
headers=self.all_projects_header, extra_headers=True)
@decorators.idempotent_id('2e496596-ac07-11eb-ae06-74e5f9e2a801')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
def test_update_pool_with_invalid_hostname_in_ns_records(self):
# Note: Update pool API is deprecated for removal.
LOG.info('Create a pool')
@@ -332,6 +361,10 @@
headers=self.all_projects_header, extra_headers=True)
@decorators.idempotent_id('3e934624-ac07-11eb-ae06-74e5f9e2a801')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
def test_update_pool_with_invalid_priority_in_ns_records(self):
# Note: Update pool API is deprecated for removal.
LOG.info('Create a pool')
diff --git a/designate_tempest_plugin/tests/api/v2/test_tsigkey.py b/designate_tempest_plugin/tests/api/v2/test_tsigkey.py
index db92ca3..9522395 100644
--- a/designate_tempest_plugin/tests/api/v2/test_tsigkey.py
+++ b/designate_tempest_plugin/tests/api/v2/test_tsigkey.py
@@ -11,7 +11,7 @@
# 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 oslo_log import log as logging
from tempest import config
from tempest.lib.common.utils import data_utils
@@ -300,6 +300,10 @@
0, len(listed_tsigkeys), 'Failed, no tsigkey should be listed')
@decorators.idempotent_id('e8bcf80a-d8b4-11eb-b95a-74e5f9e2a801')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
def test_list_tsigkey_filter_by_scope(self):
LOG.info('Create tsigkey for a pool')
@@ -348,6 +352,10 @@
'Failed, no tsigkey is expected to be listed')
@decorators.idempotent_id('794554f0-d8b8-11eb-b95a-74e5f9e2a801')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
def test_list_tsigkey_filter_by_algorithm(self):
LOG.info('Create tsigkey for a pool')
@@ -658,6 +666,10 @@
tsigkey_data['secret'], tsigkey_data['scope'])
@decorators.idempotent_id('0dfbc2f8-d8bb-11eb-b95a-74e5f9e2a801')
+ @testtools.skipIf(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
@decorators.skip_because(bug="1934120")
def test_create_tsigkey_for_pool_with_scope_zone(self):
pool = self.pool_admin_client.create_pool()[1]
diff --git a/designate_tempest_plugin/tests/resources/__init__.py b/designate_tempest_plugin/tests/resources/__init__.py
new file mode 100644
index 0000000..f4f5c82
--- /dev/null
+++ b/designate_tempest_plugin/tests/resources/__init__.py
@@ -0,0 +1,20 @@
+# Copyright (C) 2024 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.
+import os
+
+# The idea here is that anything that needs resources can do:
+#
+# from designate.tests import resources
+# my_resource_path = os.path.join(resources.path, my_resource_folder)
+path = os.path.dirname(os.path.realpath(__file__))
diff --git a/designate_tempest_plugin/tests/resources/pools_yaml/multiple-pools.yaml b/designate_tempest_plugin/tests/resources/pools_yaml/multiple-pools.yaml
new file mode 100644
index 0000000..2fe047d
--- /dev/null
+++ b/designate_tempest_plugin/tests/resources/pools_yaml/multiple-pools.yaml
@@ -0,0 +1,59 @@
+---
+- name: pool-2
+ id: cf2e8eab-76cd-4162-bf76-8aeee3556de0
+ description: BIND9 Pool-2
+ attributes:
+ internal: true
+ ns_records:
+ - hostname: ns1-1.example.org.
+ priority: 1
+ - hostname: ns1-2.example.org.
+ priority: 2
+ nameservers:
+ - host: 192.0.2.2
+ port: 1053
+ # - host: 192.0.2.3
+ # port: 53
+ targets:
+ - type: bind9
+ description: BIND9 Server 1
+ masters:
+ - host: 192.0.2.1
+ port: 5354
+ options:
+ host: 192.0.2.2
+ port: 1053
+ rndc_host: 192.0.2.2
+ rndc_port: 1953
+ rndc_key_file: /etc/designate/rndc.key
+ tsigkey_name: multiple-pools-pool-2
+
+- name: default
+ description: Default BIND9 Pool
+
+ attributes: {}
+
+ ns_records:
+ - hostname: ns1-1.example.org.
+ priority: 1
+ - hostname: ns1-2.example.org.
+ priority: 2
+
+ nameservers:
+ - host: 192.0.2.2
+ port: 53
+ # - host: 192.0.2.3
+ # port: 53
+
+ targets:
+ - type: bind9
+ description: Default BIND9 Server
+ masters:
+ - host: 192.0.2.1
+ port: 5354
+ options:
+ host: 192.0.2.2
+ port: 53
+ rndc_host: 192.0.2.2
+ rndc_port: 953
+ rndc_key_file: /etc/designate/rndc.key
diff --git a/designate_tempest_plugin/tests/resources/pools_yaml/other-pools.yaml b/designate_tempest_plugin/tests/resources/pools_yaml/other-pools.yaml
new file mode 100644
index 0000000..5e931d2
--- /dev/null
+++ b/designate_tempest_plugin/tests/resources/pools_yaml/other-pools.yaml
@@ -0,0 +1,61 @@
+---
+- name: other_pool2
+ id: f2e9d8c7-6b5a-4f3e-8d2c-1b7a9e4d3f2e
+ description: The first BIND9 pool of the other multipools file
+ attributes:
+ type: internal
+
+ ns_records:
+ - hostname: ns1-1.example.org.
+ priority: 1
+ - hostname: ns1-2.example.org.
+ priority: 2
+
+ nameservers:
+ - host: 192.0.2.2
+ port: 1053
+ # - host: 192.0.2.3
+ # port: 53
+
+ targets:
+ - type: bind9
+ description: BIND9 Server 1
+ masters:
+ - host: 192.0.2.1
+ port: 5354
+ options:
+ host: 192.0.2.2
+ port: 1053
+ rndc_host: 192.0.2.2
+ rndc_port: 1953
+ rndc_key_file: /etc/designate/rndc.key
+ tsigkey_name: other-pools-pool-2
+
+- name: default
+ description: Default BIND9 Pool
+ attributes: {}
+
+ ns_records:
+ - hostname: ns1-1.example.org.
+ priority: 1
+ - hostname: ns1-2.example.org.
+ priority: 2
+
+ nameservers:
+ - host: 192.0.2.2
+ port: 53
+ # - host: 192.0.2.3
+ # port: 53
+
+ targets:
+ - type: bind9
+ description: Default BIND9 Server
+ masters:
+ - host: 192.0.2.1
+ port: 5354
+ options:
+ host: 192.0.2.2
+ port: 53
+ rndc_host: 192.0.2.2
+ rndc_port: 953
+ rndc_key_file: /etc/designate/rndc.key
\ No newline at end of file
diff --git a/designate_tempest_plugin/tests/scenario/v2/test_designate_multipool.py b/designate_tempest_plugin/tests/scenario/v2/test_designate_multipool.py
new file mode 100644
index 0000000..c38ef28
--- /dev/null
+++ b/designate_tempest_plugin/tests/scenario/v2/test_designate_multipool.py
@@ -0,0 +1,246 @@
+# Copyright 2024 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.
+import os
+import random
+
+import testtools
+import yaml
+from oslo_log import log as logging
+from tempest import config
+import subprocess
+
+from tempest.lib import decorators
+
+from designate_tempest_plugin.tests import base
+from designate_tempest_plugin.tests import resources
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class DesignateManageTest(base.BaseDnsV2Test):
+ credentials = ["admin", 'primary', 'system_admin']
+ managed_resource = None
+
+ @classmethod
+ def skip_checks(cls) -> None:
+ super().skip_checks()
+ if CONF.dns_feature_enabled.designate_manage_path:
+ cls.designate_manage_cmd = (
+ CONF.dns_feature_enabled.designate_manage_path)
+ else:
+ raise cls.skipException('designate-manage path was not found. '
+ 'Skipping this test class')
+
+ @classmethod
+ def _run_designate_manage_command(cls,
+ managed_resource: str,
+ command: str,
+ *args) -> str:
+ """Runs the designate-manage command with the provided arguments.
+
+ :param managed_resource: (str): The resource managed by the
+ designate-manage command. For example: pool
+ :param command: (str): The command to run. For example: update
+ :return: The command output
+ """
+ managed_resource = managed_resource or cls.managed_resource
+
+ commands_list = [cls.designate_manage_cmd, managed_resource]
+ if command and isinstance(command, tuple):
+ commands_list.extend(command)
+ else:
+ commands_list.append(command)
+ if args and isinstance(args, tuple):
+ commands_list.extend(args[0])
+ try:
+ output = subprocess.check_output(commands_list,
+ stderr=subprocess.STDOUT,
+ text=True)
+ return output
+ except subprocess.CalledProcessError as e:
+ LOG.error(e.output)
+
+
+def _get_pools_path(name: str) -> str:
+ return os.path.join(resources.path, 'pools_yaml', name)
+
+
+@testtools.skipUnless(CONF.dns_feature_enabled.test_multipool_with_delete_opt,
+ 'Multipools feature is being tested with --delete '
+ 'option. It might delete pools that were created in '
+ 'other tests.')
+class DesignateManagePoolTest(DesignateManageTest):
+ managed_resource = 'pool'
+ file_attributes_to_num_of_appearances = { # per each Pool
+ 'also_notifies:': 1, 'attributes:': 1, 'description:': 2, 'id:': 1,
+ 'name:': 2, 'nameservers:': 1, 'ns_records:': 1, 'targets:': 1
+ }
+ MULTIPOOLS_FILE_PATH = "/etc/designate/multiple-pools.yaml"
+
+ @classmethod
+ def resource_setup(cls):
+ testtools.skipUnless(os.path.exists(cls.MULTIPOOLS_FILE_PATH),
+ f"multiple-pools configuration file {cls.MULTIPOOLS_FILE_PATH} was "
+ "not found, skipping the test")
+ cls._update_pools_file(cls.MULTIPOOLS_FILE_PATH)
+
+ @classmethod
+ def _update_pools_file(cls, pools_file_path):
+ if not pools_file_path.startswith('/'):
+ pools_file_path = _get_pools_path(name=pools_file_path)
+ cls._run_designate_manage_pool_command(
+ 'update',
+ '--file',
+ pools_file_path,
+ '--delete')
+
+ def tearDown(self):
+ super(DesignateManagePoolTest, self).tearDown()
+ self._update_pools_file(self.MULTIPOOLS_FILE_PATH)
+
+ @staticmethod
+ def _load_config(filename) -> str:
+ with open(filename) as stream:
+ return yaml.safe_load(stream)
+
+ @classmethod
+ def _run_designate_manage_pool_command(cls, command: str, *args) -> str:
+ return super(
+ DesignateManagePoolTest, cls)._run_designate_manage_command(
+ 'pool', command, args)
+
+ @decorators.idempotent_id('ed42f367-e5ba-40d7-a08d-366ad787d21d')
+ def test_pool_show_config(self):
+ self._update_pools_file(self.MULTIPOOLS_FILE_PATH)
+ pool_config = self._run_designate_manage_pool_command(
+ command='show_config').split('\n\n')[0]
+ self.assertIn('BIND Pool', pool_config)
+
+ @decorators.idempotent_id('ed42f367-e5ba-40d7-a08d-366ad787d21e')
+ def test_pool_show_config_all(self):
+ self._update_pools_file(pools_file_path='multiple-pools.yaml')
+ pool_config = self._run_designate_manage_pool_command(
+ 'show_config', '--all').split('\n\n')[0]
+
+ pool_config_list = pool_config.split('\n')
+
+ for attribute in self.file_attributes_to_num_of_appearances:
+ num_of_occurrences = sum(attribute in s for s in pool_config_list)
+ file_attributes_to_num_of_appearances = {
+ 'also_notifies:': 2, 'attributes:': 2, 'description:': 4,
+ 'id:': 2, 'name:': 7, 'nameservers:': 2, 'ns_records:': 2,
+ 'targets:': 2
+ }
+ err_msg = (f'{attribute} was supposed to appear '
+ f'{file_attributes_to_num_of_appearances[attribute]} '
+ 'times on the designate-manage output, but '
+ f'it appeared {num_of_occurrences} times.')
+ self.assertEqual(
+ file_attributes_to_num_of_appearances[attribute],
+ num_of_occurrences, err_msg)
+
+ @decorators.idempotent_id('ed42f367-e5ba-40d7-a08d-366ad787d220')
+ def test_pool_update_multiple_pools_without_delete(self):
+
+ # Updating to multiple-pools.yaml with --delete
+ self._update_pools_file(pools_file_path='multiple-pools.yaml')
+
+ # Updating to other-pools.yaml without --delete. There should be 5
+ # pools after the update
+ pools_yaml_path = _get_pools_path(name='other-pools.yaml')
+ self._run_designate_manage_pool_command(
+ 'update',
+ '--file',
+ pools_yaml_path,
+ )
+
+ pool_config = self._run_designate_manage_pool_command(
+ 'show_config', '--all').split('\n\n')[0]
+
+ pool_config_list = pool_config.split('\n')
+ for attribute in self.file_attributes_to_num_of_appearances:
+ num_of_occurrences = sum(attribute in s for s in pool_config_list)
+ file_attributes_to_num_of_appearances = {
+ 'also_notifies:': 3, 'attributes:': 3, 'description:': 6,
+ 'id:': 3, 'name:': 11, 'nameservers:': 3, 'ns_records:': 3,
+ 'targets:': 3
+ }
+ err_msg = (f'{attribute} was supposed to appear '
+ f'{file_attributes_to_num_of_appearances[attribute]} '
+ 'times on the designate-manage output, but '
+ f'it appeared {num_of_occurrences} times.')
+ self.assertEqual(
+ file_attributes_to_num_of_appearances[attribute],
+ num_of_occurrences, err_msg)
+
+ @decorators.idempotent_id('ed42f367-e5ba-40d7-a08d-366ad787d223')
+ def test_pool_update_multiple_pools_dry_run(self):
+ self._update_pools_file(pools_file_path='multiple-pools.yaml')
+
+ pools_yaml_path = _get_pools_path(name='other-pools.yaml')
+ self._run_designate_manage_pool_command(
+ 'update',
+ '--file',
+ pools_yaml_path,
+ '--dry-run'
+ )
+
+ pool_config = self._run_designate_manage_pool_command(
+ 'show_config', '--all').split('\n\n')[0]
+
+ pool_config_list = pool_config.split('\n')
+
+ for attribute in self.file_attributes_to_num_of_appearances:
+ num_of_occurrences = sum(attribute in s for s in pool_config_list)
+ file_attributes_to_num_of_appearances = {
+ 'also_notifies:': 2, 'attributes:': 2, 'description:': 4,
+ 'id:': 2, 'name:': 7, 'nameservers:': 2, 'ns_records:': 2,
+ 'targets:': 2
+ }
+ err_msg = (f'{attribute} was supposed to appear '
+ f'{file_attributes_to_num_of_appearances[attribute]} '
+ 'times on the designate-manage output, but '
+ f'it appeared {num_of_occurrences} times.')
+ self.assertEqual(
+ file_attributes_to_num_of_appearances[attribute],
+ num_of_occurrences, err_msg)
+
+ @decorators.idempotent_id('ed42f367-e5ba-40d7-a08d-366ad787d224')
+ def test_pool_generate_file(self):
+ temp_pools_yaml_conf_path = '/tmp/pools_tempest.yaml'
+ if os.path.exists(temp_pools_yaml_conf_path):
+ LOG.debug(f'Temporary pools.yaml file {temp_pools_yaml_conf_path} '
+ 'exists.\nRemoving this file so we could continue '
+ 'testing')
+ os.remove(temp_pools_yaml_conf_path)
+ self._run_designate_manage_pool_command('generate_file',
+ '--file',
+ temp_pools_yaml_conf_path)
+ self.assertTrue(os.path.exists(path=temp_pools_yaml_conf_path))
+ # (At least) the default pool config should be written to the file
+ pools_conf = self._load_config(filename=temp_pools_yaml_conf_path)
+ if len(pools_conf) > 1:
+ pool_idx = random.randint(0, len(pools_conf) - 1)
+ else:
+ pool_idx = 0
+ pool = yaml.safe_dump(pools_conf[pool_idx]).split('\n')
+
+ for attribute in self.file_attributes_to_num_of_appearances:
+ self.assertTrue(
+ any(attribute in s for s in pool),
+ f'{attribute} not in {pool}'
+ )
+ if os.path.exists(temp_pools_yaml_conf_path):
+ os.remove(temp_pools_yaml_conf_path)