From: Christian Hofstaedtler Date: Wed, 19 Mar 2014 15:47:38 +0000 (+0100) Subject: API: implement search-data for recursor auth zones X-Git-Tag: rec-3.6.0-rc1~117^2^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F1336%2Fhead;p=thirdparty%2Fpdns.git API: implement search-data for recursor auth zones --- diff --git a/pdns/ws-recursor.cc b/pdns/ws-recursor.cc index 4ee34e28bc..fd22a1de91 100644 --- a/pdns/ws-recursor.cc +++ b/pdns/ws-recursor.cc @@ -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/", &apiServerZoneDetail); d_ws->registerApiHandler("/servers/localhost/zones", &apiServerZones); diff --git a/regression-tests.api/test_Zones.py b/regression-tests.api/test_Zones.py index 23c8f81000..104182aeb5 100644 --- a/regression-tests.api/test_Zones.py +++ b/regression-tests.api/test_Zones.py @@ -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)