From c0f6a1da6320c428e65eb6d6879cca972cd1eb92 Mon Sep 17 00:00:00 2001 From: Christian Hofstaedtler Date: Mon, 7 Dec 2015 00:47:54 +0100 Subject: [PATCH] API: make cache flushing a public, documented operation Note that this changes the URL, and only allows for exact flushing now. Fixes #3003. --- docs/markdown/httpapi/api_spec.md | 22 +++++++++++++++++++--- pdns/ws-auth.cc | 12 +++++------- pdns/ws-recursor.cc | 8 +++++--- regression-tests.api/test_Cache.py | 27 +++++++++++++++++++++++++++ regression-tests.api/test_Servers.py | 13 ------------- 5 files changed, 56 insertions(+), 26 deletions(-) create mode 100644 regression-tests.api/test_Cache.py diff --git a/docs/markdown/httpapi/api_spec.md b/docs/markdown/httpapi/api_spec.md index 29c1e9aca..1f93b06a5 100644 --- a/docs/markdown/httpapi/api_spec.md +++ b/docs/markdown/httpapi/api_spec.md @@ -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: [ "", diff --git a/pdns/ws-auth.cc b/pdns/ws-auth.cc index 30402fc1b..6f7a2659b 100644 --- a/pdns/ws-auth.cc +++ b/pdns/ws-auth.cc @@ -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 object; object["count"] = lexical_cast(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); diff --git a/pdns/ws-recursor.cc b/pdns/ws-recursor.cc index 2755bdea5..ccb6778cc 100644 --- a/pdns/ws-recursor.cc +++ b/pdns/ws-recursor.cc @@ -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(boost::bind(pleaseWipeCache, canon, false)); + count += broadcastAccFunction(boost::bind(pleaseWipePacketCache, canon, false)); count += broadcastAccFunction(boost::bind(pleaseWipeAndCountNegCache, canon, false)); map object; object["count"] = lexical_cast(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 index 000000000..6a3f618d5 --- /dev/null +++ b/regression-tests.api/test_Cache.py @@ -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) diff --git a/regression-tests.api/test_Servers.py b/regression-tests.api/test_Servers.py index 28067858f..7b08d763a 100644 --- a/regression-tests.api/test_Servers.py +++ b/regression-tests.api/test_Servers.py @@ -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.') -- 2.40.0