From f758857a65412a3204d37699ff2820080bc4b420 Mon Sep 17 00:00:00 2001 From: bert hubert Date: Mon, 14 Dec 2015 10:42:02 +0100 Subject: [PATCH] implement delta() to show changes versus configuration, so you can store your 'just right' setup. --- pdns/dnsdist-console.cc | 18 +++++++++++++-- pdns/dnsdist-lua.cc | 46 ++++++++++++++++++++++++++++++++++--- pdns/dnsdist-lua2.cc | 50 +++++++++++++++++++++++++++++++++++++++++ pdns/dnsdist.hh | 7 ++++++ 4 files changed, 116 insertions(+), 5 deletions(-) diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index 48151caa7..4cad399b1 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -5,6 +5,16 @@ #include #include "dolog.hh" +vector > g_confDelta; + +// MUST BE CALLED UNDER A LOCK - right now the LuaLock +void feedConfigDelta(const std::string& line) +{ + struct timeval now; + gettimeofday(&now, 0); + g_confDelta.push_back({now,line}); +} + void doClient(ComboAddress server, const std::string& command) { cout<<"Connecting to "< lock(g_luamutex); g_outputBuffer.clear(); + resetLuaSideEffect(); auto ret=g_lua.executeCode< boost::optional< boost::variant< @@ -139,7 +150,8 @@ void doConsole() } else cout << g_outputBuffer; - + if(!getLuaNoSideEffect()) + feedConfigDelta(line); } catch(const LuaContext::ExecutionErrorException& e) { std::cerr << e.what() << ": "; @@ -229,6 +241,7 @@ try try { std::lock_guard lock(g_luamutex); g_outputBuffer.clear(); + resetLuaSideEffect(); auto ret=g_lua.executeCode< boost::optional< boost::variant< @@ -248,7 +261,8 @@ try } else response=g_outputBuffer; - + if(!getLuaNoSideEffect()) + feedConfigDelta(line); } catch(const LuaContext::ExecutionErrorException& e) { response = "Error: " + string(e.what()) + ": "; diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index 6f2c18b02..0c54b975d 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -83,6 +83,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("newServer", [client](boost::variant pvars, boost::optional qps) { + setLuaSideEffect(); if(client) { return std::make_shared(ComboAddress()); } @@ -205,12 +206,14 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("addAnyTCRule", []() { + setLuaSideEffect(); auto rules=g_rulactions.getCopy(); rules.push_back({ std::make_shared(0xff), std::make_shared()}); g_rulactions.setState(rules); }); g_lua.writeFunction("rmRule", [](unsigned int num) { + setLuaSideEffect(); auto rules = g_rulactions.getCopy(); if(num >= rules.size()) { g_outputBuffer = "Error: attempt to delete non-existing rule\n"; @@ -221,6 +224,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("topRule", []() { + setLuaSideEffect(); auto rules = g_rulactions.getCopy(); if(rules.empty()) return; @@ -230,6 +234,7 @@ vector> setupLua(bool client, const std::string& confi g_rulactions.setState(rules); }); g_lua.writeFunction("mvRule", [](unsigned int from, unsigned int to) { + setLuaSideEffect(); auto rules = g_rulactions.getCopy(); if(from >= rules.size() || to > rules.size()) { g_outputBuffer = "Error: attempt to move rules from/to invalid index\n"; @@ -252,6 +257,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("rmServer", [](boost::variant, int> var) { + setLuaSideEffect(); auto states = g_dstates.getCopy(); if(auto* rem = boost::get>(&var)) states.erase(remove(states.begin(), states.end(), *rem), states.end()); @@ -262,18 +268,21 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("setServerPolicy", [](ServerPolicy policy) { + setLuaSideEffect(); g_policy.setState(policy); }); g_lua.writeFunction("setServerPolicyLua", [](string name, policy_t policy) { + setLuaSideEffect(); g_policy.setState(ServerPolicy{name, policy}); }); g_lua.writeFunction("showServerPolicy", []() { + setLuaSideEffect(); g_outputBuffer=g_policy.getLocal()->name+"\n"; }); - g_lua.writeFunction("truncateTC", [](bool tc) { g_truncateTC=tc; }); - g_lua.writeFunction("fixupCase", [](bool fu) { g_fixupCase=fu; }); + g_lua.writeFunction("truncateTC", [](bool tc) { setLuaSideEffect(); g_truncateTC=tc; }); + g_lua.writeFunction("fixupCase", [](bool fu) { setLuaSideEffect(); g_fixupCase=fu; }); g_lua.registerMember("name", &ServerPolicy::name); g_lua.registerMember("policy", &ServerPolicy::policy); @@ -284,10 +293,12 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeVariable("whashed", ServerPolicy{"whashed", whashed}); g_lua.writeVariable("leastOutstanding", ServerPolicy{"leastOutstanding", leastOutstanding}); g_lua.writeFunction("addACL", [](const std::string& domain) { + setLuaSideEffect(); g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); }); }); g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional doTCP) { + setLuaSideEffect(); if(client) return; if (g_configurationDone) { @@ -305,6 +316,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional doTCP) { + setLuaSideEffect(); if(client) return; if (g_configurationDone) { @@ -320,6 +332,7 @@ vector> setupLua(bool client, const std::string& confi } }); g_lua.writeFunction("setACL", [](boost::variant>> inp) { + setLuaSideEffect(); NetmaskGroup nmg; if(auto str = boost::get(&inp)) { nmg.addMask(*str); @@ -330,6 +343,7 @@ vector> setupLua(bool client, const std::string& confi g_ACL.setState(nmg); }); g_lua.writeFunction("showACL", []() { + setLuaNoSideEffect(); vector vec; g_ACL.getCopy().toStringVector(&vec); @@ -342,6 +356,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("addDomainBlock", [](const std::string& domain) { + setLuaSideEffect(); SuffixMatchNode smn; smn.add(DNSName(domain)); g_rulactions.modify([smn](decltype(g_rulactions)::value_type& rulactions) { @@ -352,6 +367,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("showServers", []() { + setLuaNoSideEffect(); try { ostringstream ret; boost::format fmt("%1$-3d %2$-20.20s %|25t|%3% %|55t|%4$5s %|51t|%5$7.1f %|66t|%6$7d %|69t|%7$3d %|78t|%8$2d %|80t|%9$10d %|86t|%10$7d %|91t|%11$5.1f %|109t|%12$5.1f %13%" ); @@ -396,6 +412,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("addLuaAction", [](luadnsrule_t var, LuaAction::func_t func) { + setLuaSideEffect(); auto rule=makeRule(var); g_rulactions.modify([rule,func](decltype(g_rulactions)::value_type& rulactions){ rulactions.push_back({rule, @@ -420,6 +437,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("addDomainSpoof", [](const std::string& domain, const std::string& ip, boost::optional ip6) { + setLuaSideEffect(); SuffixMatchNode smn; ComboAddress a, b; b.sin6.sin6_family=0; @@ -480,6 +498,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("benchRule", [](std::shared_ptr rule, boost::optional times_, boost::optional suffix_) { + setLuaNoSideEffect(); int times = times_.get_value_or(100000); DNSName suffix(suffix_.get_value_or("powerdns.com")); struct item { @@ -535,6 +554,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("addAction", [](luadnsrule_t var, std::shared_ptr ea) { + setLuaSideEffect(); auto rule=makeRule(var); g_rulactions.modify([rule, ea](decltype(g_rulactions)::value_type& rulactions){ rulactions.push_back({rule, ea}); @@ -543,6 +563,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("addPoolRule", [](luadnsrule_t var, string pool) { + setLuaSideEffect(); auto rule=makeRule(var); g_rulactions.modify([rule, pool](decltype(g_rulactions)::value_type& rulactions) { rulactions.push_back({ @@ -552,6 +573,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("addNoRecurseRule", [](luadnsrule_t var) { + setLuaSideEffect(); auto rule=makeRule(var); g_rulactions.modify([rule](decltype(g_rulactions)::value_type& rulactions) { rulactions.push_back({ @@ -561,6 +583,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("addDisableValidationRule", [](luadnsrule_t var) { + setLuaSideEffect(); auto rule=makeRule(var); g_rulactions.modify([rule](decltype(g_rulactions)::value_type& rulactions) { rulactions.push_back({ @@ -571,6 +594,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("addQPSPoolRule", [](luadnsrule_t var, int limit, string pool) { + setLuaSideEffect(); auto rule = makeRule(var); g_rulactions.modify([rule, pool,limit](decltype(g_rulactions)::value_type& rulactions) { rulactions.push_back({ @@ -580,6 +604,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("setDNSSECPool", [](const std::string& pool) { + setLuaSideEffect(); g_rulactions.modify([pool](decltype(g_rulactions)::value_type& rulactions) { rulactions.push_back({std::make_shared(), std::make_shared(pool)}); @@ -587,6 +612,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("addQPSLimit", [](luadnsrule_t var, int lim) { + setLuaSideEffect(); auto rule = makeRule(var); g_rulactions.modify([lim,rule](decltype(g_rulactions)::value_type& rulactions) { rulactions.push_back({rule, @@ -595,6 +621,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("addDelay", [](luadnsrule_t var, int msec) { + setLuaSideEffect(); auto rule = makeRule(var); g_rulactions.modify([msec,rule](decltype(g_rulactions)::value_type& rulactions) { rulactions.push_back({rule, @@ -604,6 +631,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("showRules", []() { + setLuaNoSideEffect(); boost::format fmt("%-3d %9d %-50s %s\n"); g_outputBuffer += (fmt % "#" % "Matches" % "Rule" % "Action").str(); int num=0; @@ -615,6 +643,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("getServers", []() { + setLuaNoSideEffect(); vector > > ret; int count=1; for(const auto& s : g_dstates.getCopy()) { @@ -703,6 +732,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("carbonServer", [](const std::string& address, boost::optional ourName, boost::optional interval) { + setLuaSideEffect(); auto ours = g_carbon.getCopy(); ours.server=ComboAddress(address, 2003); if(ourName) @@ -715,6 +745,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("webserver", [client](const std::string& address, const std::string& password) { + setLuaSideEffect(); if(client) return; ComboAddress local(address); @@ -738,6 +769,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("controlSocket", [client](const std::string& str) { + setLuaSideEffect(); ComboAddress local(str, 5199); if(client) { @@ -767,6 +799,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("topClients", [](boost::optional top_) { + setLuaNoSideEffect(); auto top = top_.get_value_or(10); map counts; unsigned int total=0; @@ -798,6 +831,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("getTopQueries", [](unsigned int top, boost::optional labels) { + setLuaNoSideEffect(); map counts; unsigned int total=0; if(!labels) { @@ -845,6 +879,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("getResponseRing", []() { + setLuaNoSideEffect(); decltype(g_rings.respRing) ring; { std::lock_guard lock(g_rings.respMutex); @@ -864,6 +899,7 @@ vector> setupLua(bool client, const std::string& confi }); g_lua.writeFunction("getTopResponses", [](unsigned int top, unsigned int kind, boost::optional labels) { + setLuaNoSideEffect(); map counts; unsigned int total=0; { @@ -917,7 +953,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("showResponseLatency", []() { - + setLuaNoSideEffect(); map histo; double bin=100; for(int i=0; i < 15; ++i) { @@ -973,10 +1009,12 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("makeKey", []() { + setLuaNoSideEffect(); g_outputBuffer="setKey("+newKey()+")\n"; }); g_lua.writeFunction("setKey", [](const std::string& key) { + setLuaSideEffect(); if(B64Decode(key, g_key) < 0) { g_outputBuffer=string("Unable to decode ")+key+" as Base64"; errlog("%s", g_outputBuffer); @@ -986,6 +1024,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("testCrypto", [](boost::optional optTestMsg) { + setLuaNoSideEffect(); try { string testmsg; @@ -1039,6 +1078,7 @@ vector> setupLua(bool client, const std::string& confi g_lua.writeFunction("setECSOverride", [](bool override) { g_ECSOverride=override; }); g_lua.writeFunction("dumpStats", [] { + setLuaNoSideEffect(); vector leftcolumn, rightcolumn; boost::format fmt("%-23s\t%+11s"); diff --git a/pdns/dnsdist-lua2.cc b/pdns/dnsdist-lua2.cc index 257ec05f7..91d600f1c 100644 --- a/pdns/dnsdist-lua2.cc +++ b/pdns/dnsdist-lua2.cc @@ -7,6 +7,34 @@ #include "lock.hh" #include #include +#include + +boost::tribool g_noLuaSideEffect; + +/* this is a best effort way to prevent logging calls with no side-effects in the output of delta() + Functions can declare setLuaNoSideEffect() and if nothing else does declare a side effect, or nothing + has done so before on this invocation, this call won't be part of delta() output */ +void setLuaNoSideEffect() +{ + if(g_noLuaSideEffect==false) // there has been a side effect already + return; + g_noLuaSideEffect=true; +} + +void setLuaSideEffect() +{ + g_noLuaSideEffect=false; +} + +bool getLuaNoSideEffect() +{ + return g_noLuaSideEffect==true; +} + +void resetLuaSideEffect() +{ + g_noLuaSideEffect = boost::logic::indeterminate; +} map filterScore(const map& counts, double delta, int rate) @@ -105,10 +133,12 @@ void moreLua() }); g_lua.writeFunction("setDynBlockNMG", [](const nmts_t& nmg) { + setLuaSideEffect(); g_dynblockNMG.setState(nmg); }); g_lua.writeFunction("showDynBlocks", []() { + setLuaNoSideEffect(); auto slow = g_dynblockNMG.getCopy(); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -121,12 +151,14 @@ void moreLua() }); g_lua.writeFunction("clearDynBlocks", []() { + setLuaSideEffect(); nmts_t nmg; g_dynblockNMG.setState(nmg); }); g_lua.writeFunction("addDynBlocks", [](const map& m, const std::string& msg, boost::optional seconds) { + setLuaSideEffect(); auto slow = g_dynblockNMG.getCopy(); struct timespec until, now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -154,19 +186,23 @@ void moreLua() [](nmts_t& s, const ComboAddress& ca) { return s.match(ca); }); g_lua.writeFunction("exceedServfails", [](unsigned int rate, int seconds) { + setLuaNoSideEffect(); return exceedRCode(rate, seconds, RCode::ServFail); }); g_lua.writeFunction("exceedNXDOMAINs", [](unsigned int rate, int seconds) { + setLuaNoSideEffect(); return exceedRCode(rate, seconds, RCode::NXDomain); }); g_lua.writeFunction("exceedRespByterate", [](unsigned int rate, int seconds) { + setLuaNoSideEffect(); return exceedRespByterate(rate, seconds); }); g_lua.writeFunction("exceedQTypeRate", [](uint16_t type, unsigned int rate, int seconds) { + setLuaNoSideEffect(); return exceedQueryGen(rate, seconds, [type](counts_t& counts, const Rings::Query& q) { if(q.qtype==type) counts[q.requestor]++; @@ -176,6 +212,7 @@ void moreLua() }); g_lua.writeFunction("topBandwidth", [](unsigned int top) { + setLuaNoSideEffect(); auto res = g_rings.getTopBandwidth(top); boost::format fmt("%7d %s\n"); for(const auto& l : res) { @@ -183,6 +220,19 @@ void moreLua() } }); + g_lua.writeFunction("delta", []() { + setLuaNoSideEffect(); + // we hold the lua lock already! + for(const auto& d : g_confDelta) { + struct tm tm; + localtime_r(&d.first.tv_sec, &tm); + char date[80]; + strftime(date, sizeof(date)-1, "# %a %b %d %Y %H:%M:%S %Z\n", &tm); + g_outputBuffer += date; + g_outputBuffer += d.second + "\n"; + } + }); + g_lua.writeFunction("grepq", [](const std::string& s, boost::optional limit) { boost::optional nm; boost::optional dn; diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index 597ce1a5e..724dbc139 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -29,6 +29,9 @@ struct DynBlock }; extern GlobalStateHolder> g_dynblockNMG; + +extern vector > g_confDelta; + struct DNSDistStats { using stat_t=std::atomic; // aww yiss ;-) @@ -434,3 +437,7 @@ void controlClientThread(int fd, ComboAddress client); extern "C" { char** my_completion( const char * text , int start, int end); } +void setLuaNoSideEffect(); // if nothing has been declared, set that there are no side effects +void setLuaSideEffect(); // set to report a side effect, cancelling all _no_ side effect calls +bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect +void resetLuaSideEffect(); // reset to indeterminate state -- 2.40.0