]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add unit tests for Lua LB policies as well
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 16 Dec 2019 17:57:31 +0000 (18:57 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 11 Feb 2020 10:49:57 +0000 (11:49 +0100)
pdns/dnsdist-lbpolicies.hh
pdns/dnsdist-lua.cc
pdns/dnsdist-snmp.cc
pdns/dnsdist.cc
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/dnsdist-lbpolicies.cc
pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc

index ce763860add8587a50dafb3e51eb37bb808ed11a..90c208da37e4a4254d63e0723ee1da42a842f233 100644 (file)
@@ -73,3 +73,4 @@ std::shared_ptr<DownstreamState> wrandom(const ServerPolicy::NumberedServerVecto
 std::shared_ptr<DownstreamState> whashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
 std::shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
 std::shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> getSelectedBackendFromPolicy(const ServerPolicy& policy, const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq);
index cef2742d45b49cdab058354f53ce9b3e669702b9..8adbb810cd730536f472fb8509e7cae779b0b4bb 100644 (file)
@@ -210,7 +210,7 @@ static void parseTLSConfig(TLSConfig& config, const std::string& context, boost:
 
 #endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
 
-void setupLuaConfig(bool client, bool configCheck)
+static void setupLuaConfig(bool client, bool configCheck)
 {
   typedef std::unordered_map<std::string, boost::variant<bool, std::string, vector<pair<int, std::string> >, DownstreamState::checkfunc_t > > newserver_t;
   g_lua.writeFunction("inClientStartup", [client]() {
index c2d0a86fcdd07f9d68f37a8962e09d38803d4968..eefa558b7baea1d4a144dcbe8babdce11505ed84 100644 (file)
@@ -52,6 +52,10 @@ static const oid specialMemoryUsageOID[] = { DNSDIST_STATS_OID, 39 };
 
 static std::unordered_map<oid, DNSDistStats::entry_t> s_statsMap;
 
+bool g_snmpEnabled{false};
+bool g_snmpTrapsEnabled{false};
+DNSDistSNMPAgent* g_snmpAgent{nullptr};
+
 /* We are never called for a GETNEXT if it's registered as a
    "instance", as it's "magically" handled for us.  */
 /* a instance handler also only hands us one request at a time, so
index c27c132dece07ca06a65555aa744fca5a4026f8d..5c5803b1c728cf6a0dacb81d5865202b11b5b7be 100644 (file)
@@ -48,7 +48,6 @@
 #include "dnsdist-ecs.hh"
 #include "dnsdist-healthchecks.hh"
 #include "dnsdist-lua.hh"
-#include "dnsdist-lua-ffi.hh"
 #include "dnsdist-rings.hh"
 #include "dnsdist-secpoll.hh"
 #include "dnsdist-xpf.hh"
@@ -103,10 +102,6 @@ std::vector<std::unique_ptr<ClientState>> g_frontends;
 GlobalStateHolder<pools_t> g_pools;
 size_t g_udpVectorSize{1};
 
-bool g_snmpEnabled{false};
-bool g_snmpTrapsEnabled{false};
-DNSDistSNMPAgent* g_snmpAgent{nullptr};
-
 /* UDP: the grand design. Per socket we listen on for incoming queries there is one thread.
    Then we have a bunch of connected sockets for talking to downstream servers. 
    We send directly to those sockets.
@@ -1181,25 +1176,7 @@ ProcessQueryResult processQuery(DNSQuestion& dq, ClientState& cs, LocalHolders&
       policy = *(serverPool->policy);
     }
     auto servers = serverPool->getServers();
-    if (policy.isLua) {
-      if (!policy.isFFI) {
-        std::lock_guard<std::mutex> lock(g_luamutex);
-        selectedBackend = policy.policy(servers, &dq);
-      }
-      else {
-        dnsdist_ffi_dnsquestion_t dnsq(&dq);
-        dnsdist_ffi_servers_list_t serversList(servers);
-        unsigned int selected = 0;
-        {
-          std::lock_guard<std::mutex> lock(g_luamutex);
-          selected = policy.ffipolicy(&serversList, &dnsq);
-        }
-        selectedBackend = servers.at(selected).second;
-      }
-    }
-    else {
-      selectedBackend = policy.policy(servers, &dq);
-    }
+    selectedBackend = getSelectedBackendFromPolicy(policy, servers, dq);
 
     uint16_t cachedResponseSize = dq.size;
     uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL;
index 1a48b590ad750491f7b8a4afd7c7ad53698c06d0..2e0d9f9afed5ff606c440ec128759bf393d6d849 100644 (file)
@@ -224,6 +224,8 @@ testrunner_SOURCES = \
        dnsdist-ecs.cc dnsdist-ecs.hh \
        dnsdist-kvs.cc dnsdist-kvs.hh \
        dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
+       dnsdist-lua-ffi.cc dnsdist-lua-ffi.hh \
+       dnsdist-lua-ffi-interface.h dnsdist-lua-ffi-interface.inc \
        dnsdist-rings.hh \
        dnsdist-xpf.cc dnsdist-xpf.hh \
        dnscrypt.cc dnscrypt.hh \
@@ -249,7 +251,8 @@ testrunner_SOURCES = \
        threadname.hh threadname.cc \
        testrunner.cc \
        uuid-utils.hh uuid-utils.cc \
-       xpf.cc xpf.hh
+       xpf.cc xpf.hh \
+       ext/luawrapper/include/LuaContext.hpp
 
 dnsdist_LDFLAGS = \
        $(AM_LDFLAGS) \
@@ -277,8 +280,9 @@ testrunner_LDFLAGS = \
 
 testrunner_LDADD = \
        $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) \
-       $(LIBSODIUM_LIBS) \
        $(FSTRM_LIBS) \
+       $(LIBSODIUM_LIBS) \
+       $(LUA_LIBS) \
        $(RT_LIBS) \
        $(SANITIZER_FLAGS) \
        $(LIBCAP_LIBS)
index acb8f27780b955d2bfab3506fbda8fd1e90e7bcb..4b707dcaa296493987c777ea18549a458594028e 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "dnsdist.hh"
 #include "dnsdist-lbpolicies.hh"
+#include "dnsdist-lua-ffi.hh"
 #include "dolog.hh"
 
 GlobalStateHolder<ServerPolicy> g_policy;
@@ -241,3 +242,30 @@ std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poo
 
   return it->second;
 }
+
+std::shared_ptr<DownstreamState> getSelectedBackendFromPolicy(const ServerPolicy& policy, const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq)
+{
+  std::shared_ptr<DownstreamState> selectedBackend{nullptr};
+
+  if (policy.isLua) {
+    if (!policy.isFFI) {
+      std::lock_guard<std::mutex> lock(g_luamutex);
+      selectedBackend = policy.policy(servers, &dq);
+    }
+    else {
+      dnsdist_ffi_dnsquestion_t dnsq(&dq);
+      dnsdist_ffi_servers_list_t serversList(servers);
+      unsigned int selected = 0;
+      {
+        std::lock_guard<std::mutex> lock(g_luamutex);
+        selected = policy.ffipolicy(&serversList, &dnsq);
+      }
+      selectedBackend = servers.at(selected).second;
+    }
+  }
+  else {
+    selectedBackend = policy.policy(servers, &dq);
+  }
+
+  return selectedBackend;
+}
index 1e8418c70f16ed1dd68e6f9c18462bb3880d87af..90a8ece93d6e993ec9b98f11e98b31c069dab64b 100644 (file)
 #include "dolog.hh"
 
 uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
+
 std::mutex g_luamutex;
+#include "ext/luawrapper/include/LuaContext.hpp"
+LuaContext g_lua;
+
+bool g_snmpEnabled{false};
+bool g_snmpTrapsEnabled{false};
+DNSDistSNMPAgent* g_snmpAgent{nullptr};
+
+/* add stub implementations, we don't want to include the corresponding object files
+   and their dependencies */
 
-static std::shared_ptr<DownstreamState> getSelectedBackendFromPolicy(const ServerPolicy& policy, const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq)
+#ifdef HAVE_DNS_OVER_HTTPS
+std::unordered_map<std::string, std::string> DOHUnit::getHTTPHeaders() const
 {
-  std::shared_ptr<DownstreamState> selectedBackend{nullptr};
+  return {};
+}
 
-  if (policy.isLua) {
-    if (!policy.isFFI) {
-      std::lock_guard<std::mutex> lock(g_luamutex);
-      selectedBackend = policy.policy(servers, &dq);
-    }
-    else {
-      dnsdist_ffi_dnsquestion_t dnsq(&dq);
-      dnsdist_ffi_servers_list_t serversList(servers);
-      unsigned int selected = 0;
-      {
-        std::lock_guard<std::mutex> lock(g_luamutex);
-        selected = policy.ffipolicy(&serversList, &dnsq);
-      }
-      selectedBackend = servers.at(selected).second;
-    }
-  }
-  else {
-    selectedBackend = policy.policy(servers, &dq);
-  }
+std::string DOHUnit::getHTTPPath() const
+{
+  return "";
+}
+
+std::string DOHUnit::getHTTPHost() const
+{
+  return "";
+}
+
+std::string DOHUnit::getHTTPScheme() const
+{
+  return "";
+}
+
+std::string DOHUnit::getHTTPQueryString() const
+{
+  return "";
+}
+
+void DOHUnit::setHTTPResponse(uint16_t statusCode, const std::string& body_, const std::string& contentType_)
+{
+}
+#endif /* HAVE_DNS_OVER_HTTPS */
 
-  return selectedBackend;
+std::string DNSQuestion::getTrailingData() const
+{
+  return "";
+}
+
+bool DNSQuestion::setTrailingData(const std::string& tail)
+{
+  return false;
+}
+
+bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dq, const std::string& reason)
+{
+  return false;
 }
 
 static DNSQuestion getDQ(const DNSName* providedName = nullptr)
@@ -136,7 +165,7 @@ BOOST_AUTO_TEST_CASE(test_wrandom) {
   ServerPolicy::NumberedServerVector servers;
   std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
   for (size_t idx = 1; idx <= 10; idx++) {
-    servers.push_back({ idx + 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+    servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
     serversMap[servers.at(idx - 1).second] = 0;
     servers.at(idx - 1).second->setUp();
   }
@@ -200,7 +229,7 @@ BOOST_AUTO_TEST_CASE(test_whashed) {
   ServerPolicy::NumberedServerVector servers;
   std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
   for (size_t idx = 1; idx <= 10; idx++) {
-    servers.push_back({ idx + 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+    servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
     serversMap[servers.at(idx - 1).second] = 0;
     servers.at(idx - 1).second->setUp();
   }
@@ -264,6 +293,7 @@ BOOST_AUTO_TEST_CASE(test_whashed) {
   BOOST_CHECK_LT(got, expected * 2);
 }
 
+
 BOOST_AUTO_TEST_CASE(test_chashed) {
   bool existingVerboseValue = g_verbose;
   g_verbose = false;
@@ -278,7 +308,7 @@ BOOST_AUTO_TEST_CASE(test_chashed) {
   ServerPolicy::NumberedServerVector servers;
   std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
   for (size_t idx = 1; idx <= 10; idx++) {
-    servers.push_back({ idx + 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+    servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
     serversMap[servers.at(idx - 1).second] = 0;
     servers.at(idx - 1).second->setUp();
     /* we need to have a weight of at least 1000 to get an optimal repartition with the consistent hashing algo */
@@ -348,4 +378,105 @@ BOOST_AUTO_TEST_CASE(test_chashed) {
   g_verbose = existingVerboseValue;
 }
 
+BOOST_AUTO_TEST_CASE(test_lua) {
+  std::vector<DNSName> names;
+  names.reserve(1000);
+  for (size_t idx = 0; idx < 1000; idx++) {
+    names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+  }
+
+  static const std::string policySetupStr = R"foo(
+    local counter = 0
+    function luaroundrobin(servers, dq)
+      counter = counter + 1
+      return servers[1 + (counter % #servers)]
+    end
+
+    setServerPolicyLua("luaroundrobin", luaroundrobin)
+  )foo";
+  g_lua.writeFunction("setServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy) {
+      g_policy.setState(ServerPolicy{name, policy, true});
+    });
+  g_lua.executeCode(policySetupStr);
+
+  ServerPolicy pol = g_policy.getCopy();
+  ServerPolicy::NumberedServerVector servers;
+  std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
+  for (size_t idx = 1; idx <= 10; idx++) {
+    servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+    serversMap[servers.at(idx - 1).second] = 0;
+    servers.at(idx - 1).second->setUp();
+  }
+  BOOST_REQUIRE_EQUAL(servers.size(), 10);
+
+  for (const auto& name : names) {
+    auto dq = getDQ(&name);
+    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    BOOST_REQUIRE(serversMap.count(server) == 1);
+    ++serversMap[server];
+  }
+  uint64_t total = 0;
+  for (const auto& entry : serversMap) {
+    BOOST_CHECK_GT(entry.second, 0);
+    BOOST_CHECK_GT(entry.second, (names.size() / servers.size() / 2));
+    BOOST_CHECK_LT(entry.second, (names.size() / servers.size() * 2));
+    total += entry.second;
+  }
+  BOOST_CHECK_EQUAL(total, names.size());
+}
+
+#ifdef LUAJIT_VERSION
+BOOST_AUTO_TEST_CASE(test_lua_ffi) {
+  std::vector<DNSName> names;
+  names.reserve(1000);
+  for (size_t idx = 0; idx < 1000; idx++) {
+    names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+  }
+
+  static const std::string policySetupStr = R"foo(
+    local ffi = require("ffi")
+    local C = ffi.C
+    local counter = 0
+    function ffilb(servers_list, dq)
+      local serversCount = tonumber(C.dnsdist_ffi_servers_list_get_count(servers_list))
+      counter = counter + 1
+      return counter % serversCount
+    end
+
+    setServerPolicyLuaFFI("FFI", ffilb)
+  )foo";
+  g_lua.executeCode(getLuaFFIWrappers());
+  g_lua.writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) {
+      auto pol = ServerPolicy(name, policy);
+      g_policy.setState(std::move(pol));
+    });
+  g_lua.executeCode(policySetupStr);
+
+  ServerPolicy pol = g_policy.getCopy();
+  ServerPolicy::NumberedServerVector servers;
+  std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
+  for (size_t idx = 1; idx <= 10; idx++) {
+    servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+    serversMap[servers.at(idx - 1).second] = 0;
+    servers.at(idx - 1).second->setUp();
+  }
+  BOOST_REQUIRE_EQUAL(servers.size(), 10);
+
+  for (const auto& name : names) {
+    auto dq = getDQ(&name);
+    auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+    BOOST_REQUIRE(serversMap.count(server) == 1);
+    ++serversMap[server];
+  }
+  uint64_t total = 0;
+  for (const auto& entry : serversMap) {
+    BOOST_CHECK_GT(entry.second, 0);
+    BOOST_CHECK_GT(entry.second, (names.size() / servers.size() / 2));
+    BOOST_CHECK_LT(entry.second, (names.size() / servers.size() * 2));
+    total += entry.second;
+  }
+  BOOST_CHECK_EQUAL(total, names.size());
+}
+#endif /* LUAJIT_VERSION */
+
 BOOST_AUTO_TEST_SUITE_END()