]> granicus.if.org Git - pdns/commitdiff
API: implement search-data for recursor auth zones
authorChristian Hofstaedtler <christian@hofstaedtler.name>
Wed, 19 Mar 2014 15:47:38 +0000 (16:47 +0100)
committerChristian Hofstaedtler <christian@hofstaedtler.name>
Wed, 19 Mar 2014 15:47:49 +0000 (16:47 +0100)
pdns/ws-recursor.cc
regression-tests.api/test_Zones.py

index 4ee34e28bcbb18c68f1883cd002e7f9baacfb095..fd22a1de912a0000123cc15e317a2ea27ccdc8db 100644 (file)
@@ -345,6 +345,59 @@ static void apiServerZoneDetail(HttpRequest* req, HttpResponse* resp)
   }
 }
 
+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");
+
+  Document doc;
+  doc.SetArray();
+
+  BOOST_FOREACH(const SyncRes::domainmap_t::value_type& val, *t_sstorage->domainmap) {
+    string zoneId = apiZoneNameToId(val.first);
+    if (pdns_ci_find(val.first, q) != string::npos) {
+      Value object;
+      object.SetObject();
+      object.AddMember("type", "zone", doc.GetAllocator());
+      Value jzoneId(zoneId.c_str(), doc.GetAllocator()); // copy
+      object.AddMember("zone_id", jzoneId, doc.GetAllocator());
+      Value jzoneName(val.first.c_str(), doc.GetAllocator()); // copy
+      object.AddMember("name", jzoneName, 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 (val.first == q) {
+      continue;
+    }
+
+    const SyncRes::AuthDomain& zone = val.second;
+
+    BOOST_FOREACH(const SyncRes::AuthDomain::records_t::value_type& rr, zone.d_records) {
+      if (pdns_ci_find(rr.qname, q) == string::npos && pdns_ci_find(rr.content, q) == string::npos)
+        continue;
+
+      Value object;
+      object.SetObject();
+      object.AddMember("type", "record", doc.GetAllocator());
+      Value jzoneId(zoneId.c_str(), doc.GetAllocator()); // copy
+      object.AddMember("zone_id", jzoneId, doc.GetAllocator());
+      Value jzoneName(val.first.c_str(), doc.GetAllocator()); // copy
+      object.AddMember("zone_name", jzoneName, 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());
+    }
+  }
+  resp->setBody(doc);
+}
+
 RecursorWebServer::RecursorWebServer(FDMultiplexer* fdm)
 {
   RecursorControlParser rcp; // inits
@@ -361,6 +414,7 @@ RecursorWebServer::RecursorWebServer(FDMultiplexer* fdm)
   d_ws->registerApiHandler("/servers/localhost/config/allow-from", &apiServerConfigAllowFrom);
   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>", &apiServerZoneDetail);
   d_ws->registerApiHandler("/servers/localhost/zones", &apiServerZones);
index 23c8f81000172645964bbd3fdb7a5b39efc289d4..104182aeb51e35b9cd93d916f4a8f1260076038f 100644 (file)
@@ -522,36 +522,33 @@ class AuthZones(ApiTestCase):
 @unittest.skipIf(not isRecursor(), "Not applicable")
 class RecursorZones(ApiTestCase):
 
-    def test_CreateAuthZone(self):
+    def create_zone(self, name=None, kind=None, rd=False, servers=None):
+        if name is None:
+            name = unique_zone_name()
+        if servers is None:
+            servers = []
         payload = {
-            'name': unique_zone_name(),
-            'kind': 'Native',
-            'recursion_desired': False
+            'name': name,
+            'kind': kind,
+            'servers': servers,
+            'recursion_desired': rd
         }
         r = self.session.post(
             self.url("/servers/localhost/zones"),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assertSuccessJson(r)
-        data = r.json()
+        return (payload, r.json())
+
+    def test_CreateAuthZone(self):
+        payload, data = self.create_zone(kind='Native')
         # return values are normalized
         payload['name'] += '.'
         for k in payload.keys():
             self.assertEquals(data[k], payload[k])
 
     def test_CreateForwardedZone(self):
-        payload = {
-            'name': unique_zone_name(),
-            'kind': 'Forwarded',
-            'servers': ['8.8.8.8'],
-            'recursion_desired': False
-        }
-        r = self.session.post(
-            self.url("/servers/localhost/zones"),
-            data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
-        self.assertSuccessJson(r)
-        data = r.json()
+        payload, data = self.create_zone(kind='Forwarded', rd=False, servers=['8.8.8.8'])
         # return values are normalized
         payload['servers'][0] += ':53'
         payload['name'] += '.'
@@ -559,18 +556,7 @@ class RecursorZones(ApiTestCase):
             self.assertEquals(data[k], payload[k])
 
     def test_CreateForwardedRDZone(self):
-        payload = {
-            'name': 'google.com',
-            'kind': 'Forwarded',
-            'servers': ['8.8.8.8'],
-            'recursion_desired': True
-        }
-        r = self.session.post(
-            self.url("/servers/localhost/zones"),
-            data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
-        self.assertSuccessJson(r)
-        data = r.json()
+        payload, data = self.create_zone(name='google.com', kind='Forwarded', rd=True, servers=['8.8.8.8'])
         # return values are normalized
         payload['servers'][0] += ':53'
         payload['name'] += '.'
@@ -578,17 +564,7 @@ class RecursorZones(ApiTestCase):
             self.assertEquals(data[k], payload[k])
 
     def test_CreateAuthZoneWithSymbols(self):
-        payload = {
-            'name': 'foo/bar.'+unique_zone_name(),
-            'kind': 'Native',
-            'recursion_desired': False
-        }
-        r = self.session.post(
-            self.url("/servers/localhost/zones"),
-            data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
-        self.assertSuccessJson(r)
-        data = r.json()
+        payload, data = self.create_zone(name='foo/bar.'+unique_zone_name(), kind='Native')
         # return values are normalized
         payload['name'] += '.'
         expected_id = (payload['name'].replace('/', '=2F'))
@@ -597,17 +573,8 @@ class RecursorZones(ApiTestCase):
         self.assertEquals(data['id'], expected_id)
 
     def test_RenameAuthZone(self):
-        name = unique_zone_name()+'.'
-        payload = {
-            'name': name,
-            'kind': 'Native',
-            'recursion_desired': False
-        }
-        r = self.session.post(
-            self.url("/servers/localhost/zones"),
-            data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
-        self.assertSuccessJson(r)
+        payload, data = self.create_zone(kind='Native')
+        name = payload['name'] + '.'
         # now rename it
         payload = {
             'name': 'renamed-'+name,
@@ -622,3 +589,20 @@ class RecursorZones(ApiTestCase):
         data = r.json()
         for k in payload.keys():
             self.assertEquals(data[k], payload[k])
+
+    def test_SearchRRExactZone(self):
+        name = unique_zone_name() + '.'
+        self.create_zone(name=name, kind='Native')
+        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, u'zone_id': name}])
+
+    def test_SearchRRSubstring(self):
+        name = 'search-rr-zone.name'
+        self.create_zone(name=name, kind='Native')
+        r = self.session.get(self.url("/servers/localhost/search-data?q=rr-zone"))
+        self.assertSuccessJson(r)
+        print r.json()
+        # should return zone, SOA
+        self.assertEquals(len(r.json()), 2)