diff --git a/manilaclient/client.py b/manilaclient/client.py index 1221ee93e..f713a131c 100644 --- a/manilaclient/client.py +++ b/manilaclient/client.py @@ -41,9 +41,9 @@ if not hasattr(urlparse, 'parse_qsl'): import requests from manilaclient import exceptions +from manilaclient.openstack.common import importutils from manilaclient.openstack.common import jsonutils from manilaclient import service_catalog -from manilaclient import utils class HTTPClient(object): @@ -417,7 +417,7 @@ def get_client_class(version): (version, ', '.join(version_map))) raise exceptions.UnsupportedVersion(msg) - return utils.import_class(client_path) + return importutils.import_class(client_path) def Client(version, *args, **kwargs): diff --git a/manilaclient/shell.py b/manilaclient/shell.py index 7d40e1f50..2b8664e43 100644 --- a/manilaclient/shell.py +++ b/manilaclient/shell.py @@ -36,6 +36,7 @@ import six from manilaclient import client from manilaclient import exceptions as exc import manilaclient.extension +from manilaclient.openstack.common import cliutils from manilaclient.openstack.common import strutils from manilaclient import utils from manilaclient.v1 import shell as shell_v1 @@ -547,12 +548,12 @@ class OpenStackManilaShell(object): if not service_type: service_type = DEFAULT_MANILA_SERVICE_TYPE - service_type = utils.get_service_type(args.func) or service_type + service_type = cliutils.get_service_type(args.func) or service_type # FIXME(usrleon): Here should be restrict for project id same as # for os_username or os_password but for compatibility it is not. - if not utils.isunauthenticated(args.func): + if not cliutils.isunauthenticated(args.func): if not os_username: raise exc.CommandError( "You must provide a username " @@ -591,7 +592,7 @@ class OpenStackManilaShell(object): http_log_debug=args.debug, cacert=cacert, os_cache=os_cache) - if not utils.isunauthenticated(args.func): + if not cliutils.isunauthenticated(args.func): helper = SecretsHelper(args, self.cs.client) if os_reset_cache: helper.reset() diff --git a/manilaclient/utils.py b/manilaclient/utils.py index 40950ae9a..6471d6d8c 100644 --- a/manilaclient/utils.py +++ b/manilaclient/utils.py @@ -14,12 +14,10 @@ from __future__ import print_function import os import sys -import uuid import prettytable import six -from manilaclient import exceptions from manilaclient.openstack.common import strutils @@ -58,87 +56,6 @@ def add_arg(f, *args, **kwargs): f.arguments.insert(0, (args, kwargs)) -def add_resource_manager_extra_kwargs_hook(f, hook): - """Adds hook to bind CLI arguments to ResourceManager calls. - - The `do_foo` calls in shell.py will receive CLI args and then in turn pass - them through to the ResourceManager. Before passing through the args, the - hooks registered here will be called, giving us a chance to add extra - kwargs (taken from the command-line) to what's passed to the - ResourceManager. - """ - if not hasattr(f, 'resource_manager_kwargs_hooks'): - f.resource_manager_kwargs_hooks = [] - - names = [h.__name__ for h in f.resource_manager_kwargs_hooks] - if hook.__name__ not in names: - f.resource_manager_kwargs_hooks.append(hook) - - -def get_resource_manager_extra_kwargs(f, args, allow_conflicts=False): - """Return extra_kwargs by calling resource manager kwargs hooks.""" - hooks = getattr(f, "resource_manager_kwargs_hooks", []) - extra_kwargs = {} - for hook in hooks: - hook_name = hook.__name__ - hook_kwargs = hook(args) - - conflicting_keys = set(list(hook_kwargs)) & set(list(extra_kwargs)) - if conflicting_keys and not allow_conflicts: - msg = ("Hook '%s' is attempting to redefine " - "attributes '%s'" % (hook_name, conflicting_keys)) - raise Exception(msg) - - extra_kwargs.update(hook_kwargs) - - return extra_kwargs - - -def unauthenticated(f): - """Adds 'unauthenticated' attribute to decorated function. - - Usage: - @unauthenticated - def mymethod(f): - ... - """ - f.unauthenticated = True - return f - - -def isunauthenticated(f): - """Verifies whether function requires authentication or not. - - Checks to see if the function is marked as not requiring authentication - with the @unauthenticated decorator. - Returns True if decorator is set to True, False otherwise. - """ - return getattr(f, 'unauthenticated', False) - - -def service_type(stype): - """Adds 'service_type' attribute to decorated function. - - Usage: - @service_type('share') - def mymethod(f): - ... - """ - def inner(f): - f.service_type = stype - return f - return inner - - -def get_service_type(f): - """Retrieves service type from function.""" - return getattr(f, 'service_type', None) - - -def pretty_choice_list(l): - return ', '.join("'%s'" % i for i in l) - - def _print(pt, order): if sys.version_info >= (3, 0): print(pt.get_string(sortby=order)) @@ -146,6 +63,8 @@ def _print(pt, order): print(strutils.safe_encode(pt.get_string(sortby=order))) +# NOTE(vponomaryov): replace function 'print_list' and 'print_dict' +# with functions from cliutils, when bug #1342050 is fixed def print_list(objs, fields, formatters={}, order_by=None): mixed_case_fields = ['serverId'] pt = prettytable.PrettyTable([f for f in fields], caching=False) @@ -178,70 +97,6 @@ def print_dict(d, property="Property"): _print(pt, property) -def find_resource(manager, name_or_id): - """Helper for the _find_* methods.""" - # first try to get entity as integer id - try: - if isinstance(name_or_id, int) or name_or_id.isdigit(): - return manager.get(int(name_or_id)) - except exceptions.NotFound: - pass - - if sys.version_info <= (3, 0): - name_or_id = strutils.safe_decode(name_or_id) - - # now try to get entity as uuid - try: - uuid.UUID(name_or_id) - return manager.get(name_or_id) - except (ValueError, exceptions.NotFound): - pass - - try: - try: - return manager.find(human_id=name_or_id) - except exceptions.NotFound: - pass - - # finally try to find entity by name - try: - return manager.find(name=name_or_id) - except exceptions.NotFound: - try: - return manager.find(display_name=name_or_id) - except (UnicodeDecodeError, exceptions.NotFound): - try: - # Volumes does not have name, but display_name - return manager.find(display_name=name_or_id) - except exceptions.NotFound: - msg = ("No %s with a name or ID of '%s' exists." % - (manager.resource_class.__name__.lower(), - name_or_id)) - raise exceptions.CommandError(msg) - except exceptions.NoUniqueMatch: - msg = ("Multiple %s matches found for '%s', use an ID to be more" - " specific." % (manager.resource_class.__name__.lower(), - name_or_id)) - raise exceptions.CommandError(msg) - - -def find_share(cs, share): - """Get a share by name or ID.""" - return find_resource(cs.shares, share) - - -def _format_servers_list_networks(server): - output = [] - for (network, addresses) in list(server.networks.items()): - if len(addresses) == 0: - continue - addresses_csv = ', '.join(addresses) - group = "%s=%s" % (network, addresses_csv) - output.append(group) - - return '; '.join(output) - - class HookableMixin(object): """Mixin so classes can register and run hooks.""" _hooks_map = {} @@ -270,25 +125,3 @@ def safe_issubclass(*args): pass return False - - -def import_class(import_str): - """Returns a class from a string including module and class.""" - mod_str, _sep, class_str = import_str.rpartition('.') - __import__(mod_str) - return getattr(sys.modules[mod_str], class_str) - - -def make_metadata_dict(metadata): - """Converts cli key=value data to python dict as {'key': 'value'}.""" - metadata_dict = {} - for item in metadata: - try: - key, value = item.split('=') - except ValueError: - msg = "Wrong argument format: '%s'" % item - raise exceptions.CommandError(msg) - if 'password' in key: - value = value.strip('"').strip("'") - metadata_dict[key] = value - return metadata_dict diff --git a/manilaclient/v1/contrib/list_extensions.py b/manilaclient/v1/contrib/list_extensions.py index f22f2ae70..5b4aff110 100644 --- a/manilaclient/v1/contrib/list_extensions.py +++ b/manilaclient/v1/contrib/list_extensions.py @@ -15,6 +15,7 @@ from manilaclient import base from manilaclient.openstack.common.apiclient import base as common_base +from manilaclient.openstack.common import cliutils from manilaclient import utils @@ -38,7 +39,7 @@ class ListExtManager(base.Manager): return self._list("/extensions", 'extensions') -@utils.service_type('share') +@cliutils.service_type('share') def do_list_extensions(client, _args): """List all the os-api extensions that are available.""" extensions = client.list_extensions.show_all() diff --git a/manilaclient/v1/shell.py b/manilaclient/v1/shell.py index 816d8880c..e86bc0a6d 100644 --- a/manilaclient/v1/shell.py +++ b/manilaclient/v1/shell.py @@ -20,6 +20,7 @@ import sys import time from manilaclient import exceptions +from manilaclient.openstack.common import cliutils from manilaclient import utils from manilaclient.v1 import quotas @@ -56,7 +57,7 @@ def _poll_for_status(poll_fn, obj_id, action, final_ok_states, def _find_share(cs, share): """Get a share by ID.""" - return utils.find_resource(cs.shares, share) + return cliutils.find_resource(cs.shares, share) def _print_share(cs, share): @@ -66,7 +67,7 @@ def _print_share(cs, share): def _find_share_snapshot(cs, snapshot): """Get a snapshot by ID.""" - return utils.find_resource(cs.share_snapshots, snapshot) + return cliutils.find_resource(cs.share_snapshots, snapshot) def _print_share_snapshot(cs, snapshot): @@ -77,7 +78,7 @@ def _print_share_snapshot(cs, snapshot): def _find_share_network(cs, share_network): "Get a share network by ID or name." - return utils.find_resource(cs.share_networks, share_network) + return cliutils.find_resource(cs.share_networks, share_network) def _translate_keys(collection, convert): @@ -203,7 +204,7 @@ def do_quota_defaults(cs, args): default=None, help='Whether force update the quota even if the already used' ' and reserved exceeds the new quota') -@utils.service_type('share') +@cliutils.service_type('share') def do_quota_update(cs, args): """Update the quotas for a tenant/user.""" @@ -231,7 +232,7 @@ def do_quota_delete(cs, args): @utils.arg('class_name', metavar='', help='Name of quota class to list the quotas for.') -@utils.service_type('share') +@cliutils.service_type('share') def do_quota_class_show(cs, args): """List the quotas for a quota class.""" @@ -257,14 +258,14 @@ def do_quota_class_show(cs, args): metavar='', type=int, default=None, help='New value for the "share_networks" quota.') -@utils.service_type('share') +@cliutils.service_type('share') def do_quota_class_update(cs, args): """Update the quotas for a quota class.""" _quota_update(cs.quota_classes, args.class_name, args) -@utils.service_type('share') +@cliutils.service_type('share') def do_absolute_limits(cs, args): """Print a list of absolute limits for a user.""" limits = cs.limits.get().absolute @@ -272,7 +273,7 @@ def do_absolute_limits(cs, args): utils.print_list(limits, columns) -@utils.service_type('share') +@cliutils.service_type('share') def do_rate_limits(cs, args): """Print a list of rate limits for a user.""" limits = cs.limits.get().rate @@ -321,7 +322,7 @@ def do_rate_limits(cs, args): metavar='', help='Optional volume type. (Default=None)', default=None) -@utils.service_type('share') +@cliutils.service_type('share') def do_create(cs, args): """Creates new NAS storage (NFS or CIFS).""" @@ -352,10 +353,10 @@ def do_create(cs, args): nargs='+', default=[], help='Metadata to set/unset (only key is necessary on unset)') -@utils.service_type('share') +@cliutils.service_type('share') def do_metadata(cs, args): """Set or Delete metadata on a share.""" - share = utils.find_share(cs, args.share) + share = _find_share(cs, args.share) metadata = _extract_metadata(args) if args.action == 'set': @@ -366,10 +367,10 @@ def do_metadata(cs, args): @utils.arg('share', metavar='', help='Name or ID of share') -@utils.service_type('share') +@cliutils.service_type('share') def do_metadata_show(cs, args): """Show metadata of given share.""" - share = utils.find_share(cs, args.share) + share = _find_share(cs, args.share) metadata = cs.shares.get_metadata(share)._info utils.print_dict(metadata, 'Metadata-property') @@ -382,10 +383,10 @@ def do_metadata_show(cs, args): nargs='+', default=[], help='Metadata entry/entries to update.') -@utils.service_type('share') +@cliutils.service_type('share') def do_metadata_update_all(cs, args): """Update all metadata of a share.""" - share = utils.find_share(cs, args.share) + share = _find_share(cs, args.share) metadata = _extract_metadata(args) metadata = share.update_all_metadata(metadata)._info['metadata'] utils.print_dict(metadata, 'Metadata-property') @@ -432,7 +433,7 @@ def do_force_delete(cs, args): 'share', metavar='', help='Name or ID of the NAS share.') -@utils.service_type('share') +@cliutils.service_type('share') def do_show(cs, args): """Show details about a NAS share.""" share = _find_share(cs, args.share) @@ -452,7 +453,7 @@ def do_show(cs, args): 'access_to', metavar='', help='Value that defines access') -@utils.service_type('share') +@cliutils.service_type('share') def do_access_allow(cs, args): """Allow access to the share.""" share = _find_share(cs, args.share) @@ -468,7 +469,7 @@ def do_access_allow(cs, args): 'id', metavar='', help='id of the access rule to be deleted.') -@utils.service_type('share') +@cliutils.service_type('share') def do_access_deny(cs, args): """Deny access to a share.""" share = _find_share(cs, args.share) @@ -479,7 +480,7 @@ def do_access_deny(cs, args): 'share', metavar='', help='Name or ID of the share.') -@utils.service_type('share') +@cliutils.service_type('share') def do_access_list(cs, args): """Show access list for share.""" share = _find_share(cs, args.share) @@ -511,7 +512,7 @@ def do_access_list(cs, args): metavar='', default=None, help='Filter results by share-server id.') -@utils.service_type('share') +@cliutils.service_type('share') def do_list(cs, args): """List all NAS shares.""" all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants)) @@ -551,7 +552,7 @@ def do_list(cs, args): metavar='', default=None, help='Filter results by share-id') -@utils.service_type('share') +@cliutils.service_type('share') def do_snapshot_list(cs, args): """List all the snapshots.""" all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants)) @@ -570,7 +571,7 @@ def do_snapshot_list(cs, args): 'snapshot', metavar='', help='Name or ID of the snapshot.') -@utils.service_type('share') +@cliutils.service_type('share') def do_snapshot_show(cs, args): """Show details about a snapshot.""" snapshot = _find_share_snapshot(cs, args.snapshot) @@ -598,10 +599,10 @@ def do_snapshot_show(cs, args): metavar='', default=None, help='Optional snapshot description. (Default=None)') -@utils.service_type('share') +@cliutils.service_type('share') def do_snapshot_create(cs, args): """Add a new snapshot.""" - share = utils.find_share(cs, args.share) + share = _find_share(cs, args.share) snapshot = cs.share_snapshots.create(share, args.force, args.name, @@ -619,7 +620,7 @@ def do_snapshot_create(cs, args): @utils.arg('--description', metavar='', help='Optional share description. (Default=None)', default=None) -@utils.service_type('share') +@cliutils.service_type('share') def do_rename(cs, args): """Rename a share.""" kwargs = {} @@ -644,7 +645,7 @@ def do_rename(cs, args): @utils.arg('--description', metavar='', help='Optional snapshot description. (Default=None)', default=None) -@utils.service_type('share') +@cliutils.service_type('share') def do_snapshot_rename(cs, args): """Rename a snapshot.""" kwargs = {} @@ -663,7 +664,7 @@ def do_snapshot_rename(cs, args): 'snapshot', metavar='', help='Name or ID of the snapshot to delete.') -@utils.service_type('share') +@cliutils.service_type('share') def do_snapshot_delete(cs, args): """Remove a snapshot.""" snapshot = _find_share_snapshot(cs, args.snapshot) @@ -674,7 +675,7 @@ def do_snapshot_delete(cs, args): 'snapshot', metavar='', help='Name or ID of the snapshot to force delete.') -@utils.service_type('share') +@cliutils.service_type('share') def do_snapshot_force_delete(cs, args): """Attempts force-delete of snapshot, regardless of state.""" snapshot = _find_share_snapshot(cs, args.snapshot) @@ -689,7 +690,7 @@ def do_snapshot_force_delete(cs, args): 'Options include available, error, creating, deleting, ' 'error_deleting. If no state is provided, ' 'available will be used.')) -@utils.service_type('share') +@cliutils.service_type('share') def do_snapshot_reset_state(cs, args): """Explicitly update the state of a snapshot.""" snapshot = _find_share_snapshot(cs, args.snapshot) @@ -707,7 +708,7 @@ def do_snapshot_reset_state(cs, args): help=('Indicate which state to assign the share. Options include ' 'available, error, creating, deleting, error_deleting. If no ' 'state is provided, available will be used.')) -@utils.service_type('share') +@cliutils.service_type('share') def do_reset_state(cs, args): """Explicitly update the state of a share.""" share = _find_share(cs, args.share) @@ -1160,17 +1161,17 @@ def _print_type_and_extra_specs_list(vtypes): def _find_volume_type(cs, vtype): """Get a volume type by name or ID.""" - return utils.find_resource(cs.volume_types, vtype) + return cliutils.find_resource(cs.volume_types, vtype) -@utils.service_type('share') +@cliutils.service_type('share') def do_type_list(cs, args): """Print a list of available 'volume types'.""" vtypes = cs.volume_types.list() _print_volume_type_list(vtypes) -@utils.service_type('share') +@cliutils.service_type('share') def do_extra_specs_list(cs, args): """Print a list of current 'volume types and extra specs' (Admin Only).""" vtypes = cs.volume_types.list() @@ -1180,7 +1181,7 @@ def do_extra_specs_list(cs, args): @utils.arg('name', metavar='', help="Name of the new volume type") -@utils.service_type('share') +@cliutils.service_type('share') def do_type_create(cs, args): """Create a new volume type.""" vtype = cs.volume_types.create(args.name) @@ -1190,7 +1191,7 @@ def do_type_create(cs, args): @utils.arg('id', metavar='', help="Name or ID of the volume type to delete") -@utils.service_type('share') +@cliutils.service_type('share') def do_type_delete(cs, args): """Delete a specific volume type.""" volume_type = _find_volume_type(cs, args.id) @@ -1209,7 +1210,7 @@ def do_type_delete(cs, args): nargs='*', default=None, help='Extra_specs to set/unset (only key is necessary on unset)') -@utils.service_type('share') +@cliutils.service_type('share') def do_type_key(cs, args): """Set or unset extra_spec for a volume type.""" vtype = _find_volume_type(cs, args.vtype) diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index 73ea5458e..000000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,86 +0,0 @@ -# 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. - -from manilaclient import base -from manilaclient import exceptions -from manilaclient import utils -from tests import utils as test_utils - -UUID = '8e8ec658-c7b0-4243-bdf8-6f7f2952c0d0' - - -class FakeResource(object): - - def __init__(self, _id, properties): - self.id = _id - try: - self.name = properties['name'] - except KeyError: - pass - try: - self.display_name = properties['display_name'] - except KeyError: - pass - - -class FakeManager(base.ManagerWithFind): - - resource_class = FakeResource - - resources = [ - FakeResource('1234', {'name': 'entity_one'}), - FakeResource(UUID, {'name': 'entity_two'}), - FakeResource('4242', {'display_name': 'entity_three'}), - FakeResource('5678', {'name': '9876'}) - ] - - def get(self, resource_id): - for resource in self.resources: - if resource.id == str(resource_id): - return resource - raise exceptions.NotFound(resource_id) - - def list(self): - return self.resources - - -class FindResourceTestCase(test_utils.TestCase): - - def setUp(self): - super(FindResourceTestCase, self).setUp() - self.manager = FakeManager(None) - - def test_find_none(self): - self.assertRaises(exceptions.CommandError, - utils.find_resource, - self.manager, - 'asdf') - - def test_find_by_integer_id(self): - output = utils.find_resource(self.manager, 1234) - self.assertEqual(output, self.manager.get('1234')) - - def test_find_by_str_id(self): - output = utils.find_resource(self.manager, '1234') - self.assertEqual(output, self.manager.get('1234')) - - def test_find_by_uuid(self): - output = utils.find_resource(self.manager, UUID) - self.assertEqual(output, self.manager.get(UUID)) - - def test_find_by_str_name(self): - output = utils.find_resource(self.manager, 'entity_one') - self.assertEqual(output, self.manager.get('1234')) - - def test_find_by_str_displayname(self): - output = utils.find_resource(self.manager, 'entity_three') - self.assertEqual(output, self.manager.get('4242'))