]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Error handling and bulk update of forwards
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 12 Oct 2023 09:02:17 +0000 (11:02 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 12 Oct 2023 09:02:17 +0000 (11:02 +0200)
pdns/recursordist/settings/cxxsupport.cc
pdns/recursordist/settings/rust-bridge-in.rs
pdns/recursordist/settings/rust/src/bridge.rs

index b6db21383cc8598fa3d0aa34e583e15756c9a328..37ccfc35d42616db6b1ffd268cf6795b443f4fe5 100644 (file)
@@ -134,13 +134,13 @@ static void mergeYamlSubFile(const std::string& configname, Recursorsettings& se
   pdns::rust::settings::rec::merge(settings, data);
 }
 
-static void convertACLFile(const string& includeDir, const string& apiDir, const std::string& filename)
+static void possiblyConvertACLFile(const string& includeDir, const string& apiDir, const std::string& filename, Logr::log_t log)
 {
   auto path = includeDir;
   path.append("/").append(filename).append(".conf");
   auto file = ifstream(path);
   if (!file.is_open()) {
-    cerr << "Cannot open " << path << endl;
+    // Not an error, file just is not there
     return;
   }
   rust::vec<rust::string> result;
@@ -170,31 +170,71 @@ static void convertACLFile(const string& includeDir, const string& apiDir, const
   }
   string yamlfilename =  apiDir;
   yamlfilename.append("/").append(filename).append(".yml");
-  ofstream ofconf(yamlfilename + ".tmp");
+  string tmpfilename = yamlfilename + ".tmp";
+  ofstream ofconf(tmpfilename);
   if (!ofconf) {
-    throw runtime_error("Could not open config file '" + yamlfilename + "' for writing: " + stringerror());
+    int err = errno;
+    log->error(Logr::Error, err, "Cannot open for file for writing YAML", "to", Logging::Loggable(tmpfilename));
+    throw runtime_error("YAML Conversion");
   }
   ofconf << "# Generated by pdns-recursor REST API, DO NOT EDIT" << endl;
   ofconf << yaml << endl;
   ofconf.close();
-  cerr << "Converted " << path << " to " << yamlfilename <<endl;
   if (rename(path.c_str(), (path + ".converted").c_str()) != 0) {
-    // LOGGING
-    unlink(yamlfilename.c_str());
+    int err = errno;
+    log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(path), "to", Logging::Loggable(path + ".converted"));
+    unlink(tmpfilename.c_str());
+    throw runtime_error("YAML Conversion");
+  }
+
+  if (rename(tmpfilename.c_str(), yamlfilename.c_str()) != 0) {
+    int err = errno;
+    log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(tmpfilename), "to", Logging::Loggable(yamlfilename));
+    rename((path + ".converted").c_str(), path.c_str());
+    throw runtime_error("YAML Conversion");
   }
-  // ERROR CHECKS AND LOG
-  rename((yamlfilename + ".tmp").c_str(), yamlfilename.c_str());
+  log->info(Logr::Notice, "Converted to YAML", "file", Logging::Loggable(path), "to", Logging::Loggable(yamlfilename));
 }
 
-static void convertForwardsandAuths(const std::string& includeDir, const std::string& apiDir, Logr::log_t log)
+static void fileCopy(const string& src, const string& dst, Logr::log_t log)
 {
-  std::vector<std::string> forwardFiles;
-  ::arg().gatherIncludes(includeDir, "..conf", forwardFiles);
+  ifstream ifconf(src);
+  if (!ifconf) {
+    log->info(Logr::Error, "Cannot open for file for reading", "file", Logging::Loggable(src));
+    throw runtime_error("YAML Conversion");
+  }
+  ofstream ofconf(dst);
+  if (!ofconf) {
+    log->info(Logr::Error, "Cannot open for file for writing YAML", "to", Logging::Loggable(dst));
+    throw runtime_error("YAML Conversion");
+  }
+  for (;;) {
+    auto character = ifconf.get();
+    if (ifconf.eof()) {
+      break;
+    }
+    if (ifconf.bad()) {
+      int err = errno;
+      log->error(Logr::Error, err, "Error reading", "to", Logging::Loggable(src));
+      throw runtime_error("YAML Conversion");
+    }
+    ofconf.put(character);
+    if (ofconf.bad()) {
+      int err = errno;
+      log->error(Logr::Error, err, "Error writing YAML", "to", Logging::Loggable(dst));
+      throw runtime_error("YAML Conversion");
+    }
+  }
+  ofconf.close();
+  ifconf.close();
+}
+static void possiblyConvertForwardsandAuths(const std::string& includeDir, const std::string& apiDir, Logr::log_t log)
+{
+  std::vector<std::string> forwAndAuthFiles;
+  ::arg().gatherIncludes(includeDir, "..conf", forwAndAuthFiles);
   pdns::rust::settings::rec::Recursorsettings settings;
-  for (const auto& file : forwardFiles) {
+  for (const auto& file : forwAndAuthFiles) {
     auto yaml = pdns::settings::rec::oldStyleSettingsFileToYaml(file, false);
-    cerr << "Converted YAML for " << file << endl;
-    cerr << yaml << endl;
     pdns::rust::settings::rec::merge(settings, yaml);
   }
   const string yamlAPiZonesFile = apiDir + "/apizones";
@@ -203,20 +243,18 @@ static void convertForwardsandAuths(const std::string& includeDir, const std::st
     const std::string origName(zone.file);
     std::string newName(zone.file);
     newName.replace(0, includeDir.length(), apiDir);
-    cerr << "Rename " << origName << ' ' << newName << ' ';
-    auto ret = rename(origName.c_str(), newName.c_str());
-    cerr << ret << ' ' << stringerror() << endl;
+    log->info(Logr::Notice, "Copying auth zone file", "file", Logging::Loggable(origName), "to", Logging::Loggable(newName));
+    fileCopy(origName, newName, log);
     zone.file = ::rust::String(newName);
     api_add_auth_zone(yamlAPiZonesFile, zone);
   }
-  for (const auto& zone : settings.recursor.forward_zones) {
-    api_add_forward_zone(yamlAPiZonesFile, zone);
-  }
-  for (const auto& zone : settings.recursor.forward_zones_recurse) {
-    api_add_forward_zone(yamlAPiZonesFile, zone);
-  }
-  for (const auto& file : forwardFiles) {
-    rename(file.c_str(), (file + ".converted").c_str());
+  api_add_forward_zones(yamlAPiZonesFile, settings.recursor.forward_zones);
+  api_add_forward_zones(yamlAPiZonesFile, settings.recursor.forward_zones_recurse);
+  for (const auto& file : forwAndAuthFiles) {
+    if (rename(file.c_str(), (file + ".converted").c_str()) != 0) {
+      int err = errno;
+      log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(file), "to", Logging::Loggable(file + ".converted"));
+    }
   }
 }
 
@@ -238,7 +276,7 @@ void pdns::settings::rec::processAPIDir(const string& includeDirOnCommandLine, p
     "allow-notify-from"
   };
   for (const auto& file : aclFiles) {
-    convertACLFile(includeDir, apiDir, file);
+    possiblyConvertACLFile(includeDir, apiDir, file, log);
     auto path = apiDir;
     path.append("/").append(file).append(".yml");
     try {
@@ -247,7 +285,7 @@ void pdns::settings::rec::processAPIDir(const string& includeDirOnCommandLine, p
     catch (const runtime_error& err) {
     }
   }
-  convertForwardsandAuths(includeDir, apiDir, log);
+  possiblyConvertForwardsandAuths(includeDir, apiDir, log);
 }
 
 pdns::settings::rec::YamlSettingsStatus pdns::settings::rec::readYamlSettings(const std::string& configname, const std::string& includeDirOnCommandLine, Recursorsettings& settings, std::string& msg, Logr::log_t log)
index 1ee664c173cfb8540308d04e833650984d54f4ad..40e53b144f0ce06df43baeff3e6ea9df53d06acc 100644 (file)
@@ -105,5 +105,6 @@ extern "Rust" {
     fn api_read_zones(path: &str) ->  Result<UniquePtr<ApiZones>>;
     fn api_add_auth_zone(file: &str, authzone: AuthZone) -> Result<()>;
     fn api_add_forward_zone(file: &str, forwardzone: ForwardZone) -> Result<()>;
+    fn api_add_forward_zones(file: &str, forwardzones: &mut Vec<ForwardZone>) -> Result<()>;
     fn api_delete_zone(file: &str, zone: &str) -> Result<()>;
 }
index 370a881074f83daf0397bddf0590ef51e39df8cb..181e23424247d1112d6d6106fdde6a11dc84a551 100644 (file)
@@ -465,6 +465,15 @@ pub fn api_add_forward_zone(path: &str, forwardzone: ForwardZone) -> Result<(),
     zones.forward_zones.push(forwardzone);
     api_write_zones(path, &zones)
 }
+
+// This function is called from C++, it needs to acquire the lock
+pub fn api_add_forward_zones(path: &str, forwardzones: &mut Vec<ForwardZone>) -> Result<(), std::io::Error> {
+    let _lock = LOCK.lock().unwrap();
+    let mut zones = api_read_zones_locked(path, true)?;
+    zones.forward_zones.append(forwardzones);
+    api_write_zones(path, &zones)
+}
+
 // This function is called from C++, it needs to acquire the lock
 pub fn api_delete_zone(path: &str, zone: &str) -> Result<(), std::io::Error> {
     let _lock = LOCK.lock().unwrap();