]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
JSON API: add search-data 1329/head
authorChristian Hofstaedtler <christian@hofstaedtler.name>
Mon, 10 Mar 2014 12:28:44 +0000 (13:28 +0100)
committerChristian Hofstaedtler <christian@hofstaedtler.name>
Mon, 10 Mar 2014 12:29:58 +0000 (13:29 +0100)
Searches for zones, records, comments.

pdns/ws-auth.cc
regression-tests.api/test_Zones.py

index 4eaf1012ffe67f96a85d1c1337b175ef3946b747..f0bc3d5dd0c9aa9652c6c9866372f66649619c67 100644 (file)
@@ -725,6 +725,76 @@ static void apiServerZoneRRset(HttpRequest* req, HttpResponse* resp) {
   resp->body = "{}";
 }
 
+static void apiServerSearchData(HttpRequest* req, HttpResponse* resp) {
+  if(req->method != "GET")
+    throw HttpMethodNotAllowedException();
+
+  string q = req->parameters["q"];
+  if (q.empty())
+    throw ApiException("Query q can't be blank");
+
+  UeberBackend B;
+
+  vector<DomainInfo> domains;
+  B.getAllDomains(&domains, true); // incl. disabled
+
+  Document doc;
+  doc.SetArray();
+
+  DNSResourceRecord rr;
+  Comment comment;
+
+  BOOST_FOREACH(const DomainInfo& di, domains) {
+    if (di.zone.find(q) != string::npos) {
+      Value object;
+      object.SetObject();
+      object.AddMember("type", "zone", doc.GetAllocator());
+      Value jname(di.zone.c_str(), doc.GetAllocator()); // copy
+      object.AddMember("name", jname, doc.GetAllocator());
+      doc.PushBack(object, doc.GetAllocator());
+    }
+
+    // if zone name is an exact match, don't bother with returning all records/comments in it
+    if (di.zone == q) {
+      continue;
+    }
+
+    di.backend->list(di.zone, di.id, true); // incl. disabled
+    while(di.backend->get(rr)) {
+      if (!rr.qtype.getCode())
+        continue; // skip empty non-terminals
+
+      if (rr.qname.find(q) == string::npos && rr.content.find(q) == string::npos)
+        continue;
+
+      Value object;
+      object.SetObject();
+      object.AddMember("type", "record", doc.GetAllocator());
+      Value jname(rr.qname.c_str(), doc.GetAllocator()); // copy
+      object.AddMember("name", jname, doc.GetAllocator());
+      Value jcontent(rr.content.c_str(), doc.GetAllocator()); // copy
+      object.AddMember("content", jcontent, doc.GetAllocator());
+      doc.PushBack(object, doc.GetAllocator());
+    }
+
+    di.backend->listComments(di.id);
+    while(di.backend->getComment(comment)) {
+      if (comment.qname.find(q) == string::npos && comment.content.find(q) == string::npos)
+        continue;
+
+      Value object;
+      object.SetObject();
+      object.AddMember("type", "comment", doc.GetAllocator());
+      Value jname(comment.qname.c_str(), doc.GetAllocator()); // copy
+      object.AddMember("name", jname, doc.GetAllocator());
+      Value jcontent(comment.content.c_str(), doc.GetAllocator()); // copy
+      object.AddMember("content", jcontent, doc.GetAllocator());
+      doc.PushBack(object, doc.GetAllocator());
+    }
+  }
+  resp->setBody(doc);
+}
+
 void AuthWebServer::jsonstat(HttpRequest* req, HttpResponse* resp)
 {
   string command;
@@ -825,6 +895,7 @@ void AuthWebServer::webThread()
     if(::arg().mustDo("experimental-json-interface")) {
       d_ws->registerApiHandler("/servers/localhost/config", &apiServerConfig);
       d_ws->registerApiHandler("/servers/localhost/search-log", &apiServerSearchLog);
+      d_ws->registerApiHandler("/servers/localhost/search-data", &apiServerSearchData);
       d_ws->registerApiHandler("/servers/localhost/statistics", &apiServerStatistics);
       d_ws->registerApiHandler("/servers/localhost/zones/<id>/rrset", &apiServerZoneRRset);
       d_ws->registerApiHandler("/servers/localhost/zones/<id>", &apiServerZoneDetail);
index 3ccee84ac50f93e7780adf5c71f069b3a33a28a9..14a0b06dc8daab7a6d416e7bafd77d0e6e7ce607 100644 (file)
@@ -492,6 +492,23 @@ class AuthZones(ApiTestCase):
             u'name': u'a.a.0.0.b.b.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa'
         }])
 
+    def test_SearchRRExactZone(self):
+        name = unique_zone_name()
+        self.create_zone(name=name)
+        r = self.session.get(self.url("/servers/localhost/search-data?q=" + name))
+        self.assertSuccessJson(r)
+        print r.json()
+        self.assertEquals(r.json(), [{u'type': u'zone', u'name': name}])
+
+    def test_SearchRRSubstring(self):
+        name = 'search-rr-zone.name'
+        self.create_zone(name=name)
+        r = self.session.get(self.url("/servers/localhost/search-data?q=rr-zone"))
+        self.assertSuccessJson(r)
+        print r.json()
+        # should return zone, SOA, ns1, ns2
+        self.assertEquals(len(r.json()), 4)
+
 
 @unittest.skipIf(not isRecursor(), "Not applicable")
 class RecursorZones(ApiTestCase):