diff --git a/senlinclient/plugin.py b/senlinclient/plugin.py index d48865f..66002bb 100644 --- a/senlinclient/plugin.py +++ b/senlinclient/plugin.py @@ -13,6 +13,7 @@ import logging from openstack import connection +from openstack import profile from osc_lib import utils LOG = logging.getLogger(__name__) @@ -20,12 +21,16 @@ LOG = logging.getLogger(__name__) DEFAULT_CLUSTERING_API_VERSION = '1' API_VERSION_OPTION = 'os_clustering_api_version' API_NAME = 'clustering' +CURRENT_API_VERSION = '1.2' def make_client(instance): """Returns a clustering proxy""" + prof = profile.Profile() + prof.set_api_version(API_NAME, CURRENT_API_VERSION) - conn = connection.Connection(authenticator=instance.session.auth) + conn = connection.Connection(profile=prof, + authenticator=instance.session.auth) LOG.debug('Connection: %s', conn) LOG.debug('Clustering client initialized using OpenStackSDK: %s', conn.cluster) diff --git a/senlinclient/shell.py b/senlinclient/shell.py index ea40849..ecc129d 100644 --- a/senlinclient/shell.py +++ b/senlinclient/shell.py @@ -235,8 +235,8 @@ class SenlinShell(object): 'trust_id': args.trust_id, } - return senlin_client.Client('1', args.user_preferences, USER_AGENT, - **kwargs) + return senlin_client.Client('1', prof=args.user_preferences, + user_agent=USER_AGENT, **kwargs) def main(self, argv): # Parse args once to find version diff --git a/senlinclient/tests/unit/test_shell.py b/senlinclient/tests/unit/test_shell.py index e0eb883..9c27990 100644 --- a/senlinclient/tests/unit/test_shell.py +++ b/senlinclient/tests/unit/test_shell.py @@ -366,8 +366,8 @@ class ShellTest(testtools.TestCase): mock_conn.return_value = conn conn.session = mock.Mock() sh._setup_senlin_client('1', args) - mock_conn.assert_called_once_with(args.user_preferences, USER_AGENT, - **kwargs) + mock_conn.assert_called_once_with(prof=args.user_preferences, + user_agent=USER_AGENT, **kwargs) client = mock.Mock() senlin_client.Client = mock.MagicMock(return_value=client) self.assertEqual(client, sh._setup_senlin_client('1', args)) diff --git a/senlinclient/tests/unit/v1/test_client.py b/senlinclient/tests/unit/v1/test_client.py index 605300a..a12eb76 100644 --- a/senlinclient/tests/unit/v1/test_client.py +++ b/senlinclient/tests/unit/v1/test_client.py @@ -33,16 +33,17 @@ class ClientTest(testtools.TestCase): self.assertEqual(self.conn, sc.conn) self.assertEqual(self.service, sc.service) - mock_conn.assert_called_once_with(None, None) + mock_conn.assert_called_once_with(prof=None, user_agent=None) def test_init_with_params(self, mock_conn): mock_conn.return_value = self.conn - sc = client.Client(preferences='FOO', user_agent='BAR', zoo='LARR') + sc = client.Client(prof='FOO', user_agent='BAR', zoo='LARR') self.assertEqual(self.conn, sc.conn) self.assertEqual(self.service, sc.service) - mock_conn.assert_called_once_with('FOO', 'BAR', zoo='LARR') + mock_conn.assert_called_once_with(prof='FOO', user_agent='BAR', + zoo='LARR') def test_profile_types(self, mock_conn): mock_conn.return_value = self.conn diff --git a/senlinclient/tests/unit/v1/test_cluster.py b/senlinclient/tests/unit/v1/test_cluster.py index 3bba71f..98bfe7f 100644 --- a/senlinclient/tests/unit/v1/test_cluster.py +++ b/senlinclient/tests/unit/v1/test_cluster.py @@ -798,3 +798,38 @@ class TestClusterRecover(TestCluster): error = self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) self.assertIn('Cluster not found: cluster1', str(error)) + + +class TestClusterCollect(TestCluster): + response = [ + { + "node_id": "8bb476c3-0f4c-44ee-9f64-c7b0260814de", + "attr_value": "value 1", + }, + { + "node_id": "7d85f602-a948-4a30-afd4-e84f47471c15", + "attr_value": "value 2", + } + ] + + def setUp(self): + super(TestClusterCollect, self).setUp() + self.cmd = osc_cluster.ClusterCollect(self.app, None) + self.mock_client.collect_cluster_attrs = mock.Mock( + return_value=self.response) + + def test_cluster_collect(self): + arglist = ['--path', 'path.to.attr', 'cluster1'] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, data = self.cmd.take_action(parsed_args) + self.mock_client.collect_cluster_attrs.assert_called_once_with( + 'cluster1', 'path.to.attr') + self.assertEqual(['node_id', 'attr_value'], columns) + + def test_cluster_collect_with_full_id(self): + arglist = ['--path', 'path.to.attr', '--full-id', 'cluster1'] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, data = self.cmd.take_action(parsed_args) + self.mock_client.collect_cluster_attrs.assert_called_once_with( + 'cluster1', 'path.to.attr') + self.assertEqual(['node_id', 'attr_value'], columns) diff --git a/senlinclient/tests/unit/v1/test_shell.py b/senlinclient/tests/unit/v1/test_shell.py index b5cc399..8919d25 100644 --- a/senlinclient/tests/unit/v1/test_shell.py +++ b/senlinclient/tests/unit/v1/test_shell.py @@ -1057,6 +1057,65 @@ class ShellTest(testtools.TestCase): service.recover_cluster.assert_called_once_with('cluster1') + def test_do_cluster_collect(self): + service = mock.Mock() + args = self._make_args({ + 'path': 'path.to.attr', + 'list': False, + 'full_id': False, + 'id': 'cluster1' + }) + service.collect_cluster_attrs = mock.Mock( + return_value=[mock.Mock(node_id='FAKE1', attr_value='VALUE1')] + ) + + sh.do_cluster_collect(service, args) + + service.collect_cluster_attrs.assert_called_once_with( + 'cluster1', 'path.to.attr') + + @mock.patch.object(utils, 'print_list') + def test_do_cluster_collect_as_list(self, mock_print): + service = mock.Mock() + args = self._make_args({ + 'path': 'path.to.attr', + 'list': True, + 'full_id': True, + 'id': 'cluster1' + }) + attrs = [mock.Mock(node_id='FAKE1', attr_value='VALUE1')] + fields = ['node_id', 'attr_value'] + formatters = {'attr_value': utils.json_formatter} + service.collect_cluster_attrs = mock.Mock(return_value=attrs) + + sh.do_cluster_collect(service, args) + + service.collect_cluster_attrs.assert_called_once_with( + 'cluster1', 'path.to.attr') + mock_print.assert_called_once_with(attrs, fields, + formatters=formatters) + + @mock.patch.object(utils, 'print_list') + def test_do_cluster_collect_as_list_with_shortid(self, mock_print): + service = mock.Mock() + args = self._make_args({ + 'path': 'path.to.attr', + 'list': True, + 'full_id': False, + 'id': 'cluster1' + }) + attrs = [mock.Mock(node_id='FAKE1', attr_value='VALUE1')] + fields = ['node_id', 'attr_value'] + formatters = {'node_id': mock.ANY, 'attr_value': utils.json_formatter} + service.collect_cluster_attrs = mock.Mock(return_value=attrs) + + sh.do_cluster_collect(service, args) + + service.collect_cluster_attrs.assert_called_once_with( + 'cluster1', 'path.to.attr') + mock_print.assert_called_once_with(attrs, fields, + formatters=formatters) + @mock.patch.object(utils, 'print_list') def test_do_node_list(self, mock_print): service = mock.Mock() diff --git a/senlinclient/v1/client.py b/senlinclient/v1/client.py index 444dfe7..5054014 100644 --- a/senlinclient/v1/client.py +++ b/senlinclient/v1/client.py @@ -15,8 +15,9 @@ from senlinclient.common import sdk class Client(object): - def __init__(self, preferences=None, user_agent=None, **kwargs): - self.conn = sdk.create_connection(preferences, user_agent, **kwargs) + def __init__(self, prof=None, user_agent=None, **kwargs): + self.conn = sdk.create_connection(prof=prof, user_agent=user_agent, + **kwargs) self.service = self.conn.cluster ###################################################################### diff --git a/senlinclient/v1/cluster.py b/senlinclient/v1/cluster.py index 5a3a52f..42ad22b 100644 --- a/senlinclient/v1/cluster.py +++ b/senlinclient/v1/cluster.py @@ -766,3 +766,44 @@ class RecoverCluster(command.Command): print('Cluster recover request on cluster %(cid)s is accepted by ' 'action %(action)s.' % {'cid': cid, 'action': resp['action']}) + + +class ClusterCollect(command.Lister): + """Recover the cluster(s).""" + log = logging.getLogger(__name__ + ".ClusterCollect") + + def get_parser(self, prog_name): + parser = super(ClusterCollect, self).get_parser(prog_name) + parser.add_argument( + '--full-id', + default=False, + action="store_true", + help=_('Print full IDs in list') + ) + parser.add_argument( + '--path', + metavar='', + required=True, + help=_('JSON path expression for attribute to be collected') + ) + parser.add_argument( + 'cluster', + metavar='', + help=_('ID or name of cluster(s) to operate on.') + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + senlin_client = self.app.client_manager.clustering + attrs = senlin_client.collect_cluster_attrs(parsed_args.cluster, + parsed_args.path) + columns = ['node_id', 'attr_value'] + formatters = {} + if not parsed_args.full_id: + formatters = { + 'node_id': lambda x: x[:8] + } + return (columns, + (utils.get_item_properties(a, columns, formatters=formatters) + for a in attrs)) diff --git a/senlinclient/v1/shell.py b/senlinclient/v1/shell.py index f3a86b4..48152bf 100644 --- a/senlinclient/v1/shell.py +++ b/senlinclient/v1/shell.py @@ -504,11 +504,11 @@ def do_cluster_collect(service, args): """Collect attributes across a cluster.""" show_deprecated('senlin cluster-collect', 'openstack cluster collect') - attrs = service.cluster_collect(args.id, args.path) + attrs = service.collect_cluster_attrs(args.id, args.path) if args.list: - fields = ['node_id', 'value'] + fields = ['node_id', 'attr_value'] formatters = { - 'value': utils.json_formatter + 'attr_value': utils.json_formatter } if not args.full_id: formatters['node_id'] = lambda x: x.node_id[:8] diff --git a/setup.cfg b/setup.cfg index 3f4141c..86f9589 100644 --- a/setup.cfg +++ b/setup.cfg @@ -78,6 +78,7 @@ openstack.clustering.v1 = cluster_expand = senlinclient.v1.cluster:ScaleOutCluster cluster_show = senlinclient.v1.cluster:ShowCluster cluster_update = senlinclient.v1.cluster:UpdateCluster + cluster_collect = senlinclient.v1.cluster:ClusterCollect [global] setup-hooks =