]> granicus.if.org Git - pdns/commitdiff
dnsdist: Add Pools, cacheHitResponseRules to the API
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 30 Nov 2017 09:47:34 +0000 (10:47 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 30 Nov 2017 09:50:01 +0000 (10:50 +0100)
pdns/dnsdist-web.cc
pdns/dnsdistdist/docs/guides/webserver.rst
regression-tests.dnsdist/test_API.py

index feb0ff6a6867e648aa9bfcaccfb4da346667eaf0..3d5186156062284917e56b997c9b7f9dddcb8209 100644 (file)
@@ -375,6 +375,7 @@ static void connectionThread(int sock, ComboAddress remote, string password, str
          status = "DOWN";
        else 
          status = (a->upStatus ? "up" : "down");
+
        Json::array pools;
        for(const auto& p: a->pools)
          pools.push_back(p);
@@ -392,7 +393,9 @@ static void connectionThread(int sock, ComboAddress remote, string password, str
           {"order", (int)a->order},
           {"pools", pools},
           {"latency", (int)(a->latencyUsec/1000.0)},
-          {"queries", (double)a->queries}};
+          {"queries", (double)a->queries},
+          {"sendErrors", (int)a->sendErrors}
+        };
 
         /* sending a latency for a DOWN server doesn't make sense */
         if (a->availability == DownstreamState::Availability::Down) {
@@ -417,16 +420,38 @@ static void connectionThread(int sock, ComboAddress remote, string password, str
         frontends.push_back(frontend);
       }
 
+      Json::array pools;
+      auto localPools = g_pools.getCopy();
+      num=0;
+      for(const auto& pool :localPools) {
+        const auto& cache = pool.second->packetCache;
+        Json::object entry {
+          { "id", num++ },
+          { "name", pool.first },
+          { "serversCount", (int) pool.second->servers.size() },
+          { "cacheSize", (double) (cache ? cache->getMaxEntries() : 0) },
+          { "cacheEntries", (double) (cache ? cache->getEntriesCount() : 0) },
+          { "cacheHits", (double) (cache ? cache->getHits() : 0) },
+          { "cacheMisses", (double) (cache ? cache->getMisses() : 0) },
+          { "cacheDeferredInserts", (double) (cache ? cache->getDeferredInserts() : 0) },
+          { "cacheDeferredLookups", (double) (cache ? cache->getDeferredLookups() : 0) },
+          { "cacheLookupCollisions", (double) (cache ? cache->getLookupCollisions() : 0) },
+          { "cacheInsertCollisions", (double) (cache ? cache->getInsertCollisions() : 0) },
+          { "cacheTTLTooShorts", (double) (cache ? cache->getTTLTooShorts() : 0) }
+        };
+        pools.push_back(entry);
+      }
+
       Json::array rules;
       auto localRules = g_rulactions.getCopy();
       num=0;
       for(const auto& a : localRules) {
        Json::object rule{
-         {"id", num++},
-         {"matches", (double)a.first->d_matches},
-         {"rule", a.first->toString()},
-          {"action", a.second->toString()}, 
-          {"action-stats", a.second->getStats()} 
+          {"id", num++},
+          {"matches", (double)a.first->d_matches},
+          {"rule", a.first->toString()},
+          {"action", a.second->toString()},
+          {"action-stats", a.second->getStats()}
         };
        rules.push_back(rule);
       }
@@ -444,6 +469,19 @@ static void connectionThread(int sock, ComboAddress remote, string password, str
         responseRules.push_back(rule);
       }
 
+      Json::array cacheHitResponseRules;
+      num=0;
+      auto localCacheHitResponseRules = g_cachehitresprulactions.getCopy();
+      for(const auto& a : localCacheHitResponseRules) {
+        Json::object rule{
+          {"id", num++},
+          {"matches", (double)a.first->d_matches},
+          {"rule", a.first->toString()},
+          {"action", a.second->toString()},
+        };
+        cacheHitResponseRules.push_back(rule);
+      }
+
       string acl;
 
       vector<string> vec;
@@ -451,7 +489,7 @@ static void connectionThread(int sock, ComboAddress remote, string password, str
 
       for(const auto& s : vec) {
         if(!acl.empty()) acl += ", ";
-        acl+=s;      
+        acl+=s;
       }
       string localaddresses;
       for(const auto& loc : g_locals) {
@@ -460,14 +498,16 @@ static void connectionThread(int sock, ComboAddress remote, string password, str
       }
  
       Json my_json = Json::object {
-       { "daemon_type", "dnsdist" },
-       { "version", VERSION},
-       { "servers", servers},
-       { "frontends", frontends },
-       { "rules", rules},
-       { "response-rules", responseRules},
-       { "acl", acl},
-       { "local", localaddresses}
+        { "daemon_type", "dnsdist" },
+        { "version", VERSION},
+        { "servers", servers},
+        { "frontends", frontends },
+        { "pools", pools },
+        { "rules", rules},
+        { "response-rules", responseRules},
+        { "cache-hit-response-rules", cacheHitResponseRules},
+        { "acl", acl},
+        { "local", localaddresses}
       };
       resp.headers["Content-Type"] = "application/json";
       resp.body=my_json.dump();
index 0b57abf786448b77659a1613e7581aef033b3bad..6f3767a37e88071ddb7601d312839eca8217d589 100644 (file)
@@ -102,8 +102,10 @@ URL Endpoints
   Get a quick overview of several parameters.
 
   :>json string acl: A string of comma-separated netmasks currently allowed by the :ref:`ACL <ACL>`.
+  :>json list cache-hit-response-rules: A list of :json:object:`ResponseRule` objects applied on cache hits
   :>json string daemon_type: The type of daemon, always "dnsdist"
   :>json list frontends: A list of :json:object:`Frontend` objects
+  :>json list pools: A list of :json:object:`Pool` objects
   :>json list response-rules: A list of :json:object:`ResponseRule` objects
   :>json list rules: A list of :json:object:`Rule` objects
   :>json list servers: A list of :json:object:`Server` objects
@@ -162,12 +164,29 @@ JSON Objects
   :property boolean udp: true if this is a UDP bind
   :property boolean tcp: true if this is a TCP bind
 
+.. json:object:: Pool
+
+  A description of a pool of backend servers.
+
+  :property integer id: Internal identifier
+  :property integer cacheDeferredInserts: The number of times an entry could not be inserted in the associated cache, if any, because of a lock
+  :property integer cacheDeferredLookups: The number of times an entry could not be looked up from the associated cache, if any, because of a lock
+  :property integer cacheEntries: The current number of entries in the associated cache, if any
+  :property integer cacheHits: The number of cache hits for the associated cache, if any
+  :property integer cacheLookupCollisions: The number of times an entry retrieved from the cache based on the query hash did not match the actual query
+  :property integer cacheInsertCollisions: The number of times an entry could not be inserted into the cache because a different entry with the same hash already existed
+  :property integer cacheMisses: The number of cache misses for the associated cache, if any
+  :property integer cacheSize: The maximum number of entries in the associated cache, if any
+  :property integer cacheTTLTooShorts: The number of times an entry could not be inserted into the cache because its TTL was set below the minimum threshold
+  :property string name: Name of the pool
+  :property integer serversCount: Number of backends in this pool
+
 .. json:object:: Rule
 
   This represents a policy that is applied to queries
 
   :property string action: The action taken when the rule matches (e.g. "to pool abuse")
-  :property dict action-stats: TODO
+  :property dict action-stats: A list of statistics whose content varies depending on the kind of rule
   :property integer id: The identifier (or order) of this rule
   :property integer matches: How many times this rule was hit
   :property string rule: The matchers for the packet (e.g. "qname==bad-domain1.example., bad-domain2.example.")
@@ -176,7 +195,10 @@ JSON Objects
 
   This represents a policy that is applied to responses
 
-  TODO
+  :property string action: The action taken when the rule matches (e.g. "drop")
+  :property integer id: The identifier (or order) of this rule
+  :property integer matches: How many times this rule was hit
+  :property string rule: The matchers for the packet (e.g. "qname==bad-domain1.example., bad-domain2.example.")
 
 .. json:object:: Server
 
@@ -192,7 +214,8 @@ JSON Objects
   :property integer qps: The current number of queries per second to this server
   :property integer qpsLimit: The configured maximum number of queries per second
   :property integer queries: Total number of queries sent to this backend
-  :property integer reuseds: TODO
+  :property integer reuseds: Number of queries for which a response was not received in time
+  :property integer sendErrors: Number of network errors while sending a query to this server
   :property string state: The state of the server (e.g. "DOWN" or "up")
   :property integer weight: The weight assigned to this server
 
index 2fd53d8d4f2e19e83806f2b5bb15b88315fd8df6..c1d43b07695cd2cccaa6172724756470661ff92d 100644 (file)
@@ -78,7 +78,7 @@ class TestAPIBasics(DNSDistTest):
 
         self.assertEquals(content['daemon_type'], 'dnsdist')
 
-        for key in ['version', 'acl', 'local', 'rules', 'response-rules', 'servers', 'frontends']:
+        for key in ['version', 'acl', 'local', 'rules', 'response-rules', 'cache-hit-response-rules', 'servers', 'frontends', 'pools']:
             self.assertIn(key, content)
 
         for rule in content['rules']:
@@ -93,9 +93,15 @@ class TestAPIBasics(DNSDistTest):
             for key in ['id', 'matches']:
                 self.assertTrue(rule[key] >= 0)
 
+        for rule in content['cache-hit-response-rules']:
+            for key in ['id', 'matches', 'rule', 'action']:
+                self.assertIn(key, rule)
+            for key in ['id', 'matches']:
+                self.assertTrue(rule[key] >= 0)
+
         for server in content['servers']:
             for key in ['id', 'latency', 'name', 'weight', 'outstanding', 'qpsLimit',
-                        'reuseds', 'state', 'address', 'pools', 'qps', 'queries', 'order']:
+                        'reuseds', 'state', 'address', 'pools', 'qps', 'queries', 'order', 'sendErrors']:
                 self.assertIn(key, server)
 
             for key in ['id', 'latency', 'weight', 'outstanding', 'qpsLimit', 'reuseds',
@@ -111,6 +117,13 @@ class TestAPIBasics(DNSDistTest):
             for key in ['id', 'queries']:
                 self.assertTrue(frontend[key] >= 0)
 
+        for pool in content['pools']:
+            for key in ['id', 'name', 'cacheSize', 'cacheEntries', 'cacheHits', 'cacheMisses', 'cacheDeferredInserts', 'cacheDeferredLookups', 'cacheLookupCollisions', 'cacheInsertCollisions', 'cacheTTLTooShorts']:
+                self.assertIn(key, pool)
+
+            for key in ['id', 'cacheSize', 'cacheEntries', 'cacheHits', 'cacheMisses', 'cacheDeferredInserts', 'cacheDeferredLookups', 'cacheLookupCollisions', 'cacheInsertCollisions', 'cacheTTLTooShorts']:
+                self.assertTrue(pool[key] >= 0)
+
     def testServersIDontExist(self):
         """
         API: /api/v1/servers/idontexist (should be 404)