From db8593943310de54a8bb35327ef11c6734e8fd9f Mon Sep 17 00:00:00 2001 From: Peter Stachowski Date: Mon, 4 Apr 2016 20:25:53 +0000 Subject: [PATCH] Locality support for clusters In order to allow clusters to be all on the same hypervisor (affinity) or all on different hypervisors (anti-affinity) a new argument (locality) needed to be added to the Trove cluster-create API. This changeset addresses the Trove client part of this feature. A --locality flag is now available on the 'cluster-create' command and is passed to the server for processing. Partially implements: blueprint replication-cluster-locality Change-Id: Ie46cfa69ffe6a64760aca38c495563f5724bd0d0 --- ...support-for-clusters-7e89f9ddbe5f4131.yaml | 6 ++++++ troveclient/tests/test_clusters.py | 8 ++++--- troveclient/tests/test_v1_shell.py | 21 +++++++++++++++++++ troveclient/v1/clusters.py | 5 ++++- troveclient/v1/shell.py | 9 +++++++- 5 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 releasenotes/notes/locality-support-for-clusters-7e89f9ddbe5f4131.yaml diff --git a/releasenotes/notes/locality-support-for-clusters-7e89f9ddbe5f4131.yaml b/releasenotes/notes/locality-support-for-clusters-7e89f9ddbe5f4131.yaml new file mode 100644 index 00000000..9b4c1d58 --- /dev/null +++ b/releasenotes/notes/locality-support-for-clusters-7e89f9ddbe5f4131.yaml @@ -0,0 +1,6 @@ +--- +features: + - A --locality flag was added to the trove cluster-create + command to allow a user to specify whether instances in + a cluster should be on the same hypervisor (affinity) + or on different hypervisors (anti-affinity). diff --git a/troveclient/tests/test_clusters.py b/troveclient/tests/test_clusters.py index bf3061b4..0ccda058 100644 --- a/troveclient/tests/test_clusters.py +++ b/troveclient/tests/test_clusters.py @@ -70,17 +70,19 @@ class ClustersTest(testtools.TestCase): clusters_test = self.get_clusters() clusters_test._create = mock.Mock(side_effect=side_effect_func) - instance = [{'flavor-id': 11, 'volume': 2}] + instances = [{'flavor-id': 11, 'volume': 2}] + locality = 'affinity' path, body, resp_key = clusters_test.create("test-name", "datastore", "datastore-version", - instance) + instances, locality) self.assertEqual("/clusters", path) self.assertEqual("cluster", resp_key) self.assertEqual("test-name", body["cluster"]["name"]) self.assertEqual("datastore", body["cluster"]["datastore"]["type"]) self.assertEqual("datastore-version", body["cluster"]["datastore"]["version"]) - self.assertEqual(instance, body["cluster"]["instances"]) + self.assertEqual(instances, body["cluster"]["instances"]) + self.assertEqual(locality, body["cluster"]["locality"]) def test_list(self): page_mock = mock.Mock() diff --git a/troveclient/tests/test_v1_shell.py b/troveclient/tests/test_v1_shell.py index faf1548d..405ed66b 100644 --- a/troveclient/tests/test_v1_shell.py +++ b/troveclient/tests/test_v1_shell.py @@ -439,6 +439,27 @@ class ShellTest(utils.TestCase): self.run_command(cmd) self.assert_called('POST', '/clusters/cls-1234') + def test_cluster_create_with_locality(self): + cmd = ('cluster-create test-clstr2 redis 3.0 --locality=affinity ' + '--instance flavor=2,volume=1 ' + '--instance flavor=2,volume=1 ' + '--instance flavor=2,volume=1 ') + self.run_command(cmd) + self.assert_called_anytime( + 'POST', '/clusters', + {'cluster': { + 'instances': [ + {'flavorRef': '2', + 'volume': {'size': '1'}}, + {'flavorRef': '2', + 'volume': {'size': '1'}}, + {'flavorRef': '2', + 'volume': {'size': '1'}}, + ], + 'datastore': {'version': '3.0', 'type': 'redis'}, + 'name': 'test-clstr2', + 'locality': 'affinity'}}) + def test_cluster_create_with_nic_az(self): cmd = ('cluster-create test-clstr1 vertica 7.1 ' '--instance flavor=2,volume=2,nic=\'net-id=some-id\',' diff --git a/troveclient/v1/clusters.py b/troveclient/v1/clusters.py index bf207221..6dc44dfe 100644 --- a/troveclient/v1/clusters.py +++ b/troveclient/v1/clusters.py @@ -31,7 +31,8 @@ class Clusters(base.ManagerWithFind): """Manage :class:`Cluster` resources.""" resource_class = Cluster - def create(self, name, datastore, datastore_version, instances=None): + def create(self, name, datastore, datastore_version, instances=None, + locality=None): """Create (boot) a new cluster.""" body = {"cluster": { "name": name @@ -43,6 +44,8 @@ class Clusters(base.ManagerWithFind): body["cluster"]["datastore"] = datastore_obj if instances: body["cluster"]["instances"] = instances + if locality: + body["cluster"]["locality"] = locality return self._create("/clusters", body, "cluster") diff --git a/troveclient/v1/shell.py b/troveclient/v1/shell.py index edff25c8..bea1c809 100644 --- a/troveclient/v1/shell.py +++ b/troveclient/v1/shell.py @@ -688,6 +688,12 @@ def _strip_option(opts_str, opt_name, is_required=True, "(where net-id=network_id, v4-fixed-ip=IPv4r_fixed_address, " "port-id=port_id), availability_zone=, " "module=.") +@utils.arg('--locality', + metavar='', + default=None, + choices=LOCALITY_DOMAIN, + help='Locality policy to use when creating cluster. Choose ' + 'one of %(choices)s.') @utils.service_type('database') def do_cluster_create(cs, args): """Creates a new cluster.""" @@ -726,7 +732,8 @@ def do_cluster_create(cs, args): cluster = cs.clusters.create(args.name, args.datastore, args.datastore_version, - instances=instances) + instances=instances, + locality=args.locality) _print_cluster(cluster)