From 32b86928382e548b5b589adf1a103af878fba00c Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Tue, 9 Apr 2019 16:39:57 +0200 Subject: [PATCH] dnsdist: Add 'setRoundRobinFailOnNoServer()' --- pdns/dnsdist-lua.cc | 5 +++ pdns/dnsdist.cc | 3 +- pdns/dnsdist.hh | 1 + .../docs/guides/serverselection.rst | 11 ++++++- regression-tests.dnsdist/test_Routing.py | 33 +++++++++++++++++++ 5 files changed, 51 insertions(+), 2 deletions(-) diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index 69e5c571f6..f8a9d749c1 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -1458,6 +1458,11 @@ void setupLuaConfig(bool client) g_servFailOnNoPolicy = servfail; }); + g_lua.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) { + setLuaSideEffect(); + g_roundrobinFailOnNoServer = fail; + }); + g_lua.writeFunction("setRingBuffersSize", [](size_t capacity, boost::optional numberOfShards) { setLuaSideEffect(); if (g_configurationDone) { diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 461c5f3896..a6575eebae 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -142,6 +142,7 @@ bool g_servFailOnNoPolicy{false}; bool g_truncateTC{false}; bool g_fixupCase{false}; bool g_preserveTrailingData{false}; +bool g_roundrobinFailOnNoServer{false}; static void truncateTC(char* packet, uint16_t* len, size_t responseSize, unsigned int consumed) try @@ -884,7 +885,7 @@ shared_ptr roundrobin(const NumberedServerVector& servers, cons } const auto *res=&poss; - if(poss.empty()) + if(poss.empty() && !g_roundrobinFailOnNoServer) res = &servers; if(res->empty()) diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index 663e18061b..8325ad512d 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -1034,6 +1034,7 @@ extern uint16_t g_downstreamTCPCleanupInterval; extern size_t g_udpVectorSize; extern bool g_preserveTrailingData; extern bool g_allowEmptyResponse; +extern bool g_roundrobinFailOnNoServer; #ifdef HAVE_EBPF extern shared_ptr g_defaultBPFFilter; diff --git a/pdns/dnsdistdist/docs/guides/serverselection.rst b/pdns/dnsdistdist/docs/guides/serverselection.rst index 191b934d69..7e7a4495d2 100644 --- a/pdns/dnsdistdist/docs/guides/serverselection.rst +++ b/pdns/dnsdistdist/docs/guides/serverselection.rst @@ -54,6 +54,7 @@ You can also set the hash perturbation value, see :func:`setWHashedPertubation`. ~~~~~~~~~~~~~~ The last available policy is ``roundrobin``, which indiscriminately sends each query to the next server that is up. +If all servers are down, the policy will still select one server by default. Setting :func:`setRoundRobinFailOnNoServer` to ``true`` will change this behavior. Lua server policies ------------------- @@ -131,7 +132,7 @@ Functions If set, return a ServFail when no servers are available, instead of the default behaviour of dropping the query. - :param bool value: + :param bool value: whether to return a servfail instead of dropping the query .. function:: setPoolServerPolicy(policy, pool) @@ -148,6 +149,14 @@ Functions :param string function: name of the function :param string pool: Name of the pool +.. function:: setRoundRobinFailOnNoServer(value) + + .. versionadded:: 1.4.0 + + By default the roundrobin load-balancing policy will still try to select a backend even if all backends are currently down. Setting this to true will make the policy fail and return that no server is available instead. + + :param bool value: whether to fail when all servers are down + .. function:: showPoolServerPolicy(pool) Print server selection policy for ``pool``. diff --git a/regression-tests.dnsdist/test_Routing.py b/regression-tests.dnsdist/test_Routing.py index e0bda09aeb..386fba655f 100644 --- a/regression-tests.dnsdist/test_Routing.py +++ b/regression-tests.dnsdist/test_Routing.py @@ -220,6 +220,39 @@ class TestRoutingRoundRobinLBOneDown(DNSDistTest): self.assertEquals(total, numberOfQueries * 2) +class TestRoutingRoundRobinLBAllDown(DNSDistTest): + + _testServer2Port = 5351 + _config_params = ['_testServerPort', '_testServer2Port'] + _config_template = """ + setServerPolicy(roundrobin) + setRoundRobinFailOnNoServer(true) + s1 = newServer{address="127.0.0.1:%s"} + s1:setDown() + s2 = newServer{address="127.0.0.1:%s"} + s2:setDown() + """ + + def testRRWithAllDown(self): + """ + Routing: Round Robin with all servers down + """ + numberOfQueries = 10 + name = 'alldown.rr.routing.tests.powerdns.com.' + query = dns.message.make_query(name, 'A', 'IN') + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + 60, + dns.rdataclass.IN, + dns.rdatatype.A, + '192.0.2.1') + response.answer.append(rrset) + + for method in ("sendUDPQuery", "sendTCPQuery"): + sender = getattr(self, method) + (_, receivedResponse) = sender(query, response=None, useQueue=False) + self.assertEquals(receivedResponse, None) + class TestRoutingOrder(DNSDistTest): _testServer2Port = 5351 -- 2.39.2