Allow resource get to carry query string
This patch augments the resource and proxy class to do resource get with optional queries, i.e. an 'args' parameter. We need this for some parameterized resource retrieval. For example: GET <endpoint>/<resource_id>?with_details=True Change-Id: I2b89c1b16b31db92845640bfc22f485b4f3ca00c
This commit is contained in:
@@ -436,17 +436,19 @@ class Proxy(proxy.BaseProxy):
|
||||
return self._find(_node.Node, name_or_id,
|
||||
ignore_missing=ignore_missing)
|
||||
|
||||
def get_node(self, node):
|
||||
def get_node(self, node, args=None):
|
||||
"""Get a single node.
|
||||
|
||||
:param value: The value can be the name or ID of a node or a
|
||||
:param node: The value can be the name or ID of a node or a
|
||||
:class:`~openstack.cluster.v1.node.Node` instance.
|
||||
:param args: An optional argument that will be translated into query
|
||||
strings when retrieving the node.
|
||||
|
||||
:returns: One :class:`~openstack.cluster.v1.node.Node`
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
|
||||
node matching the name or ID could be found.
|
||||
"""
|
||||
return self._get(_node.Node, node)
|
||||
return self._get(_node.Node, node, args=args)
|
||||
|
||||
def nodes(self, **query):
|
||||
"""Retrieve a generator of nodes.
|
||||
|
||||
@@ -76,11 +76,13 @@ class Limits(resource.Resource):
|
||||
absolute = resource.prop("absolute", type=AbsoluteLimits)
|
||||
rate = resource.prop("rate", type=list)
|
||||
|
||||
def get(self, session, include_headers=False):
|
||||
def get(self, session, args=None, include_headers=False):
|
||||
"""Get the Limits resource.
|
||||
|
||||
:param session: The session to use for making this request.
|
||||
:type session: :class:`~openstack.session.Session`
|
||||
:param dict args: An optional dict that will be translated into query
|
||||
strings for retrieving the object when specified.
|
||||
|
||||
:returns: A Limits instance
|
||||
:rtype: :class:`~openstack.compute.v2.limits.Limits`
|
||||
|
||||
@@ -42,7 +42,7 @@ class ServerMetadata(resource.Resource):
|
||||
return attrs
|
||||
|
||||
@classmethod
|
||||
def get_data_by_id(cls, session, resource_id, path_args=None,
|
||||
def get_data_by_id(cls, session, resource_id, path_args=None, args=None,
|
||||
include_headers=False):
|
||||
url = cls._get_url(path_args)
|
||||
resp = session.get(url, endpoint_filter=cls.service)
|
||||
|
||||
@@ -146,7 +146,7 @@ class Object(resource.Resource):
|
||||
#: value in the X-Delete-At metadata item.
|
||||
delete_after = resource.header("x-delete-after", type=int)
|
||||
|
||||
def get(self, session):
|
||||
def get(self, session, args=None):
|
||||
url = self._get_url(self, self.id)
|
||||
# TODO(thowe): Add filter header support bug #1488269
|
||||
headers = {'Accept': 'bytes'}
|
||||
|
||||
@@ -177,7 +177,7 @@ class BaseProxy(object):
|
||||
return res.create(self.session)
|
||||
|
||||
@_check_resource(strict=False)
|
||||
def _get(self, resource_type, value=None, path_args=None):
|
||||
def _get(self, resource_type, value=None, path_args=None, args=None):
|
||||
"""Get a resource
|
||||
|
||||
:param resource_type: The type of resource to get.
|
||||
@@ -187,13 +187,16 @@ class BaseProxy(object):
|
||||
subclass.
|
||||
:param path_args: A dict containing arguments for forming the request
|
||||
URL, if needed.
|
||||
:param args: A optional dict containing arguments that will be
|
||||
translated into query strings when forming the request URL.
|
||||
|
||||
:returns: The result of the ``get``
|
||||
:rtype: :class:`~openstack.resource.Resource`
|
||||
"""
|
||||
res = self._get_resource(resource_type, value, path_args)
|
||||
|
||||
try:
|
||||
return res.get(self.session)
|
||||
return res.get(self.session, args=args)
|
||||
except ksa_exc.NotFound as exc:
|
||||
raise exceptions.ResourceNotFound(
|
||||
"No %s found for %s" % (resource_type.__name__, value),
|
||||
|
||||
@@ -37,6 +37,7 @@ import time
|
||||
|
||||
from keystoneauth1 import exceptions as ksa_exc
|
||||
import six
|
||||
from six.moves.urllib import parse as url_parse
|
||||
|
||||
from openstack import exceptions
|
||||
from openstack import utils
|
||||
@@ -570,7 +571,7 @@ class Resource(collections.MutableMapping):
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def get_data_by_id(cls, session, resource_id, path_args=None,
|
||||
def get_data_by_id(cls, session, resource_id, path_args=None, args=None,
|
||||
include_headers=False):
|
||||
"""Get the attributes of a remote resource from an id.
|
||||
|
||||
@@ -581,6 +582,8 @@ class Resource(collections.MutableMapping):
|
||||
:param dict path_args: A dictionary of arguments to construct
|
||||
a compound URL.
|
||||
See `How path_args are used`_ for details.
|
||||
:param dict args: A dictionary of query parameters to be appended to
|
||||
the compound URL.
|
||||
:param bool include_headers: ``True`` if header data should be
|
||||
included in the response body,
|
||||
``False`` if not.
|
||||
@@ -593,6 +596,8 @@ class Resource(collections.MutableMapping):
|
||||
raise exceptions.MethodNotSupported(cls, 'retrieve')
|
||||
|
||||
url = cls._get_url(path_args, resource_id)
|
||||
if args:
|
||||
url = '?'.join([url, url_parse.urlencode(args)])
|
||||
response = session.get(url, endpoint_filter=cls.service)
|
||||
body = response.json()
|
||||
|
||||
@@ -629,7 +634,7 @@ class Resource(collections.MutableMapping):
|
||||
include_headers=include_headers)
|
||||
return cls.existing(**body)
|
||||
|
||||
def get(self, session, include_headers=False):
|
||||
def get(self, session, include_headers=False, args=None):
|
||||
"""Get the remote resource associated with this instance.
|
||||
|
||||
:param session: The session to use for making this request.
|
||||
@@ -637,12 +642,13 @@ class Resource(collections.MutableMapping):
|
||||
:param bool include_headers: ``True`` if header data should be
|
||||
included in the response body,
|
||||
``False`` if not.
|
||||
|
||||
:param dict args: A dictionary of query parameters to be appended to
|
||||
the compound URL.
|
||||
:return: This :class:`Resource` instance.
|
||||
:raises: :exc:`~openstack.exceptions.MethodNotSupported` if
|
||||
:data:`Resource.allow_retrieve` is not set to ``True``.
|
||||
"""
|
||||
body = self.get_data_by_id(session, self.id, path_args=self,
|
||||
body = self.get_data_by_id(session, self.id, path_args=self, args=args,
|
||||
include_headers=include_headers)
|
||||
self._attrs.update(body)
|
||||
self._loaded = True
|
||||
|
||||
@@ -304,7 +304,13 @@ class TestClusterProxy(test_proxy_base.TestProxyBase):
|
||||
self.verify_find(self.proxy.find_node, node.Node)
|
||||
|
||||
def test_node_get(self):
|
||||
self.verify_get(self.proxy.get_node, node.Node)
|
||||
self.verify_get(self.proxy.get_node, node.Node, args=None,
|
||||
expected_kwargs={'args': None})
|
||||
|
||||
def test_node_get_with_args(self):
|
||||
self.verify_get(self.proxy.get_node, node.Node, args={'details': True},
|
||||
method_kwargs={'args': {'details': True}},
|
||||
expected_kwargs={'args': {'details': True}})
|
||||
|
||||
def test_nodes(self):
|
||||
self.verify_list(self.proxy.nodes, node.Node,
|
||||
|
||||
@@ -221,14 +221,20 @@ class TestProxyGet(testtools.TestCase):
|
||||
def test_get_resource(self):
|
||||
rv = self.sot._get(RetrieveableResource, self.res)
|
||||
|
||||
self.res.get.assert_called_with(self.session)
|
||||
self.res.get.assert_called_with(self.session, args=None)
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
|
||||
def test_get_resource_with_args(self):
|
||||
rv = self.sot._get(RetrieveableResource, self.res, args={'K': 'V'})
|
||||
|
||||
self.res.get.assert_called_with(self.session, args={'K': 'V'})
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
|
||||
def test_get_id(self):
|
||||
rv = self.sot._get(RetrieveableResource, self.fake_id)
|
||||
|
||||
RetrieveableResource.existing.assert_called_with(id=self.fake_id)
|
||||
self.res.get.assert_called_with(self.session)
|
||||
self.res.get.assert_called_with(self.session, args=None)
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
|
||||
def test_get_not_found(self):
|
||||
|
||||
@@ -100,16 +100,21 @@ class TestProxyBase(base.TestCase):
|
||||
expected_args=[resource_type, "resource_or_id"],
|
||||
expected_kwargs=expected_kwargs)
|
||||
|
||||
def verify_get(self, test_method, resource_type, value=None,
|
||||
def verify_get(self, test_method, resource_type, value=None, args=None,
|
||||
mock_method="openstack.proxy.BaseProxy._get",
|
||||
ignore_value=False, **kwargs):
|
||||
the_value = value
|
||||
if value is None:
|
||||
the_value = [] if ignore_value else ["value"]
|
||||
expected_kwargs = {"path_args": kwargs} if kwargs else {}
|
||||
expected_kwargs = kwargs.pop("expected_kwargs", {})
|
||||
method_kwargs = kwargs.pop("method_kwargs", kwargs)
|
||||
if args:
|
||||
expected_kwargs["args"] = args
|
||||
if kwargs:
|
||||
expected_kwargs["path_args"] = kwargs
|
||||
self._verify2(mock_method, test_method,
|
||||
method_args=the_value,
|
||||
method_kwargs=kwargs,
|
||||
method_kwargs=method_kwargs or {},
|
||||
expected_args=[resource_type] + the_value,
|
||||
expected_kwargs=expected_kwargs)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user