]> granicus.if.org Git - pdns/commitdiff
API: make cache flushing a public, documented operation
authorChristian Hofstaedtler <christian.hofstaedtler@deduktiva.com>
Sun, 6 Dec 2015 23:47:54 +0000 (00:47 +0100)
committerChristian Hofstaedtler <christian@hofstaedtler.name>
Wed, 9 Dec 2015 11:40:05 +0000 (12:40 +0100)
Note that this changes the URL, and only allows for exact flushing now.

Fixes #3003.

docs/markdown/httpapi/api_spec.md
pdns/ws-auth.cc
pdns/ws-recursor.cc
regression-tests.api/test_Cache.py [new file with mode: 0644]
regression-tests.api/test_Servers.py

index 29c1e9aca8533c10eb4a62309b8cb52072b32c05..1f93b06a51cad468e50c089ee07019ef60d195cc 100644 (file)
@@ -677,9 +677,25 @@ Returns all public data about cryptokeys, including `content`, with all the priv
 Cache Access
 ============
 
-**TODO**: Peek at the cache, clear the cache, possibly dump it into a file?
+**TODO**: Not yet implemented: Peek at the cache, clear the cache, possibly read cache?
+
+URL: /api/v1/servers/:server\_id/cache/flush?domain=:domain
+--------------------------------------------
+
+Allowed methods: `PUT` (Execute)
+
+#### PUT (Execute)
+
+Flush the cache for a given domain name `:domain`. Response body:
+
+    {
+      "count": 10,
+      "result": "Flushed cache."
+    }
+
+Implementation detail: On Authoritative servers, this clears the packet cache.
+On Recursors, this clears the positive, negative and packet cache.
 
-**TODO**: Not yet implemented.
 
 Logging & Statistics
 ====================
@@ -691,7 +707,7 @@ Allowed methods: `GET` (Query)
 
 #### GET (Query)
 
-Query the log, filtered by `:search_term`. Response body:
+Query the log, filtered by `:search_term` (query parameter). Response body:
 
     [
       "<log_line>",
index 30402fc1b8dbee157bca693be915cf938ea06151..6f7a2659b4fc1379c3f297074216c28e514ddbf6 100644 (file)
@@ -1160,16 +1160,14 @@ static void apiServerSearchData(HttpRequest* req, HttpResponse* resp) {
   resp->setBody(doc);
 }
 
-void apiServerFlushCache(HttpRequest* req, HttpResponse* resp) {
+void apiServerCacheFlush(HttpRequest* req, HttpResponse* resp) {
   if(req->method != "PUT")
     throw HttpMethodNotAllowedException();
 
+  DNSName canon = apiNameToDNSName(req->getvars["domain"]);
+
   extern PacketCache PC;
-  int count;
-  if(req->getvars["domain"].empty())
-    count = PC.purge();
-  else
-    count = PC.purge(req->getvars["domain"]);
+  int count = PC.purgeExact(canon);
 
   map<string, string> object;
   object["count"] = lexical_cast<string>(count);
@@ -1217,8 +1215,8 @@ void AuthWebServer::webThread()
 {
   try {
     if(::arg().mustDo("api")) {
+      d_ws->registerApiHandler("/api/v1/servers/localhost/cache/flush", &apiServerCacheFlush);
       d_ws->registerApiHandler("/api/v1/servers/localhost/config", &apiServerConfig);
-      d_ws->registerApiHandler("/api/v1/servers/localhost/flush-cache", &apiServerFlushCache);
       d_ws->registerApiHandler("/api/v1/servers/localhost/search-log", &apiServerSearchLog);
       d_ws->registerApiHandler("/api/v1/servers/localhost/search-data", &apiServerSearchData);
       d_ws->registerApiHandler("/api/v1/servers/localhost/statistics", &apiServerStatistics);
index 2755bdea57aa2777a3dd8bb9c5abd26459a57450..ccb6778ccf81c05eaefddf7370d670a37270e935 100644 (file)
@@ -411,12 +411,14 @@ static void apiServerSearchData(HttpRequest* req, HttpResponse* resp) {
   resp->setBody(doc);
 }
 
-static void apiServerFlushCache(HttpRequest* req, HttpResponse* resp) {
+static void apiServerCacheFlush(HttpRequest* req, HttpResponse* resp) {
   if(req->method != "PUT")
     throw HttpMethodNotAllowedException();
 
-  DNSName canon(req->getvars["domain"]);
+  DNSName canon = apiNameToDNSName(req->getvars["domain"]);
+
   int count = broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, canon, false));
+  count += broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, canon, false));
   count += broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, canon, false));
   map<string, string> object;
   object["count"] = lexical_cast<string>(count);
@@ -433,7 +435,7 @@ RecursorWebServer::RecursorWebServer(FDMultiplexer* fdm)
 
   // legacy dispatch
   d_ws->registerApiHandler("/jsonstat", boost::bind(&RecursorWebServer::jsonstat, this, _1, _2));
-  d_ws->registerApiHandler("/api/v1/servers/localhost/flush-cache", &apiServerFlushCache);
+  d_ws->registerApiHandler("/api/v1/servers/localhost/cache/flush", &apiServerCacheFlush);
   d_ws->registerApiHandler("/api/v1/servers/localhost/config/allow-from", &apiServerConfigAllowFrom);
   d_ws->registerApiHandler("/api/v1/servers/localhost/config", &apiServerConfig);
   d_ws->registerApiHandler("/api/v1/servers/localhost/search-log", &apiServerSearchLog);
diff --git a/regression-tests.api/test_Cache.py b/regression-tests.api/test_Cache.py
new file mode 100644 (file)
index 0000000..6a3f618
--- /dev/null
@@ -0,0 +1,27 @@
+from test_helper import ApiTestCase, is_auth, is_recursor
+
+
+class Servers(ApiTestCase):
+
+    def test_flush(self):
+        r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=example.org."))
+        self.assert_success_json(r)
+        data = r.json()
+        self.assertIn('count', data)
+
+    def test_flush_root(self):
+        r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=."))
+        self.assert_success_json(r)
+        data = r.json()
+        self.assertIn('count', data)
+        self.assertEqual(data['result'], 'Flushed cache.')
+
+    def test_flush_no_domain(self):
+        r = self.session.put(
+            self.url("/api/v1/servers/localhost/cache/flush"))
+        self.assertEquals(r.status_code, 422)
+
+    def test_flush_unqualified(self):
+        r = self.session.put(
+            self.url("/api/v1/servers/localhost/cache/flush?domain=bar"))
+        self.assertEquals(r.status_code, 422)
index 28067858fc86bb7035e1995f3b6202c7574f070c..7b08d763ab620633dff890842789f9094c7d98b0 100644 (file)
@@ -41,16 +41,3 @@ class Servers(ApiTestCase):
         self.assert_success_json(r)
         data = dict([(r['name'], r['value']) for r in r.json()])
         self.assertIn('uptime', data)
-
-    def test_flush_cache(self):
-        r = self.session.put(self.url("/api/v1/servers/localhost/flush-cache?domain=example.org."))
-        self.assert_success_json(r)
-        data = r.json()
-        self.assertIn('count', data)
-
-    def test_flush_complete_cache(self):
-        r = self.session.put(self.url("/api/v1/servers/localhost/flush-cache"))
-        self.assert_success_json(r)
-        data = r.json()
-        self.assertIn('count', data)
-        self.assertEqual(data['result'], 'Flushed cache.')