diff --git a/bileanclient/__init__.py b/bileanclient/__init__.py index c123570..bfdfc94 100644 --- a/bileanclient/__init__.py +++ b/bileanclient/__init__.py @@ -21,11 +21,10 @@ from bileanclient import client from bileanclient import exc as exceptions -__version__ = "1.0" -# __version__ = pbr.version.VersionInfo('python-bileanclient').version_string() +__version__ = pbr.version.VersionInfo('python-bileanclient').version_string() __all__ = [ - 'client', - 'exc', - 'exceptions', + 'client', + 'exc', + 'exceptions', ] diff --git a/bileanclient/v1/client.py b/bileanclient/v1/client.py index 6ebd7cd..d40a832 100644 --- a/bileanclient/v1/client.py +++ b/bileanclient/v1/client.py @@ -19,8 +19,7 @@ from bileanclient.common import http from bileanclient.v1 import policies from bileanclient.v1 import rules from bileanclient.v1 import users -#from bileanclient.v1 import bilean_resource -#from bileanclient.v1 import event +from bileanclient.v1 import resources class Client(object): @@ -39,5 +38,4 @@ class Client(object): self.users = users.UserManager(self.http_client) self.rules = rules.RuleManager(self.http_client) self.policies = policies.PolicyManager(self.http_client) - #self.resource = bilean_resource.ResourceManager(self.http_client) - #self.event = event.EventManager(self.http_client) + self.resources = resources.ResourceManager(self.http_client) diff --git a/bileanclient/v1/resources.py b/bileanclient/v1/resources.py new file mode 100644 index 0000000..948a776 --- /dev/null +++ b/bileanclient/v1/resources.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import six +from six.moves.urllib import parse + +from bileanclient.openstack.common.apiclient import base + + +class BileanResource(base.Resource): + def __repr__(self): + return "" % self._info + + +class ResourceManager(base.BaseManager): + resource_class = BileanResource + + def list(self, **kwargs): + """Retrieve a list of resources. + + :rtype: list of :class:`Resource`. + """ + def paginate(params): + '''Paginate resources, even if more than API limit.''' + current_limit = int(params.get('limit') or 0) + url = '/resources?%s' % parse.urlencode(params, True) + resources = self._list(url, 'resources') + for resource in resources: + yield resource + + num_resources = len(resources) + remaining_limit = current_limit - num_resources + if remaining_limit > 0 and num_resources > 0: + params['limit'] = remaining_limit + params['marker'] = resource.id + for resource in paginate(params): + yield resource + + params = {} + if 'filters' in kwargs: + filters = kwargs.pop('filters') + params.update(filters) + + for key, value in six.iteritems(kwargs): + if value: + params[key] = value + + return paginate(params) + + def get(self, resource_id): + """Get the details for a specific resource. + + :param resource_id: ID of the resource + """ + return self._get('/resources/%s' % resource_id, 'resource') diff --git a/bileanclient/v1/shell.py b/bileanclient/v1/shell.py index d436b9e..5a30a16 100644 --- a/bileanclient/v1/shell.py +++ b/bileanclient/v1/shell.py @@ -33,7 +33,7 @@ def do_user_show(bc, args): formatters = { 'status_reason': utils.text_wrap_formatter, } - utils.print_dict(user.to_dict(), formatters=formatters) + utils.print_dict(user.to_dict(), formatters=formatters) @utils.arg('-s', '--show-deleted', default=False, action="store_true", @@ -112,7 +112,7 @@ def do_user_recharge(bc, args): formatters = { 'status_reason': utils.text_wrap_formatter, } - utils.print_dict(user.to_dict(), formatters=formatters) + utils.print_dict(user.to_dict(), formatters=formatters) @utils.arg('id', @@ -132,7 +132,7 @@ def do_user_attach_policy(bc, args): formatters = { 'status_reason': utils.text_wrap_formatter, } - utils.print_dict(user.to_dict(), formatters=formatters) + utils.print_dict(user.to_dict(), formatters=formatters) @utils.arg('-s', '--show-deleted', default=False, action="store_true", @@ -155,7 +155,6 @@ def do_user_attach_policy(bc, args): @utils.arg('-d', '--sort-dir', metavar='[asc|desc]', help=_('Sorting direction (either "asc" or "desc") for the sorting ' 'keys.')) - def do_rule_list(bc, args): """List rules.""" kwargs = {} @@ -217,7 +216,7 @@ def do_rule_create(bc, args): raise exc.CommandError(_("Missing 'properties' key in spec file.")) params = { - 'rule': { + 'rule': { 'name': args.name, 'spec': spec, 'metadata': utils.format_parameters(args.metadata), @@ -245,7 +244,7 @@ def do_rule_delete(bc, args): try: bc.rules.delete(rid) except Exception as ex: - failure_count +=1 + failure_count += 1 print(ex) if failure_count > 0: msg = _('Failed to delete some of the specified rule(s).') @@ -281,7 +280,8 @@ def _show_rule(bc, rule=None, rule_id=None): @utils.arg('-l', '--limit', metavar='', help=_('Limit the number of policies returned.')) @utils.arg('-m', '--marker', metavar='', - help=_('Only return policies that appear after the given policy ID.')) + help=_('Only return policies that appear after the given ' + 'policy ID.')) @utils.arg('-k', '--sort-keys', metavar='', help=_('List of keys for sorting the returned policies. ' 'This can be specified multiple times or once with keys ' @@ -291,7 +291,6 @@ def _show_rule(bc, rule=None, rule_id=None): @utils.arg('-d', '--sort-dir', metavar='[asc|desc]', help=_('Sorting direction (either "asc" or "desc") for the sorting ' 'keys.')) - def do_policy_list(bc, args): """List policies.""" kwargs = {} @@ -341,7 +340,7 @@ def do_policy_list(bc, args): def do_policy_create(bc, args): """Create a policy.""" params = { - 'policy': { + 'policy': { 'name': args.name, 'rules': args.rule, 'metadata': utils.format_parameters(args.metadata), @@ -381,3 +380,77 @@ def _show_policy(bc, policy=None, policy_id=None): def do_policy_show(bc, args): """Show the policy details.""" _show_policy(bc, policy_id=args.id) + + +@utils.arg('-s', '--show-deleted', default=False, action="store_true", + help=_('Include soft-deleted resources in the resource listing.')) +@utils.arg('-f', '--filters', metavar='', + help=_('Filter parameters to apply on returned resources. ' + 'This can be specified multiple times, or once with ' + 'parameters separated by a semicolon.'), + action='append') +@utils.arg('-l', '--limit', metavar='', + help=_('Limit the number of resources returned.')) +@utils.arg('-m', '--marker', metavar='', + help=_('Only return resources that appear after the ' + 'given resource ID.')) +@utils.arg('-k', '--sort-keys', metavar='', + help=_('List of keys for sorting the returned resources. ' + 'This can be specified multiple times or once with keys ' + 'separated by semicolons. Valid sorting keys include ' + '"user_id", "resource_type", "created_at", "updated_at".'), + action='append') +@utils.arg('-d', '--sort-dir', metavar='[asc|desc]', + help=_('Sorting direction (either "asc" or "desc") for the sorting ' + 'keys.')) +def do_resource_list(bc, args): + """List resources.""" + kwargs = {} + fields = ['id', 'user_id', 'resource_type', 'rule_id'] + sort_keys = ['user_id', 'resource_type', 'created_at', 'updated_at'] + + sortby_index = 3 + if args: + kwargs = {'limit': args.limit, + 'marker': args.marker, + 'filters': utils.format_parameters(args.filters), + 'show_deleted': args.show_deleted} + + if args.sort_keys: + keys = [] + for k in args.sort_keys: + if ';' in k: + keys.extend(k.split(';')) + else: + keys.append(k) + for key in keys: + if key not in sort_keys: + err = _("Sorting key '%(key)s' not one of the supported " + "keys: %(keys)s") % {'key': key, "keys": sort_keys} + raise exc.CommandError(err) + kwargs['sort_keys'] = keys + sortby_index = None + + if args.sort_dir: + if args.sort_dir not in ('asc', 'desc'): + raise exc.CommandError(_("Sorting direction must be one of " + "'asc' and 'desc'")) + kwargs['sort_dir'] = args.sort_dir + + resources = bc.resources.list(**kwargs) + utils.print_list(resources, fields, sortby_index=sortby_index) + + +@utils.arg('id', metavar='', help="ID of resource to show.") +def do_resource_show(bc, args): + """Show detailed information for a resource.""" + fields = {'resource_id': args.id} + try: + resource = bc.resources.get(**fields) + except exc.HTTPNotFound: + raise exc.CommandError(_('Resource not found: %s') % args.id) + else: + formatters = { + 'properties': utils.json_formatter, + } + utils.print_dict(resource.to_dict(), formatters=formatters) diff --git a/bileanclient/v1/users.py b/bileanclient/v1/users.py index 03fcf42..3b24b00 100644 --- a/bileanclient/v1/users.py +++ b/bileanclient/v1/users.py @@ -17,7 +17,6 @@ import six from six.moves.urllib import parse -from bileanclient.common import utils from bileanclient.openstack.common.apiclient import base diff --git a/tox.ini b/tox.ini index 9d042b6..d62fbbe 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,6 @@ usedevelop = True install_command = pip install -U {opts} {packages} setenv = VIRTUAL_ENV={envdir} -install_command = pip install -U {opts} {packages} deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt @@ -23,8 +22,7 @@ deps = setuptools<3.2 [testenv:pep8] commands = - flake8 {posargs} - {toxinidir}/tools/requirements_style_check.sh requirements.txt test-requirements.txt + flake8 [testenv:cover] setenv = VIRTUAL_ENV={envdir}