diff options
author | Jenkins <jenkins@review.openstack.org> | 2017-02-05 06:46:47 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2017-02-05 06:46:47 +0000 |
commit | b5cf0c58f24e8196a8f358f156df8aa8c094df6d (patch) | |
tree | 4c2d6b494fb8f2fa9efa4a5dce183935c02cae42 /trove/tests/scenario | |
parent | 577d43b02d200b5b60eefc875f1542faa09ebfd9 (diff) | |
parent | 9bca402ec3f651fb9017c20dc27601a548cc79e1 (diff) | |
download | trove-b5cf0c58f24e8196a8f358f156df8aa8c094df6d.tar.gz |
Merge "Add configuration support for clusters"
Diffstat (limited to 'trove/tests/scenario')
-rw-r--r-- | trove/tests/scenario/groups/__init__.py | 3 | ||||
-rw-r--r-- | trove/tests/scenario/groups/cluster_group.py | 143 | ||||
-rw-r--r-- | trove/tests/scenario/runners/cluster_runners.py | 238 | ||||
-rw-r--r-- | trove/tests/scenario/runners/instance_create_runners.py | 20 | ||||
-rw-r--r-- | trove/tests/scenario/runners/test_runners.py | 20 |
5 files changed, 400 insertions, 24 deletions
diff --git a/trove/tests/scenario/groups/__init__.py b/trove/tests/scenario/groups/__init__.py index 8274dd7d..e6d1a822 100644 --- a/trove/tests/scenario/groups/__init__.py +++ b/trove/tests/scenario/groups/__init__.py @@ -51,7 +51,10 @@ CFGGRP_INST_DELETE_WAIT = "scenario.cfggrp_inst_delete_wait_grp" # Cluster Actions Group +CLUSTER_CFGGRP_CREATE = "scenario.cluster_actions_cfggrp_create_grp" +CLUSTER_CFGGRP_DELETE = "scenario.cluster_actions_cfggrp_delete_grp" CLUSTER_ACTIONS = "scenario.cluster_actions_grp" +CLUSTER_ACTIONS_CFGGRP_ACTIONS = "scenario.cluster_actions_cfggrp_actions_grp" CLUSTER_ACTIONS_ROOT_ENABLE = "scenario.cluster_actions_root_enable_grp" CLUSTER_ACTIONS_ROOT_ACTIONS = "scenario.cluster_actions_root_actions_grp" CLUSTER_ACTIONS_ROOT_GROW = "scenario.cluster_actions_root_grow_grp" diff --git a/trove/tests/scenario/groups/cluster_group.py b/trove/tests/scenario/groups/cluster_group.py index 205002b9..72330cb6 100644 --- a/trove/tests/scenario/groups/cluster_group.py +++ b/trove/tests/scenario/groups/cluster_group.py @@ -29,7 +29,7 @@ class ClusterRunnerFactory(test_runners.RunnerFactory): _runner_cls = 'ClusterRunner' -@test(groups=[GROUP, groups.CLUSTER_CREATE], +@test(groups=[GROUP, groups.CLUSTER_CFGGRP_CREATE], runs_after_groups=[groups.MODULE_DELETE, groups.CFGGRP_INST_DELETE, groups.INST_ACTIONS_RESIZE_WAIT, @@ -39,6 +39,20 @@ class ClusterRunnerFactory(test_runners.RunnerFactory): groups.ROOT_ACTION_INST_DELETE, groups.REPL_INST_DELETE_WAIT, groups.INST_DELETE]) +class ClusterConfigurationCreateGroup(TestGroup): + + def __init__(self): + super(ClusterConfigurationCreateGroup, self).__init__( + ClusterRunnerFactory.instance()) + + @test + def create_initial_configuration(self): + """Create a configuration group for a new cluster.""" + self.test_runner.run_initial_configuration_create() + + +@test(groups=[GROUP, groups.CLUSTER_ACTIONS, groups.CLUSTER_CREATE], + runs_after_groups=[groups.CLUSTER_CFGGRP_CREATE]) class ClusterCreateGroup(TestGroup): def __init__(self): @@ -71,6 +85,11 @@ class ClusterCreateWaitGroup(TestGroup): self.test_runner.run_cluster_create_wait() @test(depends_on=[cluster_create_wait]) + def verify_initial_configuration(self): + """Verify initial configuration values on the cluster.""" + self.test_runner.run_verify_initial_configuration() + + @test(depends_on=[cluster_create_wait]) def add_initial_cluster_data(self): """Add data to cluster.""" self.test_runner.run_add_initial_cluster_data() @@ -179,6 +198,11 @@ class ClusterGrowWaitGroup(TestGroup): self.test_runner.run_cluster_grow_wait() @test(depends_on=[cluster_grow_wait]) + def verify_initial_configuration(self): + """Verify initial configuration values on the cluster.""" + self.test_runner.run_verify_initial_configuration() + + @test(depends_on=[cluster_grow_wait]) def verify_initial_cluster_data_after_grow(self): """Verify the initial data still exists after cluster grow.""" self.test_runner.run_verify_initial_cluster_data() @@ -246,6 +270,11 @@ class ClusterUpgradeWaitGroup(TestGroup): self.test_runner.run_cluster_upgrade_wait() @test(depends_on=[cluster_upgrade_wait]) + def verify_initial_configuration(self): + """Verify initial configuration values on the cluster.""" + self.test_runner.run_verify_initial_configuration() + + @test(depends_on=[cluster_upgrade_wait]) def verify_initial_cluster_data_after_upgrade(self): """Verify the initial data still exists after cluster upgrade.""" self.test_runner.run_verify_initial_cluster_data() @@ -299,6 +328,11 @@ class ClusterShrinkWaitGroup(TestGroup): self.test_runner.run_cluster_shrink_wait() @test(depends_on=[cluster_shrink_wait]) + def verify_initial_configuration(self): + """Verify initial configuration values on the cluster.""" + self.test_runner.run_verify_initial_configuration() + + @test(depends_on=[cluster_shrink_wait]) def verify_initial_cluster_data_after_shrink(self): """Verify the initial data still exists after cluster shrink.""" self.test_runner.run_verify_initial_cluster_data() @@ -337,6 +371,93 @@ class ClusterRootEnableShrinkGroup(TestGroup): @test(groups=[GROUP, groups.CLUSTER_ACTIONS, + groups.CLUSTER_ACTIONS_CFGGRP_ACTIONS], + depends_on_groups=[groups.CLUSTER_CREATE_WAIT], + runs_after_groups=[groups.CLUSTER_ACTIONS_ROOT_SHRINK]) +class ClusterConfigurationActionsGroup(TestGroup): + + def __init__(self): + super(ClusterConfigurationActionsGroup, self).__init__( + ClusterRunnerFactory.instance()) + + @test + def detach_initial_configuration(self): + """Detach initial configuration group.""" + self.test_runner.run_detach_initial_configuration() + + @test(depends_on=[detach_initial_configuration]) + def restart_cluster_after_detach(self): + """Restarting cluster after configuration change.""" + self.test_runner.restart_after_configuration_change() + + @test + def create_dynamic_configuration(self): + """Create a configuration group with only dynamic entries.""" + self.test_runner.run_create_dynamic_configuration() + + @test + def create_non_dynamic_configuration(self): + """Create a configuration group with only non-dynamic entries.""" + self.test_runner.run_create_non_dynamic_configuration() + + @test(depends_on=[create_dynamic_configuration, + restart_cluster_after_detach]) + def attach_dynamic_configuration(self): + """Test attach dynamic group.""" + self.test_runner.run_attach_dynamic_configuration() + + @test(depends_on=[attach_dynamic_configuration]) + def verify_dynamic_configuration(self): + """Verify dynamic values on the cluster.""" + self.test_runner.run_verify_dynamic_configuration() + + @test(depends_on=[attach_dynamic_configuration], + runs_after=[verify_dynamic_configuration]) + def detach_dynamic_configuration(self): + """Test detach dynamic group.""" + self.test_runner.run_detach_dynamic_configuration() + + @test(depends_on=[create_non_dynamic_configuration, + detach_initial_configuration], + runs_after=[detach_dynamic_configuration]) + def attach_non_dynamic_configuration(self): + """Test attach non-dynamic group.""" + self.test_runner.run_attach_non_dynamic_configuration() + + @test(depends_on=[attach_non_dynamic_configuration]) + def restart_cluster_after_attach(self): + """Restarting cluster after configuration change.""" + self.test_runner.restart_after_configuration_change() + + @test(depends_on=[restart_cluster_after_attach]) + def verify_non_dynamic_configuration(self): + """Verify non-dynamic values on the cluster.""" + self.test_runner.run_verify_non_dynamic_configuration() + + @test(depends_on=[attach_non_dynamic_configuration], + runs_after=[verify_non_dynamic_configuration]) + def detach_non_dynamic_configuration(self): + """Test detach non-dynamic group.""" + self.test_runner.run_detach_non_dynamic_configuration() + + @test(runs_after=[detach_dynamic_configuration, + detach_non_dynamic_configuration]) + def verify_initial_cluster_data(self): + """Verify the initial data still exists.""" + self.test_runner.run_verify_initial_cluster_data() + + @test(depends_on=[detach_dynamic_configuration]) + def delete_dynamic_configuration(self): + """Test delete dynamic configuration group.""" + self.test_runner.run_delete_dynamic_configuration() + + @test(depends_on=[detach_non_dynamic_configuration]) + def delete_non_dynamic_configuration(self): + """Test delete non-dynamic configuration group.""" + self.test_runner.run_delete_non_dynamic_configuration() + + +@test(groups=[GROUP, groups.CLUSTER_ACTIONS, groups.CLUSTER_DELETE], depends_on_groups=[groups.CLUSTER_CREATE_WAIT], runs_after_groups=[groups.CLUSTER_ACTIONS_ROOT_ENABLE, @@ -345,7 +466,9 @@ class ClusterRootEnableShrinkGroup(TestGroup): groups.CLUSTER_ACTIONS_GROW_WAIT, groups.CLUSTER_ACTIONS_SHRINK_WAIT, groups.CLUSTER_UPGRADE_WAIT, - groups.CLUSTER_ACTIONS_RESTART_WAIT]) + groups.CLUSTER_ACTIONS_RESTART_WAIT, + groups.CLUSTER_CFGGRP_CREATE, + groups.CLUSTER_ACTIONS_CFGGRP_ACTIONS]) class ClusterDeleteGroup(TestGroup): def __init__(self): @@ -376,3 +499,19 @@ class ClusterDeleteWaitGroup(TestGroup): def cluster_delete_wait(self): """Wait for the existing cluster to be gone.""" self.test_runner.run_cluster_delete_wait() + + +@test(groups=[GROUP, groups.CLUSTER_ACTIONS, + groups.CLUSTER_CFGGRP_DELETE], + depends_on_groups=[groups.CLUSTER_CFGGRP_CREATE], + runs_after_groups=[groups.CLUSTER_DELETE_WAIT]) +class ClusterConfigurationDeleteGroup(TestGroup): + + def __init__(self): + super(ClusterConfigurationDeleteGroup, self).__init__( + ClusterRunnerFactory.instance()) + + @test + def delete_initial_configuration(self): + """Delete initial configuration group.""" + self.test_runner.run_delete_initial_configuration() diff --git a/trove/tests/scenario/runners/cluster_runners.py b/trove/tests/scenario/runners/cluster_runners.py index d9a0f153..8c652ec6 100644 --- a/trove/tests/scenario/runners/cluster_runners.py +++ b/trove/tests/scenario/runners/cluster_runners.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +import json import os from proboscis import SkipTest @@ -49,6 +50,11 @@ class ClusterRunner(TestRunner): self.initial_instance_count = None self.cluster_instances = None self.cluster_removed_instances = None + self.active_config_group_id = None + self.config_requires_restart = False + self.initial_group_id = None + self.dynamic_group_id = None + self.non_dynamic_group_id = None @property def is_using_existing_cluster(self): @@ -62,6 +68,15 @@ class ClusterRunner(TestRunner): def min_cluster_node_count(self): return 2 + def run_initial_configuration_create(self, expected_http_code=200): + group_id, requires_restart = self.create_initial_configuration( + expected_http_code) + if group_id: + self.initial_group_id = group_id + self.config_requires_restart = requires_restart + else: + raise SkipTest("No groups defined.") + def run_cluster_create(self, num_nodes=None, expected_task_name='BUILDING', expected_http_code=200): self.cluster_count_before_create = len( @@ -84,11 +99,11 @@ class ClusterRunner(TestRunner): self.cluster_id = self.assert_cluster_create( self.cluster_name, instance_defs, self.locality, - expected_task_name, expected_http_code) + self.initial_group_id, expected_task_name, expected_http_code) def assert_cluster_create( - self, cluster_name, instances_def, locality, expected_task_name, - expected_http_code): + self, cluster_name, instances_def, locality, configuration, + expected_task_name, expected_http_code): self.report.log("Testing cluster create: %s" % cluster_name) @@ -100,8 +115,10 @@ class ClusterRunner(TestRunner): cluster = client.clusters.create( cluster_name, self.instance_info.dbaas_datastore, self.instance_info.dbaas_datastore_version, - instances=instances_def, locality=locality) + instances=instances_def, locality=locality, + configuration=configuration) self.assert_client_code(client, expected_http_code) + self.active_config_group_id = configuration self._assert_cluster_values(cluster, expected_task_name) for instance in cluster.instances: self.register_debug_inst_ids(instance['id']) @@ -202,7 +219,8 @@ class ClusterRunner(TestRunner): self.current_root_creds = client.root.create_cluster_root( self.cluster_id, root_credentials['password']) self.assert_client_code(client, expected_http_code) - self._assert_cluster_response(client, cluster_id, expected_task_name) + self._assert_cluster_response( + client, self.cluster_id, expected_task_name) self.assert_equal(root_credentials['name'], self.current_root_creds[0]) self.assert_equal(root_credentials['password'], @@ -506,6 +524,8 @@ class ClusterRunner(TestRunner): check.has_field("updated", six.text_type) if check_locality: check.has_field("locality", six.text_type) + if self.active_config_group_id: + check.has_field("configuration", six.text_type) for instance in cluster.instances: isinstance(instance, dict) self.assert_is_not_none(instance['id']) @@ -528,6 +548,214 @@ class ClusterRunner(TestRunner): except exceptions.NotFound: self.assert_client_code(client, 404) + def restart_after_configuration_change(self): + if self.config_requires_restart: + self.run_cluster_restart() + self.run_cluster_restart_wait() + self.config_requires_restart = False + else: + raise SkipTest("Not required.") + + def run_create_dynamic_configuration(self, expected_http_code=200): + values = self.test_helper.get_dynamic_group() + if values: + self.dynamic_group_id = self.assert_create_group( + 'dynamic_cluster_test_group', + 'a fully dynamic group should not require restart', + values, expected_http_code) + elif values is None: + raise SkipTest("No dynamic group defined in %s." % + self.test_helper.get_class_name()) + else: + raise SkipTest("Datastore has no dynamic configuration values.") + + def assert_create_group(self, name, description, values, + expected_http_code): + json_def = json.dumps(values) + client = self.auth_client + result = client.configurations.create( + name, + json_def, + description, + datastore=self.instance_info.dbaas_datastore, + datastore_version=self.instance_info.dbaas_datastore_version) + self.assert_client_code(client, expected_http_code) + + return result.id + + def run_create_non_dynamic_configuration(self, expected_http_code=200): + values = self.test_helper.get_non_dynamic_group() + if values: + self.non_dynamic_group_id = self.assert_create_group( + 'non_dynamic_cluster_test_group', + 'a group containing non-dynamic properties should always ' + 'require restart', + values, expected_http_code) + elif values is None: + raise SkipTest("No non-dynamic group defined in %s." % + self.test_helper.get_class_name()) + else: + raise SkipTest("Datastore has no non-dynamic configuration " + "values.") + + def run_attach_dynamic_configuration( + self, expected_states=['NONE'], + expected_http_code=202): + if self.dynamic_group_id: + self.assert_attach_configuration( + self.cluster_id, self.dynamic_group_id, expected_states, + expected_http_code) + + def assert_attach_configuration( + self, cluster_id, group_id, expected_states, expected_http_code, + restart_inst=False): + client = self.auth_client + client.clusters.configuration_attach(cluster_id, group_id) + self.assert_client_code(client, expected_http_code) + self.active_config_group_id = group_id + self._assert_cluster_states(client, cluster_id, expected_states) + self.assert_configuration_group(client, cluster_id, group_id) + + if restart_inst: + self.config_requires_restart = True + cluster_instances = self._get_cluster_instances(cluster_id) + for node in cluster_instances: + self.assert_equal( + 'RESTART_REQUIRED', node.status, + "Node '%s' should be in 'RESTART_REQUIRED' state." + % node.id) + + def assert_configuration_group( + self, client, cluster_id, expected_group_id): + cluster = client.clusters.get(cluster_id) + self.assert_equal( + expected_group_id, cluster.configuration, + "Attached group does not have the expected ID.") + + cluster_instances = self._get_cluster_instances(client, cluster_id) + for node in cluster_instances: + self.assert_equal( + expected_group_id, cluster.configuration, + "Attached group does not have the expected ID on " + "cluster node: %s" % node.id) + + def run_attach_non_dynamic_configuration( + self, expected_states=['NONE'], + expected_http_code=202): + if self.non_dynamic_group_id: + self.assert_attach_configuration( + self.cluster_id, self.non_dynamic_group_id, + expected_states, expected_http_code, restart_inst=True) + + def run_verify_initial_configuration(self): + if self.initial_group_id: + self.verify_configuration(self.cluster_id, self.initial_group_id) + + def verify_configuration(self, cluster_id, expected_group_id): + self.assert_configuration_group(cluster_id, expected_group_id) + self.assert_configuration_values(cluster_id, expected_group_id) + + def assert_configuration_values(self, cluster_id, group_id): + if group_id == self.initial_group_id: + if not self.config_requires_restart: + expected_configs = self.test_helper.get_dynamic_group() + else: + expected_configs = self.test_helper.get_non_dynamic_group() + if group_id == self.dynamic_group_id: + expected_configs = self.test_helper.get_dynamic_group() + elif group_id == self.non_dynamic_group_id: + expected_configs = self.test_helper.get_non_dynamic_group() + + self._assert_configuration_values(cluster_id, expected_configs) + + def _assert_configuration_values(self, cluster_id, expected_configs): + cluster_instances = self._get_cluster_instances(cluster_id) + for node in cluster_instances: + host = self.get_instance_host(node) + self.report.log( + "Verifying cluster configuration via node: %s" % host) + for name, value in expected_configs.items(): + actual = self.test_helper.get_configuration_value(name, host) + self.assert_equal(str(value), str(actual), + "Unexpected value of property '%s'" % name) + + def run_verify_dynamic_configuration(self): + if self.dynamic_group_id: + self.verify_configuration(self.cluster_id, self.dynamic_group_id) + + def run_verify_non_dynamic_configuration(self): + if self.non_dynamic_group_id: + self.verify_configuration( + self.cluster_id, self.non_dynamic_group_id) + + def run_detach_initial_configuration(self, expected_states=['NONE'], + expected_http_code=202): + if self.initial_group_id: + self.assert_detach_configuration( + self.cluster_id, expected_states, expected_http_code, + restart_inst=self.config_requires_restart) + + def run_detach_dynamic_configuration(self, expected_states=['NONE'], + expected_http_code=202): + if self.dynamic_group_id: + self.assert_detach_configuration( + self.cluster_id, expected_states, expected_http_code) + + def assert_detach_configuration( + self, cluster_id, expected_states, expected_http_code, + restart_inst=False): + client = self.auth_client + client.clusters.configuration_detach(cluster_id) + self.assert_client_code(client, expected_http_code) + self.active_config_group_id = None + self._assert_cluster_states(client, cluster_id, expected_states) + cluster = client.clusters.get(cluster_id) + self.assert_false( + hasattr(cluster, 'configuration'), + "Configuration group was not detached from the cluster.") + + cluster_instances = self._get_cluster_instances(client, cluster_id) + for node in cluster_instances: + self.assert_false( + hasattr(node, 'configuration'), + "Configuration group was not detached from cluster node: %s" + % node.id) + + if restart_inst: + self.config_requires_restart = True + cluster_instances = self._get_cluster_instances(client, cluster_id) + for node in cluster_instances: + self.assert_equal( + 'RESTART_REQUIRED', node.status, + "Node '%s' should be in 'RESTART_REQUIRED' state." + % node.id) + + def run_detach_non_dynamic_configuration( + self, expected_states=['NONE'], + expected_http_code=202): + if self.non_dynamic_group_id: + self.assert_detach_configuration( + self.cluster_id, expected_states, expected_http_code, + restart_inst=True) + + def run_delete_initial_configuration(self, expected_http_code=202): + if self.initial_group_id: + self.assert_group_delete(self.initial_group_id, expected_http_code) + + def assert_group_delete(self, group_id, expected_http_code): + client = self.auth_client + client.configurations.delete(group_id) + self.assert_client_code(client, expected_http_code) + + def run_delete_dynamic_configuration(self, expected_http_code=202): + if self.dynamic_group_id: + self.assert_group_delete(self.dynamic_group_id, expected_http_code) + + def run_delete_non_dynamic_configuration(self, expected_http_code=202): + if self.non_dynamic_group_id: + self.assert_group_delete(self.non_dynamic_group_id, + expected_http_code) + class CassandraClusterRunner(ClusterRunner): diff --git a/trove/tests/scenario/runners/instance_create_runners.py b/trove/tests/scenario/runners/instance_create_runners.py index eb4bc259..3e9e6484 100644 --- a/trove/tests/scenario/runners/instance_create_runners.py +++ b/trove/tests/scenario/runners/instance_create_runners.py @@ -13,8 +13,6 @@ # License for the specific language governing permissions and limitations # under the License. -import json - from proboscis import SkipTest from trove.tests.config import CONFIG @@ -62,21 +60,9 @@ class InstanceCreateRunner(TestRunner): self.instance_info.helper_database = instance_info.helper_database def run_initial_configuration_create(self, expected_http_code=200): - dynamic_config = self.test_helper.get_dynamic_group() - non_dynamic_config = self.test_helper.get_non_dynamic_group() - values = dynamic_config or non_dynamic_config - if values: - json_def = json.dumps(values) - client = self.auth_client - result = client.configurations.create( - 'initial_configuration_for_instance_create', - json_def, - "Configuration group used by instance create tests.", - datastore=self.instance_info.dbaas_datastore, - datastore_version=self.instance_info.dbaas_datastore_version) - self.assert_client_code(client, expected_http_code) - - self.config_group_id = result.id + group_id, _ = self.create_initial_configuration(expected_http_code) + if group_id: + self.config_group_id = group_id else: raise SkipTest("No groups defined.") diff --git a/trove/tests/scenario/runners/test_runners.py b/trove/tests/scenario/runners/test_runners.py index bc9292d4..3699b087 100644 --- a/trove/tests/scenario/runners/test_runners.py +++ b/trove/tests/scenario/runners/test_runners.py @@ -15,6 +15,7 @@ import datetime import inspect +import json import netaddr import os import proboscis @@ -903,6 +904,25 @@ class TestRunner(object): full_list = client.databases.list(instance_id) return {database.name: database for database in full_list} + def create_initial_configuration(self, expected_http_code): + client = self.auth_client + dynamic_config = self.test_helper.get_dynamic_group() + non_dynamic_config = self.test_helper.get_non_dynamic_group() + values = dynamic_config or non_dynamic_config + if values: + json_def = json.dumps(values) + result = client.configurations.create( + 'initial_configuration_for_create_tests', + json_def, + "Configuration group used by create tests.", + datastore=self.instance_info.dbaas_datastore, + datastore_version=self.instance_info.dbaas_datastore_version) + self.assert_client_code(client, expected_http_code) + + return (result.id, dynamic_config is None) + + return (None, False) + class CheckInstance(AttrCheck): """Class to check various attributes of Instance details.""" |