From a83004d351cf1af90e422d5cb237dc6affa65399 Mon Sep 17 00:00:00 2001 From: Christian Hofstaedtler Date: Tue, 29 Apr 2014 00:44:46 +0200 Subject: [PATCH] API: Auth: Add zone//export route --- pdns/ws-auth.cc | 73 ++++++++++++++++++++++++++++++ regression-tests.api/test_Zones.py | 26 +++++++++++ 2 files changed, 99 insertions(+) diff --git a/pdns/ws-auth.cc b/pdns/ws-auth.cc index 851cb8fd3..c1e05f95a 100644 --- a/pdns/ws-auth.cc +++ b/pdns/ws-auth.cc @@ -661,6 +661,78 @@ static void apiServerZoneDetail(HttpRequest* req, HttpResponse* resp) { throw HttpMethodNotAllowedException(); } +static string makeDotted(string in) { + if (in.empty()) { + return "."; + } + if (in[in.size()-1] != '.') { + return in + "."; + } + return in; +} + +static void apiServerZoneExport(HttpRequest* req, HttpResponse* resp) { + string zonename = apiZoneIdToName(req->path_parameters["id"]); + + if(req->method != "GET") + throw HttpMethodNotAllowedException(); + + ostringstream ss; + + UeberBackend B; + DomainInfo di; + if(!B.getDomainInfo(zonename, di)) + throw ApiException("Could not find domain '"+zonename+"'"); + + DNSResourceRecord rr; + SOAData sd; + di.backend->list(zonename, di.id); + while(di.backend->get(rr)) { + if (!rr.qtype.getCode()) + continue; // skip empty non-terminals + + string content = rr.content; + + switch(rr.qtype.getCode()) { + case QType::SOA: + fillSOAData(rr.content, sd); + sd.nameserver = makeDotted(sd.nameserver); + sd.hostmaster = makeDotted(sd.hostmaster); + content = serializeSOAData(sd); + break; + case QType::MX: + case QType::SRV: + content = lexical_cast(rr.priority) + "\t" + makeDotted(content); + break; + case QType::CNAME: + case QType::NS: + case QType::AFSDB: + content = makeDotted(rr.content); + break; + default: + break; + } + + ss << + makeDotted(rr.qname) << "\t" << + rr.ttl << "\t" << + rr.qtype.getName() << "\t" << + content << + endl; + } + + if (req->accept_json) { + Document doc; + doc.SetObject(); + Value val(ss.str().c_str(), doc.GetAllocator()); // copy + doc.AddMember("zone", val, doc.GetAllocator()); + resp->body = makeStringFromDocument(doc); + } else { + resp->headers["Content-Type"] = "text/plain; charset=us-ascii"; + resp->body = ss.str(); + } +} + static void makePtr(const DNSResourceRecord& rr, DNSResourceRecord* ptr) { if (rr.qtype.getCode() == QType::A) { uint32_t ip; @@ -1025,6 +1097,7 @@ void AuthWebServer::webThread() 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//export", &apiServerZoneExport); d_ws->registerApiHandler("/servers/localhost/zones/", &apiServerZoneDetail); d_ws->registerApiHandler("/servers/localhost/zones", &apiServerZones); d_ws->registerApiHandler("/servers/localhost", &apiServerDetail); diff --git a/regression-tests.api/test_Zones.py b/regression-tests.api/test_Zones.py index 22ac9fc74..6d637c1ef 100644 --- a/regression-tests.api/test_Zones.py +++ b/regression-tests.api/test_Zones.py @@ -169,6 +169,32 @@ class AuthZones(ApiTestCase): self.assertIn(k, data) self.assertEquals(data['name'], 'example.com') + def test_ExportZoneJson(self): + payload, zone = self.create_zone(nameservers=['ns1.foo.com', 'ns2.foo.com']) + name = payload['name'] + # export it + r = self.session.get( + self.url("/servers/localhost/zones/" + name + "/export"), + headers={'accept': 'application/json;q=0.9,*/*;q=0.8'} + ) + self.assertSuccessJson(r) + data = r.json() + self.assertIn('zone', data) + expected_data = [name+'.\t3600\tNS\tns1.foo.com.',name+'.\t3600\tNS\tns2.foo.com.',name+'.\t3600\tSOA\ta.misconfigured.powerdns.server. hostmaster.'+name+'. 0 10800 3600 604800 3600'] + self.assertEquals(data['zone'].strip().split('\n'), expected_data) + + def test_ExportZoneText(self): + payload, zone = self.create_zone(nameservers=['ns1.foo.com', 'ns2.foo.com']) + name = payload['name'] + # export it + r = self.session.get( + self.url("/servers/localhost/zones/" + name + "/export"), + headers={'accept': '*/*'} + ) + data = r.text.strip().split("\n") + expected_data = [name+'.\t3600\tNS\tns1.foo.com.',name+'.\t3600\tNS\tns2.foo.com.',name+'.\t3600\tSOA\ta.misconfigured.powerdns.server. hostmaster.'+name+'. 0 10800 3600 604800 3600'] + self.assertEquals(data, expected_data) + def test_UpdateZone(self): payload, zone = self.create_zone() name = payload['name'] -- 2.40.0