]> granicus.if.org Git - pdns/commitdiff
API: Auth: Add zone/<id>/export route
authorChristian Hofstaedtler <christian@hofstaedtler.name>
Mon, 28 Apr 2014 22:44:46 +0000 (00:44 +0200)
committerChristian Hofstaedtler <christian@hofstaedtler.name>
Mon, 28 Apr 2014 22:45:08 +0000 (00:45 +0200)
pdns/ws-auth.cc
regression-tests.api/test_Zones.py

index 851cb8fd30edb65aee6b583c44147e67325798a0..c1e05f95a509224e9e9c72583a2a42cc34c2abcd 100644 (file)
@@ -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<string>(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/<id>/export", &apiServerZoneExport);
       d_ws->registerApiHandler("/servers/localhost/zones/<id>", &apiServerZoneDetail);
       d_ws->registerApiHandler("/servers/localhost/zones", &apiServerZones);
       d_ws->registerApiHandler("/servers/localhost", &apiServerDetail);
index 22ac9fc7447b572e9c46c893a011be3e59836793..6d637c1ef94e1a7f9f325b4eedf5d622eb1b1532 100644 (file)
@@ -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']