From e9cb52ad55c2b5611d363a69211792e94a25700d Mon Sep 17 00:00:00 2001 From: dixiaoli Date: Wed, 17 Feb 2016 13:28:01 +0800 Subject: [PATCH] Add OpenstackClient plugin for cluster profile list This change implements the "openstack cluster profile list" command Based on the existing senlin command: senlin profile-list Change-Id: I7103a53a0caba7ec7e9f710e9a33bc183ec377e3 Blueprint: senlin-support-python-openstackclient --- senlinclient/osc/v1/profile.py | 68 ++++++++++++++ .../tests/unit/osc/v1/test_profile.py | 92 +++++++++++++++++++ setup.cfg | 1 + 3 files changed, 161 insertions(+) diff --git a/senlinclient/osc/v1/profile.py b/senlinclient/osc/v1/profile.py index 1fb27b56..b27cb007 100644 --- a/senlinclient/osc/v1/profile.py +++ b/senlinclient/osc/v1/profile.py @@ -14,11 +14,13 @@ import logging +from cliff import lister from cliff import show from openstack import exceptions as sdk_exc from openstackclient.common import exceptions as exc from openstackclient.common import utils +from senlinclient.common.i18n import _ from senlinclient.common import utils as senlin_utils @@ -70,3 +72,69 @@ def _show_profile(senlin_client, profile_id): ] return columns, utils.get_dict_properties(data.to_dict(), columns, formatters=formatters) + + +class ListProfile(lister.Lister): + """List profiles that meet the criteria.""" + + log = logging.getLogger(__name__ + ".ListProfile") + + def get_parser(self, prog_name): + parser = super(ListProfile, self).get_parser(prog_name) + parser.add_argument( + '--limit', + metavar='', + help=_('Limit the number of profiles returned.') + ) + parser.add_argument( + '--marker', + metavar='', + help=_('Only return profiles that appear after the given ID.') + ) + parser.add_argument( + '--sort', + metavar='', + help=_("Sorting option which is a string containing a list of keys" + " separated by commas. Each key can be optionally appended " + "by a sort direction (:asc or :desc). The valid sort_keys " + "are:['type', 'name', 'created_at', 'updated_at']") + ) + parser.add_argument( + '--global-project', + default=False, + action="store_true", + help=_('Indicate that the list should include profiles from' + ' all projects. This option is subject to access policy ' + 'checking. Default is False.') + ) + parser.add_argument( + '--full-id', + default=False, + action="store_true", + help=_('Print full IDs in list.') + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + + senlin_client = self.app.client_manager.clustering + + columns = ['id', 'name', 'type', 'created_at'] + queries = { + 'limit': parsed_args.limit, + 'marker': parsed_args.marker, + 'sort': parsed_args.sort, + 'global_project': parsed_args.global_project, + } + data = senlin_client.profiles(**queries) + formatters = {} + if not parsed_args.full_id: + formatters = { + 'id': lambda x: x[:8], + } + return ( + columns, + (utils.get_item_properties(p, columns, formatters=formatters) + for p in data) + ) diff --git a/senlinclient/tests/unit/osc/v1/test_profile.py b/senlinclient/tests/unit/osc/v1/test_profile.py index 4676b969..70811dd3 100644 --- a/senlinclient/tests/unit/osc/v1/test_profile.py +++ b/senlinclient/tests/unit/osc/v1/test_profile.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import copy import mock from openstack.cluster.v1 import profile as sdk_profile @@ -107,3 +108,94 @@ class TestProfileShow(TestProfile): exc.CommandError, self.cmd.take_action, parsed_args) + + +class TestProfileList(TestProfile): + columns = ['id', 'name', 'type', 'created_at'] + data = {"profiles": [ + { + "created_at": "2016-02-17T13:01:05", + "domain": None, + "id": "757347e0-6526-4a77-a16d-e099fecde123", + "metadata": {}, + "name": "my_profile", + "project": "5f1cc92b578e4e25a3b284179cf20a9b", + "spec": { + "properties": { + "flavor": 1, + "name": "cirros_server" + }, + "type": "os.nova.server", + "version": 1 + }, + "type": "os.nova.server-1.0", + "updated_at": None, + "user": "2d7aca950f3e465d8ef0c81720faf6ff" + } + ]} + defaults = { + 'limit': None, + 'marker': None, + 'sort': None, + 'global_project': False, + } + + def setUp(self): + super(TestProfileList, self).setUp() + self.cmd = osc_profile.ListProfile(self.app, None) + self.mock_client.profiles = mock.Mock( + return_value=sdk_profile.Profile(None, {})) + + def test_profile_list_defaults(self): + arglist = [] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, data = self.cmd.take_action(parsed_args) + self.mock_client.profiles.assert_called_with(**self.defaults) + self.assertEqual(self.columns, columns) + + def test_profile_list_full_id(self): + arglist = ['--full-id'] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, data = self.cmd.take_action(parsed_args) + self.mock_client.profiles.assert_called_with(**self.defaults) + self.assertEqual(self.columns, columns) + + def test_profile_list_limit(self): + kwargs = copy.deepcopy(self.defaults) + kwargs['limit'] = '3' + arglist = ['--limit', '3'] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, data = self.cmd.take_action(parsed_args) + self.mock_client.profiles.assert_called_with(**kwargs) + self.assertEqual(self.columns, columns) + + def test_profile_list_sort(self): + kwargs = copy.deepcopy(self.defaults) + kwargs['sort'] = 'id:asc' + arglist = ['--sort', 'id:asc'] + parsed_args = self.check_parser(self.cmd, arglist, []) + columns, data = self.cmd.take_action(parsed_args) + self.mock_client.profiles.assert_called_with(**kwargs) + self.assertEqual(self.columns, columns) + + def test_profile_list_sort_invalid_key(self): + self.mock_client.profiles = mock.Mock( + return_value=self.data) + kwargs = copy.deepcopy(self.defaults) + kwargs['sort'] = 'bad_key' + arglist = ['--sort', 'bad_key'] + parsed_args = self.check_parser(self.cmd, arglist, []) + self.mock_client.profiles.side_effect = sdk_exc.HttpException() + self.assertRaises(sdk_exc.HttpException, + self.cmd.take_action, parsed_args) + + def test_profile_list_sort_invalid_direction(self): + self.mock_client.profiles = mock.Mock( + return_value=self.data) + kwargs = copy.deepcopy(self.defaults) + kwargs['sort'] = 'id:bad_direction' + arglist = ['--sort', 'id:bad_direction'] + parsed_args = self.check_parser(self.cmd, arglist, []) + self.mock_client.profiles.side_effect = sdk_exc.HttpException() + self.assertRaises(sdk_exc.HttpException, + self.cmd.take_action, parsed_args) diff --git a/setup.cfg b/setup.cfg index 1431aae9..acd1622d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,6 +30,7 @@ openstack.cli.extension = clustering = senlinclient.osc.plugin openstack.clustering.v1 = + cluster_profile_list = senlinclient.osc.v1.profile:ListProfile cluster_profile_show = senlinclient.osc.v1.profile:ShowProfile [global]