]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Allow disabled records to be fetched from the API.
authorMiod Vallat <miod.vallat@powerdns.com>
Thu, 20 Mar 2025 14:15:35 +0000 (15:15 +0100)
committerMiod Vallat <miod.vallat@powerdns.com>
Mon, 14 Apr 2025 14:57:41 +0000 (16:57 +0200)
Fixes #11473

docs/http-api/swagger/authoritative-api-swagger.yaml
pdns/ws-auth.cc
regression-tests.api/test_Zones.py

index c231b9d1fdd1b571adb54559a726b75ccdb44006..b820599f7baeae4e7f6c7bbb1465d95ba90ddb99 100644 (file)
@@ -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
index 8e4e0850573ba40cfb9247d904618863bc3f6ba5..ee98b52edf7d0ddcecb40e8fa2c68888ac6e21fb 100644 (file)
@@ -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<DNSResourceRecord> records;
     vector<Comment> 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<int>(domainInfo.id));
+        bool include_disabled = boolFromHttpRequest(req, "include_disabled");
+        domainInfo.backend->APILookup(qType, qName, static_cast<int>(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<int>(domainInfo.id));
+          domainInfo.backend->APILookup(QType(QType::ANY), qname, static_cast<int>(domainInfo.id), nullptr, false);
           DNSResourceRecord resourceRecord;
           while (domainInfo.backend->get(resourceRecord)) {
             if (resourceRecord.qtype.getCode() == QType::ENT) {
index 2876b5e268d4b45f27866f7b00d7d8e7733d7bad..3902376ac238a2507739ca34c8e9ceeeb2daee4e 100644 (file)
@@ -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.")