diff options
author | Brant Knudson <bknudson@us.ibm.com> | 2015-08-06 09:37:43 -0500 |
---|---|---|
committer | Brant Knudson <bknudson@us.ibm.com> | 2015-08-06 09:37:43 -0500 |
commit | 4e498a54d0034b2ce5c87130f080ff580d241600 (patch) | |
tree | d21d11091373e80bf1a4f70ecf1ee54ff82e0ff8 /keystoneclient/base.py | |
parent | d5c5423d6de3710e3480e47062333b33e8de0713 (diff) | |
parent | eae8e83f5a7a170b98ef2d74a4ffd9eac7cc47ba (diff) | |
download | python-keystoneclient-feature/keystoneauth_integration.tar.gz |
Merge remote-tracking branch 'origin/master' into merge-branchfeature/keystoneauth_integration
Conflicts:
keystoneclient/exceptions.py
keystoneclient/fixture/discovery.py
keystoneclient/fixture/v2.py
keystoneclient/fixture/v3.py
keystoneclient/middleware/auth_token.py
keystoneclient/middleware/s3_token.py
keystoneclient/tests/unit/test_auth_token_middleware.py
keystoneclient/tests/unit/test_memcache_crypt.py
keystoneclient/tests/unit/test_s3_token_middleware.py
requirements.txt
test-requirements.txt
Change-Id: Ib51acebaac7966bf37c1562fa15b9061df6a7aa5
Diffstat (limited to 'keystoneclient/base.py')
-rw-r--r-- | keystoneclient/base.py | 116 |
1 files changed, 113 insertions, 3 deletions
diff --git a/keystoneclient/base.py b/keystoneclient/base.py index 025362b..f19ed84 100644 --- a/keystoneclient/base.py +++ b/keystoneclient/base.py @@ -20,15 +20,17 @@ Base utilities to build API operation managers and objects on top of. """ import abc +import copy import functools +import warnings +from oslo_utils import strutils import six from six.moves import urllib from keystoneclient import auth from keystoneclient import exceptions from keystoneclient.i18n import _ -from keystoneclient.openstack.common.apiclient import base def getid(obj): @@ -91,8 +93,17 @@ class Manager(object): @property def api(self): - """Deprecated. Use `client` instead. + """The client. + + .. warning:: + + This property is deprecated as of the 1.7.0 release in favor of + :meth:`client` and may be removed in the 2.0.0 release. + """ + warnings.warn( + 'api is deprecated as of the 1.7.0 release in favor of client and ' + 'may be removed in the 2.0.0 release', DeprecationWarning) return self.client def _list(self, url, response_key, obj_class=None, body=None, **kwargs): @@ -356,6 +367,17 @@ class CrudManager(Manager): @filter_kwargs def list(self, fallback_to_auth=False, **kwargs): + if 'id' in kwargs.keys(): + # Ensure that users are not trying to call things like + # ``domains.list(id='default')`` when they should have used + # ``[domains.get(domain_id='default')]`` instead. Keystone supports + # ``GET /v3/domains/{domain_id}``, not ``GET + # /v3/domains?id={domain_id}``. + raise TypeError( + _("list() got an unexpected keyword argument 'id'. To " + "retrieve a single object using a globally unique " + "identifier, try using get() instead.")) + url = self.build_url(dict_args_in_out=kwargs) try: @@ -418,11 +440,99 @@ class CrudManager(Manager): return rl[0] -class Resource(base.Resource): +class Resource(object): """Base class for OpenStack resources (tenant, user, etc.). This is pretty much just a bag for attributes. """ + HUMAN_ID = False + NAME_ATTR = 'name' + + def __init__(self, manager, info, loaded=False): + """Populate and bind to a manager. + + :param manager: BaseManager object + :param info: dictionary representing resource attributes + :param loaded: prevent lazy-loading if set to True + """ + self.manager = manager + self._info = info + self._add_details(info) + self._loaded = loaded + + def __repr__(self): + reprkeys = sorted(k + for k in self.__dict__.keys() + if k[0] != '_' and k != 'manager') + info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) + return "<%s %s>" % (self.__class__.__name__, info) + + @property + def human_id(self): + """Human-readable ID which can be used for bash completion. + """ + if self.HUMAN_ID: + name = getattr(self, self.NAME_ATTR, None) + if name is not None: + return strutils.to_slug(name) + return None + + def _add_details(self, info): + for (k, v) in six.iteritems(info): + try: + setattr(self, k, v) + self._info[k] = v + except AttributeError: + # In this case we already defined the attribute on the class + pass + + def __getattr__(self, k): + if k not in self.__dict__: + # NOTE(bcwaldon): disallow lazy-loading if already loaded once + if not self.is_loaded(): + self.get() + return self.__getattr__(k) + + raise AttributeError(k) + else: + return self.__dict__[k] + + def get(self): + """Support for lazy loading details. + + Some clients, such as novaclient have the option to lazy load the + details, details which can be loaded with this function. + """ + # set_loaded() first ... so if we have to bail, we know we tried. + self.set_loaded(True) + if not hasattr(self.manager, 'get'): + return + + new = self.manager.get(self.id) + if new: + self._add_details(new._info) + self._add_details( + {'x_request_id': self.manager.client.last_request_id}) + + def __eq__(self, other): + if not isinstance(other, Resource): + return NotImplemented + # two resources of different types are not equal + if not isinstance(other, self.__class__): + return False + if hasattr(self, 'id') and hasattr(other, 'id'): + return self.id == other.id + return self._info == other._info + + def is_loaded(self): + return self._loaded + + def set_loaded(self, val): + self._loaded = val + + def to_dict(self): + return copy.deepcopy(self._info) + def delete(self): return self.manager.delete(self) |