From: Miod Vallat Date: Thu, 20 Mar 2025 14:15:35 +0000 (+0100) Subject: Allow disabled records to be fetched from the API. X-Git-Tag: dnsdist-2.0.0-alpha2~66^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=86935e10c1d9ac4a5bf30f8160942f6025ab89a5;p=thirdparty%2Fpdns.git Allow disabled records to be fetched from the API. Fixes #11473 --- diff --git a/docs/http-api/swagger/authoritative-api-swagger.yaml b/docs/http-api/swagger/authoritative-api-swagger.yaml index c231b9d1fd..b820599f7b 100644 --- a/docs/http-api/swagger/authoritative-api-swagger.yaml +++ b/docs/http-api/swagger/authoritative-api-swagger.yaml @@ -196,6 +196,10 @@ paths: in: query description: Limit output to the RRset of this type. Can only be used together with rrset_name. type: string + - name: include_disabled + in: query + description: '“true” (default) or “false”, whether to include disabled RRsets in the response.' + type: boolean responses: '200': description: A Zone diff --git a/pdns/ws-auth.cc b/pdns/ws-auth.cc index 8e4e085057..ee98b52edf 100644 --- a/pdns/ws-auth.cc +++ b/pdns/ws-auth.cc @@ -373,16 +373,16 @@ static Json::object getZoneInfo(const DomainInfo& domainInfo, DNSSECKeeper* dnss return obj; } -static bool shouldDoRRSets(HttpRequest* req) +static bool boolFromHttpRequest(HttpRequest* req, const std::string& var) { - if (req->getvars.count("rrsets") == 0 || req->getvars["rrsets"] == "true") { + if (req->getvars.count(var) == 0 || req->getvars[var] == "true") { return true; } - if (req->getvars["rrsets"] == "false") { + if (req->getvars[var] == "false") { return false; } - throw ApiException("'rrsets' request parameter value '" + req->getvars["rrsets"] + "' is not supported"); + throw ApiException("'" + var + "' request parameter value '" + req->getvars[var] + "' is not supported"); } static void fillZone(UeberBackend& backend, const ZoneName& zonename, HttpResponse* resp, HttpRequest* req) @@ -440,7 +440,7 @@ static void fillZone(UeberBackend& backend, const ZoneName& zonename, HttpRespon } doc["slave_tsig_key_ids"] = tsig_secondary_keys; - if (shouldDoRRSets(req)) { + if (boolFromHttpRequest(req, "rrsets")) { vector records; vector comments; @@ -458,7 +458,8 @@ static void fillZone(UeberBackend& backend, const ZoneName& zonename, HttpRespon if (req->getvars.count("rrset_type") != 0) { qType = req->getvars["rrset_type"]; } - domainInfo.backend->lookup(qType, qName, static_cast(domainInfo.id)); + bool include_disabled = boolFromHttpRequest(req, "include_disabled"); + domainInfo.backend->APILookup(qType, qName, static_cast(domainInfo.id), nullptr, include_disabled); } while (domainInfo.backend->get(resourceRecord)) { if (resourceRecord.qtype.getCode() == 0) { @@ -2380,7 +2381,7 @@ static void patchZone(UeberBackend& backend, const ZoneName& zonename, DomainInf bool dname_seen = false; bool ns_seen = false; - domainInfo.backend->lookup(QType(QType::ANY), qname, static_cast(domainInfo.id)); + domainInfo.backend->APILookup(QType(QType::ANY), qname, static_cast(domainInfo.id), nullptr, false); DNSResourceRecord resourceRecord; while (domainInfo.backend->get(resourceRecord)) { if (resourceRecord.qtype.getCode() == QType::ENT) { diff --git a/regression-tests.api/test_Zones.py b/regression-tests.api/test_Zones.py index 2876b5e268..3902376ac2 100644 --- a/regression-tests.api/test_Zones.py +++ b/regression-tests.api/test_Zones.py @@ -876,8 +876,9 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin): self.assertEqual(data['name'], 'example.com.') def test_get_zone_rrset(self): - rz = self.session.get(self.url("/api/v1/servers/localhost/zones")) - domains = rz.json() + name = 'host-18000.example.com.' + r = self.session.get(self.url("/api/v1/servers/localhost/zones")) + domains = r.json() example_com = [domain for domain in domains if domain['name'] == u'example.com.'][0] # verify single record from name that has a single record @@ -888,7 +889,7 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin): [ { 'comments': [], - 'name': 'host-18000.example.com.', + 'name': name, 'records': [ { @@ -902,6 +903,39 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin): ] ) + # disable previous record + rrset = { + 'changetype': 'replace', + 'name': name, + 'type': 'A', + 'ttl': 120, + 'records': + [ + { + 'content': '192.168.1.80', + 'disabled': True + } + ] + } + payload = {'rrsets': [rrset]} + r = self.session.patch( + self.url("/api/v1/servers/localhost/zones/example.com"), + data=json.dumps(payload), + headers={'content-type': 'application/json'}) + self.assert_success(r) + + # verify that the changed record is not found when asking for + # disabled records not to be included + data = self.get_zone(example_com['id'], rrset_name="host-18000.example.com.", include_disabled="false") + self.assertEqual(len(data['rrsets']), 0) + + # verify that the changed record is found when explicitly asking for + # disabled records, and by default. + data = self.get_zone(example_com['id'], rrset_name="host-18000.example.com.", include_disabled="true") + self.assertEqual(get_rrset(data, name, 'A')['records'], rrset['records']) + data = self.get_zone(example_com['id'], rrset_name="host-18000.example.com.") + self.assertEqual(get_rrset(data, name, 'A')['records'], rrset['records']) + # verify two RRsets from a name that has two types with one record each powerdnssec_org = [domain for domain in domains if domain['name'] == u'powerdnssec.org.'][0] data = self.get_zone(powerdnssec_org['id'], rrset_name="localhost.powerdnssec.org.")