Allow project switching for Designate API
Contrary to other OpenStack APIs, the Designate v2 API implements project switching based on HTTP headers, especially x-auth-sudo-project-id and x-auth-all-projects. This commit adds feature parity with other OpenStack APIs, i. e. direct usage of parameters "project_id" and "all_projects" for DNS resource list operations. Story: 2010909 Task: 48748 Change-Id: I1cb1efbf1f243cca0c5bb6e1058d25b2ad863355 Signed-off-by: Jan Hartkopf <jhartkopf@inovex.de>
This commit is contained in:
parent
04cdd0a061
commit
e7bdb02f90
@ -72,6 +72,26 @@ class Resource(resource.Resource):
|
|||||||
"No %s found for %s" % (cls.__name__, name_or_id)
|
"No %s found for %s" % (cls.__name__, name_or_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def list(
|
||||||
|
cls,
|
||||||
|
session,
|
||||||
|
project_id=None,
|
||||||
|
all_projects=None,
|
||||||
|
**params,
|
||||||
|
):
|
||||||
|
headers: ty.Union[ty.Dict[str, str] | None] = (
|
||||||
|
{} if project_id or all_projects else None
|
||||||
|
)
|
||||||
|
|
||||||
|
if headers is not None:
|
||||||
|
if project_id:
|
||||||
|
headers["x-auth-sudo-project-id"] = str(project_id)
|
||||||
|
if all_projects:
|
||||||
|
headers["x-auth-all-projects"] = str(all_projects)
|
||||||
|
|
||||||
|
return super().list(session=session, headers=headers, **params)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_next_link(cls, uri, response, data, marker, limit, total_yielded):
|
def _get_next_link(cls, uri, response, data, marker, limit, total_yielded):
|
||||||
next_link = None
|
next_link = None
|
||||||
|
@ -561,7 +561,7 @@ class Proxy(proxy.Proxy):
|
|||||||
|
|
||||||
# ======== Zone Shares ========
|
# ======== Zone Shares ========
|
||||||
def zone_shares(self, zone, **query):
|
def zone_shares(self, zone, **query):
|
||||||
"""Retrieve a generator of zone sharess
|
"""Retrieve a generator of zone shares
|
||||||
|
|
||||||
:param zone: The zone ID or a
|
:param zone: The zone ID or a
|
||||||
:class:`~openstack.dns.v2.zone.Zone` instance
|
:class:`~openstack.dns.v2.zone.Zone` instance
|
||||||
|
@ -880,7 +880,7 @@ class Proxy(adapter.Adapter):
|
|||||||
|
|
||||||
if resource_name in skip_resources:
|
if resource_name in skip_resources:
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
f"Skipping resource {resource_name} " "in project cleanup"
|
f"Skipping resource {resource_name} in project cleanup"
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -1990,6 +1990,7 @@ class Resource(dict):
|
|||||||
allow_unknown_params=False,
|
allow_unknown_params=False,
|
||||||
*,
|
*,
|
||||||
microversion=None,
|
microversion=None,
|
||||||
|
headers=None,
|
||||||
**params,
|
**params,
|
||||||
):
|
):
|
||||||
"""This method is a generator which yields resource objects.
|
"""This method is a generator which yields resource objects.
|
||||||
@ -2010,6 +2011,8 @@ class Resource(dict):
|
|||||||
passing everything known to the server. ``False`` will result in
|
passing everything known to the server. ``False`` will result in
|
||||||
validation exception when unknown query parameters are passed.
|
validation exception when unknown query parameters are passed.
|
||||||
:param str microversion: API version to override the negotiated one.
|
:param str microversion: API version to override the negotiated one.
|
||||||
|
:param dict headers: Additional headers to inject into the HTTP
|
||||||
|
request.
|
||||||
:param dict params: These keyword arguments are passed through the
|
:param dict params: These keyword arguments are passed through the
|
||||||
:meth:`~openstack.resource.QueryParamter._transpose` method
|
:meth:`~openstack.resource.QueryParamter._transpose` method
|
||||||
to find if any of them match expected query parameters to be sent
|
to find if any of them match expected query parameters to be sent
|
||||||
@ -2079,6 +2082,10 @@ class Resource(dict):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
headers_final = {"Accept": "application/json"}
|
||||||
|
if headers:
|
||||||
|
headers_final = {**headers_final, **headers}
|
||||||
|
|
||||||
# Track the total number of resources yielded so we can paginate
|
# Track the total number of resources yielded so we can paginate
|
||||||
# swift objects
|
# swift objects
|
||||||
total_yielded = 0
|
total_yielded = 0
|
||||||
@ -2086,7 +2093,7 @@ class Resource(dict):
|
|||||||
# Copy query_params due to weird mock unittest interactions
|
# Copy query_params due to weird mock unittest interactions
|
||||||
response = session.get(
|
response = session.get(
|
||||||
uri,
|
uri,
|
||||||
headers={"Accept": "application/json"},
|
headers=headers_final,
|
||||||
params=query_params.copy(),
|
params=query_params.copy(),
|
||||||
microversion=microversion,
|
microversion=microversion,
|
||||||
)
|
)
|
||||||
|
@ -18,6 +18,7 @@ from unittest import mock
|
|||||||
from keystoneauth1 import adapter
|
from keystoneauth1 import adapter
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from openstack import dns
|
||||||
from openstack import exceptions
|
from openstack import exceptions
|
||||||
from openstack import format
|
from openstack import format
|
||||||
from openstack import resource
|
from openstack import resource
|
||||||
@ -2651,6 +2652,38 @@ class TestResourceActions(base.TestCase):
|
|||||||
Test.base_path % {"something": uri_param},
|
Test.base_path % {"something": uri_param},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_list_with_injected_headers(self):
|
||||||
|
mock_empty = mock.Mock()
|
||||||
|
mock_empty.status_code = 200
|
||||||
|
mock_empty.json.return_value = {"resources": []}
|
||||||
|
|
||||||
|
self.session.get.side_effect = [mock_empty]
|
||||||
|
|
||||||
|
_ = list(
|
||||||
|
self.test_class.list(self.session, headers={'X-Test': 'value'})
|
||||||
|
)
|
||||||
|
|
||||||
|
expected = {'Accept': 'application/json', 'X-Test': 'value'}
|
||||||
|
self.assertEqual(
|
||||||
|
expected, self.session.get.call_args.kwargs['headers']
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(resource.Resource, 'list')
|
||||||
|
def test_list_dns_with_headers(self, mock_resource_list):
|
||||||
|
dns.v2._base.Resource.list(
|
||||||
|
self.session,
|
||||||
|
project_id='1234',
|
||||||
|
all_projects=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
'x-auth-sudo-project-id': '1234',
|
||||||
|
'x-auth-all-projects': 'True',
|
||||||
|
}
|
||||||
|
self.assertEqual(
|
||||||
|
expected, mock_resource_list.call_args.kwargs['headers']
|
||||||
|
)
|
||||||
|
|
||||||
def test_allow_invalid_list_params(self):
|
def test_allow_invalid_list_params(self):
|
||||||
qp = "query param!"
|
qp = "query param!"
|
||||||
qp_name = "query-param"
|
qp_name = "query-param"
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add functionality to list DNS resources for a certain project only,
|
||||||
|
or for all projects, using the new `project_id` and `all_projects`
|
||||||
|
parameters.
|
Loading…
Reference in New Issue
Block a user