diff --git a/openstack/dns/v2/_base.py b/openstack/dns/v2/_base.py index 7efdbfed0..756e42939 100644 --- a/openstack/dns/v2/_base.py +++ b/openstack/dns/v2/_base.py @@ -72,6 +72,26 @@ class Resource(resource.Resource): f"No {cls.__name__} found for {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 def _get_next_link(cls, uri, response, data, marker, limit, total_yielded): next_link = None diff --git a/openstack/dns/v2/_proxy.py b/openstack/dns/v2/_proxy.py index de2ee5742..9c71b2f5f 100644 --- a/openstack/dns/v2/_proxy.py +++ b/openstack/dns/v2/_proxy.py @@ -561,7 +561,7 @@ class Proxy(proxy.Proxy): # ======== Zone Shares ======== 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 :class:`~openstack.dns.v2.zone.Zone` instance diff --git a/openstack/proxy.py b/openstack/proxy.py index 2971824e0..e11184af9 100644 --- a/openstack/proxy.py +++ b/openstack/proxy.py @@ -879,7 +879,7 @@ class Proxy(adapter.Adapter): if resource_name in skip_resources: self.log.debug( - f"Skipping resource {resource_name} " "in project cleanup" + f"Skipping resource {resource_name} in project cleanup" ) return True diff --git a/openstack/resource.py b/openstack/resource.py index a8c7a9970..60f377ecf 100644 --- a/openstack/resource.py +++ b/openstack/resource.py @@ -1990,6 +1990,7 @@ class Resource(dict): allow_unknown_params=False, *, microversion=None, + headers=None, **params, ): """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 validation exception when unknown query parameters are passed. :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 :meth:`~openstack.resource.QueryParamter._transpose` method to find if any of them match expected query parameters to be sent @@ -2079,6 +2082,10 @@ class Resource(dict): return False 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 # swift objects total_yielded = 0 @@ -2086,7 +2093,7 @@ class Resource(dict): # Copy query_params due to weird mock unittest interactions response = session.get( uri, - headers={"Accept": "application/json"}, + headers=headers_final, params=query_params.copy(), microversion=microversion, ) diff --git a/openstack/tests/unit/test_resource.py b/openstack/tests/unit/test_resource.py index 75c758a25..42170b9ea 100644 --- a/openstack/tests/unit/test_resource.py +++ b/openstack/tests/unit/test_resource.py @@ -18,6 +18,7 @@ from unittest import mock from keystoneauth1 import adapter import requests +from openstack import dns from openstack import exceptions from openstack import format from openstack import resource @@ -2651,6 +2652,38 @@ class TestResourceActions(base.TestCase): 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): qp = "query param!" qp_name = "query-param" diff --git a/releasenotes/notes/add-dns-resource-list-by-project-8b5479a045ef7373.yaml b/releasenotes/notes/add-dns-resource-list-by-project-8b5479a045ef7373.yaml new file mode 100644 index 000000000..f79ed22c0 --- /dev/null +++ b/releasenotes/notes/add-dns-resource-list-by-project-8b5479a045ef7373.yaml @@ -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.