From: Charles-Henri Bruyand Date: Wed, 2 May 2018 12:07:13 +0000 (+0200) Subject: rec api: add subtree option to the cache flush endpoint X-Git-Tag: dnsdist-1.3.1~108^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d19c22a15f8e75ebc6ff22665ba8e8c2152957db;p=pdns rec api: add subtree option to the cache flush endpoint --- diff --git a/pdns/recursordist/docs/http-api/endpoint-cache.rst b/pdns/recursordist/docs/http-api/endpoint-cache.rst index 7a7848deb..4b642f32d 100644 --- a/pdns/recursordist/docs/http-api/endpoint-cache.rst +++ b/pdns/recursordist/docs/http-api/endpoint-cache.rst @@ -7,6 +7,7 @@ Cache manipulation endpoint :query server_id: The name of the server :query domain: The domainname to flush for + :query subtree: If set to `true`, also flush the whole subtree (default=`false`) **Example Response:** diff --git a/pdns/ws-recursor.cc b/pdns/ws-recursor.cc index 2d153f7dc..a9991dfef 100644 --- a/pdns/ws-recursor.cc +++ b/pdns/ws-recursor.cc @@ -373,10 +373,11 @@ static void apiServerCacheFlush(HttpRequest* req, HttpResponse* resp) { throw HttpMethodNotAllowedException(); DNSName canon = apiNameToDNSName(req->getvars["domain"]); + bool subtree = (req->getvars["subtree"].compare("true") == 0); - int count = broadcastAccFunction(boost::bind(pleaseWipeCache, canon, false)); - count += broadcastAccFunction(boost::bind(pleaseWipePacketCache, canon, false)); - count += broadcastAccFunction(boost::bind(pleaseWipeAndCountNegCache, canon, false)); + int count = broadcastAccFunction(boost::bind(pleaseWipeCache, canon, subtree)); + count += broadcastAccFunction(boost::bind(pleaseWipePacketCache, canon, subtree)); + count += broadcastAccFunction(boost::bind(pleaseWipeAndCountNegCache, canon, subtree)); resp->setBody(Json::object { { "count", count }, { "result", "Flushed cache." } diff --git a/regression-tests.api/runtests.py b/regression-tests.api/runtests.py index 9d2fb6c60..6278815e6 100755 --- a/regression-tests.api/runtests.py +++ b/regression-tests.api/runtests.py @@ -185,6 +185,8 @@ test_env.update({ 'DAEMON': daemon, 'SQLITE_DB': SQLITE_DB, 'PDNSUTIL_CMD': ' '.join(PDNSUTIL_CMD), + 'SDIG': sdig, + 'DNSPORT': str(DNSPORT) }) try: diff --git a/regression-tests.api/test_Cache.py b/regression-tests.api/test_Cache.py index 6a3f618d5..ad2c8503c 100644 --- a/regression-tests.api/test_Cache.py +++ b/regression-tests.api/test_Cache.py @@ -1,4 +1,4 @@ -from test_helper import ApiTestCase, is_auth, is_recursor +from test_helper import ApiTestCase, is_auth, is_recursor, sdig class Servers(ApiTestCase): @@ -9,6 +9,28 @@ class Servers(ApiTestCase): data = r.json() self.assertIn('count', data) + def test_flush_count(self): + sdig("ns1.example.com", 'A') + r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=ns1.example.com.")) + self.assert_success_json(r) + data = r.json() + self.assertIn('count', data) + self.assertEquals(1, data['count']) + + def test_flush_subtree(self): + sdig("ns1.example.com", 'A') + sdig("ns2.example.com", 'A') + r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=example.com.&subtree=false")) + self.assert_success_json(r) + data = r.json() + self.assertIn('count', data) + self.assertEquals(1, data['count']) + r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=example.com.&subtree=true")) + self.assert_success_json(r) + data = r.json() + self.assertIn('count', data) + self.assertEquals(2, data['count']) + def test_flush_root(self): r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=.")) self.assert_success_json(r) diff --git a/regression-tests.api/test_helper.py b/regression-tests.api/test_helper.py index 8c1dfd375..2affa83a4 100644 --- a/regression-tests.api/test_helper.py +++ b/regression-tests.api/test_helper.py @@ -11,11 +11,11 @@ if sys.version_info[0] == 2: else: from urllib.parse import urljoin - DAEMON = os.environ.get('DAEMON', 'authoritative') PDNSUTIL_CMD = os.environ.get('PDNSUTIL_CMD', 'NOT_SET BUT_THIS MIGHT_BE_A_LIST').split(' ') SQLITE_DB = os.environ.get('SQLITE_DB', 'pdns.sqlite3') - +SDIG = os.environ.get('SDIG', 'sdig') +DNSPORT = os.environ.get('DNSPORT', '53') class ApiTestCase(unittest.TestCase): @@ -86,7 +86,12 @@ def pdnsutil(subcommand, *args): except subprocess.CalledProcessError as except_inst: raise RuntimeError("pdnsutil %s %s failed: %s" % (command, args, except_inst.output.decode('ascii', errors='replace'))) - def pdnsutil_rectify(zonename): """Run pdnsutil rectify-zone on the given zone.""" pdnsutil('rectify-zone', zonename) + +def sdig(*args): + try: + return subprocess.check_call([SDIG, '127.0.0.1', str(DNSPORT)] + list(args)) + except subprocess.CalledProcessError as except_inst: + raise RuntimeError("sdig %s %s failed: %s" % (command, args, except_inst.output.decode('ascii', errors='replace')))