]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Reorganize a few things, add a Lua hook that's called on startup and (nice) shutdown
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 24 Oct 2024 08:30:48 +0000 (10:30 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 24 Oct 2024 10:58:21 +0000 (12:58 +0200)
pdns/lua-base4.cc
pdns/recursordist/docs/lua-scripting/functions.rst
pdns/recursordist/lua-recursor4.cc
pdns/recursordist/lua-recursor4.hh
pdns/recursordist/rec-main.cc
pdns/recursordist/recursor_cache.cc
pdns/recursordist/recursor_cache.hh
pdns/recursordist/settings/table.py

index 31323801ab9c43d5a6d9e2c7a1b010a3c2cbde60..a95f8e05afa7803fe5b63b5261991a5040aab346 100644 (file)
@@ -271,7 +271,8 @@ void BaseLua4::prepareContext() {
     });
   d_lw->registerFunction<void (DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.setContent(shared_ptr<DNSRecordContent>(DNSRecordContent::make(dr.d_type, 1, newContent))); });
 
-  // pdnsload
+  // pdnslog
+#ifdef RECURSOR
   d_lw->writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel, boost::optional<std::map<std::string, std::string>> values) {
     auto log = g_slog->withName("lua");
     if (values) {
@@ -280,6 +281,10 @@ void BaseLua4::prepareContext() {
       }
     }
     log->info(static_cast<Logr::Priority>(loglevel.get_value_or(Logr::Warning)), msg);
+#else
+    d_lw->writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) {
+      g_log << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg<<endl;
+#endif
   });
 
   d_lw->writeFunction("pdnsrandom", [](boost::optional<uint32_t> maximum) {
index 58f9a49379752cbbb2218400ccd5a40a23edf52f..af1ad09e44ae7312a01ccc7435b828afb907332b 100644 (file)
@@ -30,6 +30,9 @@ These are some functions that don't really have a place in one of the other cate
 
    :param str script: The pathname of the Lua script to run.
 
+.. note::
+     The :func:`putIntoRecordCache` and :func:`getRecordCacheRecords` functions are experimental, their functionality might change in upcoming releases.
+
 .. function:: putIntoRecordCache(dump) -> int
 
    .. versionadded:: 5.2.0
@@ -42,18 +45,19 @@ These are some functions that don't really have a place in one of the other cate
    Some records might be skipped, for example when they are already present in the record cache or contain specific information not supported yet by this function.
    If the :program:`Recursor` determines the version of the data is not compatible, it will skip loading and log an error.
 
-.. function:: getRecordCacheRecords(perShard, maxSize) ->str
+.. function:: getRecordCacheRecords(perShard, maxSize) -> str, int
 
    .. versionadded:: 5.2.0
 
    Get a record cache dump in proprietary format.
 
-   :param int perShard: The maximum number of records to produce per shard.
+   :param int perShard: The maximum number of records to retrieve per shard.
    :param int maxSize: The maximum size of the dump.
 
-   :return: A string representing the records.
+   :return: A string representing the records and an integer specifying how many records were retrieved
 
    This function will scan the most recently used records of each shard, picking at most ``perShard`` records per shard and adding them to the result.
    If adding a record's data to the result would make the result size exceed ``maxSize``, the remainder of the current shard and further remaining shards are skipped.
    The format of the string produced is proprietary.
    The string contains meta information, so the :program:`Recursor` calling :func:`putIntoRecordCache` can check if the data format is compatible.
+
index b89d9ae3b6bc0e1771ba570f05472bd35c45e956..2b4b5887cd4e3ff67c35926de58649d45b6883d8 100644 (file)
@@ -496,8 +496,8 @@ void RecursorLua4::postPrepareContext() // NOLINT(readability-function-cognitive
 
   d_lw->writeFunction("getRecordCacheRecords", [](size_t perShard, size_t maxSize) {
     std::string ret;
-    g_recCache->getRecords(perShard, maxSize, ret);
-    return ret;
+    auto number = g_recCache->getRecords(perShard, maxSize, ret);
+    return std::tuple<std::string, size_t>{ret, number};
   });
 
   d_lw->writeFunction("putIntoRecordCache", [](const string& data) {
@@ -505,8 +505,8 @@ void RecursorLua4::postPrepareContext() // NOLINT(readability-function-cognitive
   });
 
   d_lw->writeFunction("spawnThread", [](const string& scriptName) {
-    auto log = g_slog->withName("lua")->withValues("name", Logging::Loggable(scriptName));
-    log->info(Logr::Info, "Starting Lua thread");
+    auto log = g_slog->withName("lua")->withValues("script", Logging::Loggable(scriptName));
+    log->info(Logr::Info, "Starting Lua script in separate thread");
     std::thread thread([=]() {
       auto lua = std::make_shared<RecursorLua4>();
       lua->loadFile(scriptName);
@@ -550,6 +550,22 @@ void RecursorLua4::getFeatures(Features& features)
   features.emplace_back("PR8001_devicename", true);
 }
 
+void RecursorLua4::runStartStopFunction(const string& script, bool start, Logr::log_t log)
+{
+  const string func = start ? "on_recursor_start" : "on_recursor_stop";
+  auto mylog = log->withValues("script", Logging::Loggable(script), "function", Logging::Loggable(func));
+  loadFile(script);
+  auto call = d_lw->readVariable<boost::optional<std::function<void()>>>(func).get_value_or(nullptr);
+  if (call) {
+    mylog->info(Logr::Info, "Starting Lua function");
+    call();
+    mylog->info(Logr::Info, "Lua function done");
+  }
+  else {
+    mylog->info(Logr::Info, "No Lua function found");
+  }
+}
+
 static void warnDrop(const RecursorLua4::DNSQuestion& dnsQuestion)
 {
   if (dnsQuestion.rcode == -2) {
index 1a758abb5d9d9b000e0e0d65a65e7b92a0478926..375a3b9fe02226555b4f9a20cbd8ed90a05704b0 100644 (file)
@@ -224,6 +224,8 @@ public:
 
   bool policyHitEventFilter(const ComboAddress& remote, const DNSName& qname, const QType& qtype, bool tcp, DNSFilterEngine::Policy& policy, std::unordered_set<std::string>& tags, std::unordered_map<std::string, bool>& discardedPolicies) const;
 
+  void runStartStopFunction(const std::string& script, bool start, Logr::log_t log);
+
   [[nodiscard]] bool needDQ() const
   {
     return (d_prerpz || d_preresolve || d_nxdomain || d_nodata || d_postresolve);
index a638ef8ea0880feecfd2757c1405c6b8fe0359a8..935c2e89aa0bb0c5c1fda7e57c43c9fd232188d2 100644 (file)
@@ -147,7 +147,7 @@ thread_local unsigned int RecThreadInfo::t_id;
 
 pdns::RateLimitedLog g_rateLimitedLogger;
 
-static void runCustomLua(Logr::log_t log);
+static void runStartStopLua(bool start, Logr::log_t log);
 
 static std::map<unsigned int, std::set<int>> parseCPUMap(Logr::log_t log)
 {
@@ -356,6 +356,7 @@ int RecThreadInfo::runThreads(Logr::log_t log)
         ret = tInfo.exitCode;
       }
     }
+    runStartStopLua(false, log);
   }
   return ret;
 }
@@ -2378,8 +2379,8 @@ static int serviceMain(Logr::log_t log)
   setupNODThread(log);
 #endif /* NOD_ENABLED */
 
-  runCustomLua(log);
-  
+  runStartStopLua(true, log);
+
   return RecThreadInfo::runThreads(log);
 }
 
@@ -3041,20 +3042,15 @@ static pair<int, bool> doConfig(Logr::log_t startupLog, const string& configname
 
 LockGuarded<pdns::rust::settings::rec::Recursorsettings> g_yamlStruct;
 
-static void runCustomLua(Logr::log_t log)
+static void runStartStopLua(bool start, Logr::log_t log)
 {
   auto settings = g_yamlStruct.lock();
-  const auto& script = settings->recursor.lua_startup_script;
+  const auto& script = settings->recursor.lua_start_stop_script;
   if (script.empty()) {
     return;
   }
-  log->info(Logr::Info, "Starting Custom Lua", "script", Logging::Loggable(script));
-  //std::thread thread([=]() {
-    auto lua = std::make_shared<RecursorLua4>();
-    lua->loadFile(std::string(script));
-    log->info(Logr::Info, "Custom Lua done");
-    //});
-    //thread.detach();
+  auto lua = std::make_shared<RecursorLua4>();
+  lua->runStartStopFunction(std::string(script), start, log);
 }
 
 static void handleRuntimeDefaults(Logr::log_t log)
index d3c05c22131ba7940ba6b1a5bf4a69e9ec903793..fb9dc700adbc925d7cb158c9795651f0f2a73d31 100644 (file)
@@ -1047,7 +1047,7 @@ void MemRecursorCache::getRecord(T& message, U recordSet)
   message.add_bool(PBCacheEntry::required_bool_tooBig, recordSet->d_tooBig);
 }
 
-void MemRecursorCache::getRecords(size_t perShard, size_t maxSize, std::string& ret)
+size_t MemRecursorCache::getRecords(size_t perShard, size_t maxSize, std::string& ret)
 {
   auto log = g_slog->withName("recordcache")->withValues("perShard", Logging::Loggable(perShard), "maxSize", Logging::Loggable(maxSize));
   log->info(Logr::Info, "Producing cache dump");
@@ -1072,7 +1072,7 @@ void MemRecursorCache::getRecords(size_t perShard, size_t maxSize, std::string&
       if (ret.size() > maxSize) {
         message.rollback();
         log->info(Logr::Info, "Produced cache dump (max size reached)", "size", Logging::Loggable(ret.size()), "count", Logging::Loggable(count));
-        return;
+        return count;
       }
       ++count;
       ++thisShardCount;
@@ -1082,8 +1082,7 @@ void MemRecursorCache::getRecords(size_t perShard, size_t maxSize, std::string&
     }
   }
   log->info(Logr::Info, "Produced cache dump", "size", Logging::Loggable(ret.size()), "count", Logging::Loggable(count));
-  std::ofstream out("/tmp/pb");
-  out.write(ret.data(), ret.size());
+  return count;
 }
 
 template <typename T>
index d9f3a94ddfaedec397ac605f679741c390ea3efd..50c637afdf89f7cf0e48a0026b713a2323603620 100644 (file)
@@ -63,7 +63,7 @@ public:
   [[nodiscard]] pair<uint64_t, uint64_t> stats();
   [[nodiscard]] size_t ecsIndexSize();
 
-  void getRecords(size_t howmany, size_t maxsize, std::string& ret);
+  size_t getRecords(size_t howmany, size_t maxsize, std::string& ret);
   size_t putRecords(const std::string& pbuf);
 
   using OptTag = boost::optional<std::string>;
index cebd18355fa804a6967c387203cb7995ec088061..999d5b79670c926974eec0e3782a9e37c847ba8c 100644 (file)
@@ -3511,13 +3511,13 @@ Sequence of ProxyMapping
         'versionadded': '5.1.0',
     },
     {
-        'name' : 'lua_startup_script',
+        'name' : 'lua_start_stop_script',
         'section' : 'recursor',
         'type' : LType.String,
         'default' : '',
-        'help' : 'Custom Lua script to run on startup',
+        'help' : 'Lua script containing functions to run on startup and shutdown',
         'doc' : '''
-Run this Lua script on startup in a separate thread.
+Load this Lua script on startup and shutdown and run the Lua function ``on_recursor_start`` on startup and the Lua function ``on_recursor_stop`` on a ``nice`` shutdown (using ``rec_control quit-nicely`` of the :program:`Recursor` process.
         ''',
         'skip-old' : 'No equivalent old-style setting',
         'versionadded': '5.2.0',