summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stachowski <peter@tesora.com>2016-11-04 10:45:27 -0400
committerPeter Stachowski <peter@tesora.com>2017-01-05 00:11:59 +0000
commit714c6e781c0bf6ad84015061c397bedce8eccd1e (patch)
tree7e7a384a3cb20573bb661044cd6a5aac002466aa
parentd273969fa33a78a11a27ffe1128860dcba0fad47 (diff)
downloadpython-troveclient-714c6e781c0bf6ad84015061c397bedce8eccd1e.tar.gz
Add module-instance-count command
Added a --count_only flag to the call for module instances to return a summary of the applied instances based on the MD5 of the module (this is most useful for live_update modules, to see which ones haven't been updated). Added a new module-instance-count command. This was done to facilitate getting the summary, since it returns a different result set. It basically calls the same python interface as module-instances, but adds the --count_only flag. Also added some missing tests. Change-Id: Iea661166bf3a4f3520a590da5954aedcd0036243 Partial-Bug: #1554900 Depends-On: I4caf4a57226dd711575cde766076fa25d16792e2
-rw-r--r--releasenotes/notes/add_mod_inst_count-ce532a2187b.yaml6
-rw-r--r--troveclient/tests/fakes.py13
-rw-r--r--troveclient/tests/test_instances.py50
-rw-r--r--troveclient/tests/test_modules.py22
-rw-r--r--troveclient/tests/test_v1_shell.py15
-rw-r--r--troveclient/v1/modules.py4
-rw-r--r--troveclient/v1/shell.py33
7 files changed, 137 insertions, 6 deletions
diff --git a/releasenotes/notes/add_mod_inst_count-ce532a2187b.yaml b/releasenotes/notes/add_mod_inst_count-ce532a2187b.yaml
new file mode 100644
index 0000000..27b7a06
--- /dev/null
+++ b/releasenotes/notes/add_mod_inst_count-ce532a2187b.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - Add module-instance-count support to list
+ a count of all instances having a specific
+ module applied. Bug 1554900
+
diff --git a/troveclient/tests/fakes.py b/troveclient/tests/fakes.py
index eaab7c8..a3816d0 100644
--- a/troveclient/tests/fakes.py
+++ b/troveclient/tests/fakes.py
@@ -178,6 +178,17 @@ class FakeHTTPClient(base_client.HTTPClient):
"region": "regionOne",
"datastore": {"version": "5.6", "type": "mysql"}}]})
+ def get_instance_counts(self, **kw):
+ return (200, {}, {"instances": [
+ {
+ "module_id": "4321",
+ "module_name": "mod1",
+ "min_date": "2015-05-02T11:06:16",
+ "max_date": "2015-05-02T11:06:19",
+ "module_md5": "9db783b92a9355f70c41806659fcb77d",
+ "current": True,
+ "count": 1}]})
+
def get_instances_1234(self, **kw):
r = {'instance': self.get_instances()[2]['instances'][0]}
return (200, {}, r)
@@ -479,6 +490,8 @@ class FakeHTTPClient(base_client.HTTPClient):
return (200, {}, {"modules": [{"module": {}}]})
def get_modules_4321_instances(self, **kw):
+ if kw.get('count_only', False):
+ return self.get_instance_counts()
return self.get_instances()
def get_instances_modules(self, **kw):
diff --git a/troveclient/tests/test_instances.py b/troveclient/tests/test_instances.py
index 21ef2d8..b65583d 100644
--- a/troveclient/tests/test_instances.py
+++ b/troveclient/tests/test_instances.py
@@ -233,6 +233,56 @@ class InstancesTest(testtools.TestCase):
resp.status_code = 500
self.assertRaises(Exception, self.instances.edit, 'instance1')
+ def test_module_apply(self):
+ resp = mock.Mock()
+ resp.status_code = 200
+ body = {'modules': []}
+ self.instances.api.client.post = mock.Mock(return_value=(resp, body))
+ self.instances.module_apply(self.instance_with_id, "mod_id")
+ resp.status_code = 500
+ self.assertRaises(Exception, self.instances.module_apply,
+ 'instance1', 'mod1')
+
+ def test_module_remove(self):
+ resp = mock.Mock()
+ resp.status_code = 200
+ body = {'modules': []}
+ self.instances.api.client.delete = mock.Mock(return_value=(resp, body))
+ self.instances.module_remove(self.instance_with_id, "mod_id")
+ resp.status_code = 500
+ self.assertRaises(Exception, self.instances.module_remove,
+ 'instance1', 'mod1')
+
+ def test_module_query(self):
+ resp = mock.Mock()
+ resp.status_code = 200
+ body = {'modules': []}
+ self.instances.api.client.get = mock.Mock(return_value=(resp, body))
+ self.instances.module_query(self.instance_with_id)
+ resp.status_code = 500
+ self.assertRaises(Exception, self.instances.module_query,
+ 'instance1')
+
+ def test_module_retrieve(self):
+ resp = mock.Mock()
+ resp.status_code = 200
+ body = {'modules': []}
+ self.instances.api.client.get = mock.Mock(return_value=(resp, body))
+ self.instances.module_retrieve(self.instance_with_id)
+ resp.status_code = 500
+ self.assertRaises(Exception, self.instances.module_retrieve,
+ 'instance1')
+
+ def test_module_list_instance(self):
+ resp = mock.Mock()
+ resp.status_code = 200
+ body = {'modules': []}
+ self.instances.api.client.get = mock.Mock(return_value=(resp, body))
+ self.instances.modules(self.instance_with_id)
+ resp.status_code = 500
+ self.assertRaises(Exception, self.instances.modules,
+ 'instance1')
+
def test_upgrade(self):
resp = mock.Mock()
resp.status_code = 200
diff --git a/troveclient/tests/test_modules.py b/troveclient/tests/test_modules.py
index ebd2802..bffc1f6 100644
--- a/troveclient/tests/test_modules.py
+++ b/troveclient/tests/test_modules.py
@@ -123,3 +123,25 @@ class TestModules(testtools.TestCase):
self.modules.delete(self.module)
resp.status_code = 500
self.assertRaises(Exception, self.modules.delete, self.module_name)
+
+ def _test_instances(self, expected_query=None):
+ page_mock = mock.Mock()
+ self.modules._paginated = page_mock
+ limit = "test-limit"
+ marker = "test-marker"
+ if not expected_query:
+ expected_query = {}
+ self.modules.instances(self.module_name, limit, marker,
+ **expected_query)
+ page_mock.assert_called_with("/modules/mod_1/instances",
+ "instances", limit, marker,
+ query_strings=expected_query)
+
+ def test_instance_count(self):
+ expected_query = {'include_clustered': True,
+ 'count_only': True}
+ self._test_instances(expected_query)
+
+ def test_instances(self):
+ expected_query = {'include_clustered': True}
+ self._test_instances(expected_query)
diff --git a/troveclient/tests/test_v1_shell.py b/troveclient/tests/test_v1_shell.py
index 0e55947..04af36c 100644
--- a/troveclient/tests/test_v1_shell.py
+++ b/troveclient/tests/test_v1_shell.py
@@ -722,6 +722,21 @@ class ShellTest(utils.TestCase):
self.assert_called_anytime(
'GET', '/modules/4321/instances?include_clustered=True')
+ def test_module_instance_count(self):
+ with mock.patch.object(troveclient.v1.modules.Module, '__repr__',
+ mock.Mock(return_value='4321')):
+ self.run_command('module-instance-count 4321')
+ self.assert_called(
+ 'GET', '/modules/4321/instances?count_only=True')
+
+ def test_module_instance_count_clustered(self):
+ with mock.patch.object(troveclient.v1.modules.Module, '__repr__',
+ mock.Mock(return_value='4321')):
+ self.run_command('module-instance-count 4321 --include_clustered')
+ self.assert_called(
+ 'GET', '/modules/4321/instances?count_only=True&'
+ 'include_clustered=True')
+
def test_cluster_modules(self):
self.run_command('cluster-modules cls-1234')
self.assert_called_anytime('GET', '/clusters/cls-1234')
diff --git a/troveclient/v1/modules.py b/troveclient/v1/modules.py
index c8a74c3..9508608 100644
--- a/troveclient/v1/modules.py
+++ b/troveclient/v1/modules.py
@@ -157,11 +157,13 @@ class Modules(base.ManagerWithFind):
common.check_for_exceptions(resp, body, url)
def instances(self, module, limit=None, marker=None,
- include_clustered=False):
+ include_clustered=False, count_only=False):
"""Get a list of all instances this module has been applied to."""
url = "/modules/%s/instances" % base.getid(module)
query_strings = {}
if include_clustered:
query_strings['include_clustered'] = include_clustered
+ if count_only:
+ query_strings['count_only'] = count_only
return self._paginated(url, "instances", limit, marker,
query_strings=query_strings)
diff --git a/troveclient/v1/shell.py b/troveclient/v1/shell.py
index 0788fac..9131ff3 100644
--- a/troveclient/v1/shell.py
+++ b/troveclient/v1/shell.py
@@ -260,7 +260,7 @@ def do_list(cs, args):
_print_instances(instances)
-def _print_instances(instances):
+def _print_instances(instances, is_admin=False):
for instance in instances:
setattr(instance, 'flavor_id', instance.flavor['id'])
if hasattr(instance, 'volume'):
@@ -272,9 +272,12 @@ def _print_instances(instances):
setattr(instance, 'datastore_version',
instance.datastore['version'])
setattr(instance, 'datastore', instance.datastore['type'])
- utils.print_list(instances, ['id', 'name', 'datastore',
- 'datastore_version', 'status',
- 'flavor_id', 'size', 'region'])
+ fields = ['id', 'name', 'datastore',
+ 'datastore_version', 'status',
+ 'flavor_id', 'size', 'region']
+ if is_admin:
+ fields.append('tenant_id')
+ utils.print_list(instances, fields)
@utils.arg('--limit', metavar='<limit>', type=int, default=None,
@@ -1964,7 +1967,27 @@ def do_module_instances(cs, args):
while not args.limit and items.next:
items = cs.modules.instances(module, marker=items.next)
instance_list += items
- _print_instances(instance_list)
+ _print_instances(instance_list, utils.is_admin(cs))
+
+
+@utils.arg('module', metavar='<module>', type=str,
+ help=_('ID or name of the module.'))
+@utils.arg('--include_clustered', action="store_true", default=False,
+ help=_("Include instances that are part of a cluster "
+ "(default %(default)s)."))
+@utils.service_type('database')
+def do_module_instance_count(cs, args):
+ """Lists a count of the instances for each module md5."""
+ module = _find_module(cs, args.module)
+ count_list = cs.modules.instances(
+ module, include_clustered=args.include_clustered,
+ count_only=True)
+ field_list = ['module_name', 'min_updated_date', 'max_updated_date',
+ 'module_md5', 'current', 'instance_count']
+ utils.print_list(count_list, field_list,
+ labels={'module_md5': 'Module MD5',
+ 'instance_count': 'Count',
+ 'module_id': 'Module ID'})
@utils.arg('cluster', metavar='<cluster>',