]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Deprecate parameters to webserver(), add 'statsRequireAuthentication' parameter
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 13 Jan 2021 17:35:02 +0000 (18:35 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 13 Jan 2021 17:35:02 +0000 (18:35 +0100)
This PR deprecates the use of additional parameters with `webserver()`,
as the syntax is confusing and could lead to believe that the parameters
are per-instance while they actually are global.
Also implements an additional 'statsRequireAuthentication' parameter
to allow scraping the statistics without any kind of authentication,
which is useful to Prometheus setups with dynamic service discovery.

pdns/dnsdist-console.cc
pdns/dnsdist-lua.cc
pdns/dnsdist-web.cc
pdns/dnsdistdist/dnsdist-web.hh
pdns/dnsdistdist/docs/reference/config.rst
regression-tests.dnsdist/test_API.py
regression-tests.dnsdist/test_DynBlocks.py
regression-tests.dnsdist/test_Prometheus.py
regression-tests.dnsdist/test_TCPFastOpen.py

index c2ac58bed05b3e5c0df3523847fce170324ff464..29a555dd0b6b8ea609fc05281b8e0c9d8e7f37d8 100644 (file)
@@ -578,7 +578,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "setUDPMultipleMessagesVectorSize", true, "n", "set the size of the vector passed to recvmmsg() to receive UDP messages. Default to 1 which means that the feature is disabled and recvmsg() is used instead" },
   { "setUDPTimeout", true, "n", "set the maximum time dnsdist will wait for a response from a backend over UDP, in seconds" },
   { "setVerboseHealthChecks", true, "bool", "set whether health check errors will be logged" },
-  { "setWebserverConfig", true, "[{password=string, apiKey=string, customHeaders}]", "Updates webserver configuration" },
+  { "setWebserverConfig", true, "[{password=string, apiKey=string, customHeaders, statsRequireAuthentication}]", "Updates webserver configuration" },
   { "setWeightedBalancingFactor", true, "factor", "Set the balancing factor for bounded-load weighted policies (whashed, wrandom)" },
   { "setWHashedPertubation", true, "value", "Set the hash perturbation value to be used in the whashed policy instead of a random one, allowing to have consistent whashed results on different instance" },
   { "show", true, "string", "outputs `string`" },
@@ -635,7 +635,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "TrailingDataRule", true, "", "Matches if the query has trailing data" },
   { "truncateTC", true, "bool", "if set (defaults to no starting with dnsdist 1.2.0) truncate TC=1 answers so they are actually empty. Fixes an issue for PowerDNS Authoritative Server 2.9.22. Note: turning this on breaks compatibility with RFC 6891." },
   { "unregisterDynBPFFilter", true, "DynBPFFilter", "unregister this dynamic BPF filter" },
-  { "webserver", true, "address:port, password [, apiKey [, customHeaders ]])", "launch a webserver with stats on that address with that password" },
+  { "webserver", true, "address:port", "launch a webserver with stats on that address" },
   { "whashed", false, "", "Weighted hashed ('sticky') distribution over available servers, based on the server 'weight' parameter" },
   { "chashed", false, "", "Consistent hashed ('sticky') distribution over available servers, also based on the server 'weight' parameter" },
   { "wrandom", false, "", "Weighted random over available servers, based on the server 'weight' parameter" },
index e8049beb345d33b7365db44cb5b26b4645d55c9e..0981a40bf75724f7711693c538f2e3fdc72fed9f 100644 (file)
@@ -841,7 +841,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       g_carbon.setState(ours);
   });
 
-  luaCtx.writeFunction("webserver", [client,configCheck](const std::string& address, const std::string& password, const boost::optional<std::string> apiKey, const boost::optional<std::map<std::string, std::string> > customHeaders, const boost::optional<std::string> acl) {
+  luaCtx.writeFunction("webserver", [client,configCheck](const std::string& address, const boost::optional<std::string> password, const boost::optional<std::string> apiKey, const boost::optional<std::map<std::string, std::string> > customHeaders, const boost::optional<std::string> acl) {
       setLuaSideEffect();
       ComboAddress local;
       try {
@@ -855,15 +855,28 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         return;
       }
 
+      if (password || apiKey || customHeaders || acl) {
+       warnlog("Passing additional parameters to 'webserver()' is deprecated, please use 'setWebserverConfig()' instead.");
+      }
+
       try {
        int sock = SSocket(local.sin4.sin_family, SOCK_STREAM, 0);
        SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
        SBind(sock, local);
        SListen(sock, 5);
        auto launch=[sock, local, password, apiKey, customHeaders, acl]() {
-          setWebserverPassword(password);
-          setWebserverAPIKey(apiKey);
-          setWebserverCustomHeaders(customHeaders);
+          if (password) {
+            setWebserverPassword(*password);
+          }
+
+          if (apiKey) {
+            setWebserverAPIKey(apiKey);
+          }
+
+          if (customHeaders) {
+            setWebserverCustomHeaders(customHeaders);
+          }
+
           if (acl) {
             setWebserverACL(*acl);
           }
@@ -877,14 +890,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
          launch();
         }
       }
-      catch(std::exception& e) {
+      catch (const std::exception& e) {
        g_outputBuffer="Unable to bind to webserver socket on " + local.toStringWithPort() + ": " + e.what();
        errlog("Unable to bind to webserver socket on %s: %s", local.toStringWithPort(), e.what());
       }
 
     });
 
-  typedef std::unordered_map<std::string, boost::variant<std::string, std::map<std::string, std::string>> > webserveropts_t;
+  typedef std::unordered_map<std::string, boost::variant<bool, std::string, std::map<std::string, std::string>> > webserveropts_t;
 
   luaCtx.writeFunction("setWebserverConfig", [](boost::optional<webserveropts_t> vars) {
       setLuaSideEffect();
@@ -892,26 +905,34 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       if (!vars) {
         return ;
       }
-      if(vars->count("password")) {
+
+      if (vars->count("password")) {
         const std::string password = boost::get<std::string>(vars->at("password"));
 
         setWebserverPassword(password);
       }
-      if(vars->count("apiKey")) {
+
+      if (vars->count("apiKey")) {
         const std::string apiKey = boost::get<std::string>(vars->at("apiKey"));
 
         setWebserverAPIKey(apiKey);
       }
+
       if (vars->count("acl")) {
         const std::string acl = boost::get<std::string>(vars->at("acl"));
 
         setWebserverACL(acl);
       }
-      if(vars->count("customHeaders")) {
+
+      if (vars->count("customHeaders")) {
         const boost::optional<std::map<std::string, std::string> > headers = boost::get<std::map<std::string, std::string> >(vars->at("customHeaders"));
 
         setWebserverCustomHeaders(headers);
       }
+
+      if (vars->count("statsRequireAuthentication")) {
+        setWebserverStatsRequireAuthentication(boost::get<bool>(vars->at("statsRequireAuthentication")));
+      }
     });
 
   luaCtx.writeFunction("controlSocket", [client,configCheck](const std::string& str) {
index 0dc9a19b22020c9bafc5be7ce676a44abc8ed130..ebba297f71de94156596e6bb687c3dbe7e917d38 100644 (file)
 #include "threadname.hh"
 #include "sstuff.hh"
 
+struct WebserverConfig
+{
+  WebserverConfig()
+  {
+    acl.toMasks("127.0.0.1, ::1");
+  }
+
+  std::mutex lock;
+  NetmaskGroup acl;
+  std::string password;
+  std::string apiKey;
+  boost::optional<std::map<std::string, std::string> > customHeaders;
+  bool statsRequireAuthentication{true};
+};
+
 bool g_apiReadWrite{false};
 WebserverConfig g_webserverConfig;
 std::string g_apiConfigDirectory;
@@ -190,10 +205,19 @@ static bool isAStatsRequest(const YaHTTP::Request& req)
   return req.url.path == "/jsonstat" || req.url.path == "/metrics";
 }
 
-static bool compareAuthorization(const YaHTTP::Request& req)
+static bool handleAuthorization(const YaHTTP::Request& req)
 {
+  cerr<<"handling auth for "<<req.url.path<<endl;
   std::lock_guard<std::mutex> lock(g_webserverConfig.lock);
 
+  if (isAStatsRequest(req)) {
+    if (g_webserverConfig.statsRequireAuthentication) {
+      /* Access to the stats is allowed for both API and Web users */
+      return checkAPIKey(req, g_webserverConfig.apiKey) || checkWebPassword(req, g_webserverConfig.password);
+    }
+    return true;
+  }
+
   if (isAnAPIRequest(req)) {
     /* Access to the API requires a valid API key */
     if (checkAPIKey(req, g_webserverConfig.apiKey)) {
@@ -203,11 +227,6 @@ static bool compareAuthorization(const YaHTTP::Request& req)
     return isAnAPIRequestAllowedWithWebAuth(req) && checkWebPassword(req, g_webserverConfig.password);
   }
 
-  if (isAStatsRequest(req)) {
-    /* Access to the stats is allowed for both API and Web users */
-    return checkAPIKey(req, g_webserverConfig.apiKey) || checkWebPassword(req, g_webserverConfig.password);
-  }
-
   return checkWebPassword(req, g_webserverConfig.password);
 }
 
@@ -1276,7 +1295,7 @@ static void connectionThread(int sockFD, ComboAddress remote)
       handleCORS(req, resp);
       resp.status = 200;
     }
-    else if (!compareAuthorization(req)) {
+    else if (!handleAuthorization(req)) {
       YaHTTP::strstr_map_t::iterator header = req.headers.find("authorization");
       if (header != req.headers.end()) {
         errlog("HTTP Request \"%s\" from %s: Web Authentication failed", req.url.path, remote.toStringWithPort());
@@ -1350,11 +1369,25 @@ void setWebserverCustomHeaders(const boost::optional<std::map<std::string, std::
   g_webserverConfig.customHeaders = customHeaders;
 }
 
+void setWebserverStatsRequireAuthentication(bool require)
+{
+  std::lock_guard<std::mutex> lock(g_webserverConfig.lock);
+
+  g_webserverConfig.statsRequireAuthentication = require;
+}
+
 void dnsdistWebserverThread(int sock, const ComboAddress& local)
 {
   setThreadName("dnsdist/webserv");
   warnlog("Webserver launched on %s", local.toStringWithPort());
 
+  {
+    std::lock_guard<std::mutex> lock(g_webserverConfig.lock);
+    if (g_webserverConfig.password.empty()) {
+      warnlog("Webserver launched on %s without a password set!", local.toStringWithPort());
+    }
+  }
+
   for(;;) {
     try {
       ComboAddress remote(local);
index 889139f6d0230bfa5222ba3cdf5a8d3f41c0cc4d..d0d70e6821c335619d1c2cf0602a1165012b65b9 100644 (file)
@@ -1,23 +1,10 @@
 #pragma once
 
-struct WebserverConfig
-{
-  WebserverConfig()
-  {
-    acl.toMasks("127.0.0.1, ::1");
-  }
-
-  NetmaskGroup acl;
-  std::string password;
-  std::string apiKey;
-  boost::optional<std::map<std::string, std::string> > customHeaders;
-  std::mutex lock;
-};
-
 void setWebserverAPIKey(const boost::optional<std::string> apiKey);
 void setWebserverPassword(const std::string& password);
 void setWebserverACL(const std::string& acl);
 void setWebserverCustomHeaders(const boost::optional<std::map<std::string, std::string> > customHeaders);
+void setWebserverStatsRequireAuthentication(bool);
 
 void dnsdistWebserverThread(int sock, const ComboAddress& local);
 
index a6f848dd42c7d87774165f7f6320a64fb07f371e..de4687d00bd567bcbab0fe6ddb3d0a0024d2f1c8 100644 (file)
@@ -316,12 +316,17 @@ Control Socket, Console and Webserver
 Webserver configuration
 ~~~~~~~~~~~~~~~~~~~~~~~
 
-.. function:: webserver(listen_address, password[, apikey[, custom_headers[, acl]]])
+.. function:: webserver(listen_address [, password[, apikey[, custom_headers[, acl]]]])
 
   .. versionchanged:: 1.5.0
     ``acl`` optional parameter added.
 
-  Launch the :doc:`../guides/webserver` with statistics and the API.
+  .. versionchanged:: 1.6.0
+    The ``password`` parameter is now optional.
+    The use of optional parameters is now deprecated. Please use :func:`setWebserverConfig` instead.
+
+  Launch the :doc:`../guides/webserver` with statistics and the API. Note that the parameters are global, so the parameter from the last ``webserver`` will override any existing ones. For this reason
+  the use of :func:`setWebserverConfig` is advised instead of specifying optional parameters here.
 
   :param str listen_address: The IP address and Port to listen on
   :param str password: The password required to access the webserver
@@ -345,6 +350,9 @@ Webserver configuration
   .. versionchanged:: 1.5.0
     ``acl`` optional parameter added.
 
+  .. versionchanged:: 1.6.0
+    ``statsRequireAuthentication`` optional parameter added.
+
   Setup webserver configuration. See :func:`webserver`.
 
   :param table options: A table with key: value pairs with webserver options.
@@ -355,6 +363,7 @@ Webserver configuration
   * ``apiKey=newKey``: string - Changes the API Key (set to an empty string do disable it)
   * ``custom_headers={[str]=str,...}``: map of string - Allows setting custom headers and removing the defaults.
   * ``acl=newACL``: string - List of IP addresses, as a string, that are allowed to open a connection to the web server. Defaults to "127.0.0.1, ::1".
+  * ``statsRequireAuthentication``: bool - Whether access to the statistics (/metrics and /jsonstat endpoints) require a valid password or API key. Defaults to true.
 
 .. function:: registerWebHandler(path, handler)
 
index 34193049455d28903abf17bea57b29c2b5fd198f..327c781a5b880a0ad136a30f0aa0f1923f4cc4da 100644 (file)
@@ -22,7 +22,8 @@ class TestAPIBasics(DNSDistTest):
     _config_template = """
     setACL({"127.0.0.1/32", "::1/128"})
     newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     def testBasicAuth(self):
@@ -305,7 +306,8 @@ class TestAPIServerDown(DNSDistTest):
     setACL({"127.0.0.1/32", "::1/128"})
     newServer{address="127.0.0.1:%s"}
     getServer(0):setDown()
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     def testServerDownNoLatencyLocalhost(self):
@@ -333,7 +335,8 @@ class TestAPIWritable(DNSDistTest):
     _config_template = """
     setACL({"127.0.0.1/32", "::1/128"})
     newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     setAPIWritable(true, "%s")
     """
 
@@ -412,7 +415,8 @@ class TestAPICustomHeaders(DNSDistTest):
     controlSocket("127.0.0.1:%s")
     setACL({"127.0.0.1/32", "::1/128"})
     newServer({address="127.0.0.1:%s"})
-    webserver("127.0.0.1:%s", "%s", "%s", {["X-Frame-Options"]="", ["X-Custom"]="custom"})
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s", customHeaders={["X-Frame-Options"]="", ["X-Custom"]="custom"} })
     """
 
     def testBasicHeaders(self):
@@ -441,6 +445,63 @@ class TestAPICustomHeaders(DNSDistTest):
         self.assertEquals(r.headers.get('x-powered-by'), "dnsdist")
         self.assertTrue("x-frame-options" in r.headers)
 
+class TestStatsWithoutAuthentication(DNSDistTest):
+
+    _webTimeout = 2.0
+    _webServerPort = 8083
+    _webServerBasicAuthPassword = 'secret'
+    _webServerAPIKey = 'apisecret'
+    # paths accessible using the API key only
+    _apiOnlyPath = '/api/v1/servers/localhost/config'
+    # paths accessible using basic auth only (list not exhaustive)
+    _basicOnlyPath = '/'
+    _noAuthenticationPaths = [ '/metrics', '/jsonstat?command=dynblocklist' ]
+    _consoleKey = DNSDistTest.generateConsoleKey()
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
+    _config_template = """
+    setKey("%s")
+    controlSocket("127.0.0.1:%s")
+    setACL({"127.0.0.1/32", "::1/128"})
+    newServer({address="127.0.0.1:%s"})
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s", statsRequireAuthentication=false })
+    """
+
+    def testAuth(self):
+        """
+        API: Stats do not require authentication
+        """
+
+        for path in self._noAuthenticationPaths:
+            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+
+            r = requests.get(url, timeout=self._webTimeout)
+            self.assertTrue(r)
+            self.assertEquals(r.status_code, 200)
+
+        # these should still require basic authentication
+        for path in [self._basicOnlyPath]:
+            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+
+            r = requests.get(url, timeout=self._webTimeout)
+            self.assertEquals(r.status_code, 401)
+
+            r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+            self.assertTrue(r)
+            self.assertEquals(r.status_code, 200)
+
+        # these should still require API authentication
+        for path in [self._apiOnlyPath]:
+            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+
+            r = requests.get(url, timeout=self._webTimeout)
+            self.assertEquals(r.status_code, 401)
+
+            headers = {'x-api-key': self._webServerAPIKey}
+            r = requests.get(url, headers=headers, timeout=self._webTimeout)
+            self.assertTrue(r)
+            self.assertEquals(r.status_code, 200)
 
 class TestAPIAuth(DNSDistTest):
 
@@ -462,7 +523,8 @@ class TestAPIAuth(DNSDistTest):
     controlSocket("127.0.0.1:%s")
     setACL({"127.0.0.1/32", "::1/128"})
     newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     def testBasicAuthChange(self):
@@ -532,7 +594,8 @@ class TestAPIACL(DNSDistTest):
     controlSocket("127.0.0.1:%s")
     setACL({"127.0.0.1/32", "::1/128"})
     newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s", "%s", "%s", {}, "192.0.2.1")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s", acl="192.0.2.1"})
     """
 
     def testACLChange(self):
index 53b8935e71e888f00c55de9a4b07450df53af78a..5b174e703c353077fd712472664f2541028d8831 100644 (file)
@@ -560,14 +560,15 @@ class TestDynBlockQPS(DynBlocksTest):
     _dynBlockQPS = 10
     _dynBlockPeriod = 2
     _dynBlockDuration = 5
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
     function maintenance()
            addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d)
     end
     newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
+    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
 
     def testDynBlocksQRate(self):
         """
@@ -581,7 +582,6 @@ class TestDynBlockGroupQPS(DynBlocksTest):
     _dynBlockQPS = 10
     _dynBlockPeriod = 2
     _dynBlockDuration = 5
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
@@ -590,8 +590,10 @@ class TestDynBlockGroupQPS(DynBlocksTest):
            dbr:apply()
     end
     newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
+    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
 
     def testDynBlocksQRate(self):
         """
@@ -1073,7 +1075,6 @@ class TestDynBlockGroupNoOp(DynBlocksTest):
     _dynBlockQPS = 10
     _dynBlockPeriod = 2
     _dynBlockDuration = 5
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.NoOp)
@@ -1083,8 +1084,10 @@ class TestDynBlockGroupNoOp(DynBlocksTest):
     end
 
     newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
+    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
 
     def testNoOp(self):
         """
@@ -1136,7 +1139,6 @@ class TestDynBlockGroupWarning(DynBlocksTest):
     _dynBlockQPS = 20
     _dynBlockPeriod = 2
     _dynBlockDuration = 5
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_dynBlockWarningQPS', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.Drop, %d)
@@ -1146,8 +1148,10 @@ class TestDynBlockGroupWarning(DynBlocksTest):
     end
 
     newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
+    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_dynBlockWarningQPS', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
 
     def testWarning(self):
         """
index 621c62020a16c3fe87d1ebe04533d67b556d7374..4b28f6a652e2e2663b6d1ac3707bbad3d09b4c11 100644 (file)
@@ -15,7 +15,8 @@ class TestPrometheus(DNSDistTest):
     _config_params = ['_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
     newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     def checkPrometheusContentBasic(self, content):
index 9b7582734ec88c4068455f5a18829d0a875e5172..58d9c96a26ffae2683d42e7fa0ddefddbd53d3c3 100644 (file)
@@ -22,7 +22,8 @@ class TestBrokenTCPFastOpen(DNSDistTest):
     _config_params = ['_testServerPort', '_testServerRetries', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
     newServer{address="127.0.0.1:%s", useClientSubnet=true, tcpFastOpen=true, retries=%d }
-    webserver("127.0.0.1:%s", "%s", "%s")
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     @classmethod