You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ad...@apache.org on 2021/12/10 12:24:36 UTC

[nifi-minifi-cpp] branch main updated: MINIFICPP-1694 Change unnecessary errors to warnings

This is an automated email from the ASF dual-hosted git repository.

adebreceni pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git


The following commit(s) were added to refs/heads/main by this push:
     new f9d8834  MINIFICPP-1694 Change unnecessary errors to warnings
f9d8834 is described below

commit f9d8834f2d5334d438be02d7eea4dc0cee3f8d69
Author: Gabor Gyimesi <ga...@gmail.com>
AuthorDate: Fri Dec 10 13:23:05 2021 +0100

    MINIFICPP-1694 Change unnecessary errors to warnings
    
    Signed-off-by: Adam Debreceni <ad...@apache.org>
    
    This closes #1220
---
 .../RocksDbPersistableKeyValueStoreService.cpp     |  6 ++-
 libminifi/include/core/yaml/CheckRequiredField.h   | 22 +++++---
 libminifi/src/core/yaml/CheckRequiredField.cpp     | 61 +++++++++++++++-------
 libminifi/src/core/yaml/YamlConfiguration.cpp      | 48 ++++++-----------
 libminifi/src/core/yaml/YamlConnectionParser.cpp   |  4 +-
 libminifi/src/properties/Properties.cpp            |  4 ++
 6 files changed, 82 insertions(+), 63 deletions(-)

diff --git a/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp b/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp
index eb8e1c5..95d6991 100644
--- a/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp
+++ b/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp
@@ -127,7 +127,11 @@ bool RocksDbPersistableKeyValueStoreService::get(const std::string& key, std::st
   }
   rocksdb::Status status = opendb->Get(rocksdb::ReadOptions(), key, &value);
   if (!status.ok()) {
-    logger_->log_error("Failed to Get key %s from RocksDB database at %s, error: %s", key.c_str(), directory_.c_str(), status.getState());
+    if (status.getState() != nullptr) {
+      logger_->log_error("Failed to Get key %s from RocksDB database at %s, error: %s", key.c_str(), directory_.c_str(), status.getState());
+    } else {
+      logger_->log_warn("Failed to Get key %s from RocksDB database at %s (it may not have been initialized yet)", key.c_str(), directory_.c_str());
+    }
     return false;
   }
   return true;
diff --git a/libminifi/include/core/yaml/CheckRequiredField.h b/libminifi/include/core/yaml/CheckRequiredField.h
index 7029166..e6e1b50 100644
--- a/libminifi/include/core/yaml/CheckRequiredField.h
+++ b/libminifi/include/core/yaml/CheckRequiredField.h
@@ -19,6 +19,7 @@
 
 #include <string>
 #include <memory>
+#include <vector>
 
 #include "core/logging/LoggerConfiguration.h"
 #include "yaml-cpp/yaml.h"
@@ -30,26 +31,31 @@ namespace minifi {
 namespace core {
 namespace yaml {
 
+bool isFieldPresent(const YAML::Node &yaml_node, std::string_view field_name);
+std::string buildErrorMessage(const YAML::Node &yaml_node, const std::vector<std::string> &alternate_field_names, std::string_view yaml_section = "");
+
 /**
  * This is a helper function for verifying the existence of a required
  * field in a YAML::Node object. If the field is not present, an error
  * message will be logged and an std::invalid_argument exception will be
  * thrown indicating the absence of the required field in the YAML node.
  *
- * @param yamlNode     the YAML node to check
- * @param fieldName    the required field key
- * @param yamlSection  [optional] the top level section of the YAML config
- *                       for the yamlNode. This is used for generating a
+ * @param yaml_node     the YAML node to check
+ * @param field_name    the required field key
+ * @param yaml_section  [optional] the top level section of the YAML config
+ *                       for the yaml_node. This is used for generating a
  *                       useful error message for troubleshooting.
- * @param errorMessage [optional] the error message string to use if
+ * @param error_message [optional] the error message string to use if
  *                       the required field is missing. If not provided,
  *                       a default error message will be generated.
  *
- * @throws std::invalid_argument if the required field 'fieldName' is
- *                               not present in 'yamlNode'
+ * @throws std::invalid_argument if the required field 'field_name' is
+ *                               not present in 'yaml_node'
  */
 void checkRequiredField(
-    const YAML::Node *yamlNode, const std::string &fieldName, const std::shared_ptr<logging::Logger>& logger, const std::string &yamlSection = "", const std::string &errorMessage = "");
+    const YAML::Node &yaml_node, std::string_view field_name, std::string_view yaml_section = "", std::string error_message = "");
+
+std::string getRequiredField(const YAML::Node &yaml_node, const std::vector<std::string> &alternate_names, std::string_view yaml_section, std::string error_message = {});
 
 }  // namespace yaml
 }  // namespace core
diff --git a/libminifi/src/core/yaml/CheckRequiredField.cpp b/libminifi/src/core/yaml/CheckRequiredField.cpp
index 9ea47d7..493e301 100644
--- a/libminifi/src/core/yaml/CheckRequiredField.cpp
+++ b/libminifi/src/core/yaml/CheckRequiredField.cpp
@@ -19,6 +19,7 @@
 #include <stdexcept>
 
 #include "core/yaml/CheckRequiredField.h"
+#include "utils/StringUtils.h"
 
 namespace org {
 namespace apache {
@@ -27,28 +28,48 @@ namespace minifi {
 namespace core {
 namespace yaml {
 
-void checkRequiredField(const YAML::Node *yamlNode, const std::string &fieldName, const std::shared_ptr<logging::Logger>& logger, const std::string &yamlSection, const std::string &errorMessage) {
-  std::string errMsg = errorMessage;
-  if (!yamlNode->as<YAML::Node>()[fieldName]) {
-    if (errMsg.empty()) {
-      const YAML::Node name_node = yamlNode->as<YAML::Node>()["name"];
-      // Build a helpful error message for the user so they can fix the
-      // invalid YAML config file, using the component name if present
-      errMsg =
-          name_node ?
-              "Unable to parse configuration file for component named '" + name_node.as<std::string>() + "' as required field '" + fieldName + "' is missing" :
-              "Unable to parse configuration file as required field '" + fieldName + "' is missing";
-      if (!yamlSection.empty()) {
-        errMsg += " [in '" + yamlSection + "' section of configuration file]";
-      }
-      const YAML::Mark mark = yamlNode->Mark();
-      if (!mark.is_null()) {
-        errMsg += " [line:column, pos at " + std::to_string(mark.line) + ":" + std::to_string(mark.column) + ", " + std::to_string(mark.pos) + "]";
-      }
+bool isFieldPresent(const YAML::Node &yaml_node, std::string_view field_name) {
+  return bool{yaml_node.as<YAML::Node>()[field_name.data()]};
+}
+
+std::string buildErrorMessage(const YAML::Node &yaml_node, const std::vector<std::string> &alternate_field_names, std::string_view yaml_section) {
+  const YAML::Node name_node = yaml_node.as<YAML::Node>()["name"];
+  // Build a helpful error message for the user so they can fix the
+  // invalid YAML config file, using the component name if present
+  auto field_list_string = utils::StringUtils::join(", ", alternate_field_names);
+  std::string err_msg =
+      name_node ?
+          "Unable to parse configuration file for component named '" + name_node.as<std::string>() + "' as none of the possible required fields [" + field_list_string + "] is available" :
+          "Unable to parse configuration file as none of the possible required fields [" + field_list_string + "] is available";
+  if (!yaml_section.empty()) {
+    err_msg += " [in '" + std::string(yaml_section) + "' section of configuration file]";
+  }
+  const YAML::Mark mark = yaml_node.Mark();
+  if (!mark.is_null()) {
+    err_msg += " [line:column, pos at " + std::to_string(mark.line) + ":" + std::to_string(mark.column) + ", " + std::to_string(mark.pos) + "]";
+  }
+  return err_msg;
+}
+
+void checkRequiredField(const YAML::Node &yaml_node, std::string_view field_name, std::string_view yaml_section, std::string error_message) {
+  if (!isFieldPresent(yaml_node, field_name)) {
+    if (error_message.empty()) {
+      error_message = buildErrorMessage(yaml_node, std::vector<std::string>{std::string(field_name)}, yaml_section);
     }
-    logger->log_error(errMsg.c_str());
-    throw std::invalid_argument(errMsg);
+    throw std::invalid_argument(error_message);
+  }
+}
+
+std::string getRequiredField(const YAML::Node &yaml_node, const std::vector<std::string> &alternate_names, std::string_view yaml_section, std::string error_message) {
+  for (const auto& name : alternate_names) {
+    if (yaml::isFieldPresent(yaml_node, name)) {
+      return yaml_node[name].as<std::string>();
+    }
+  }
+  if (error_message.empty()) {
+    error_message = buildErrorMessage(yaml_node, alternate_names, yaml_section);
   }
+  throw std::invalid_argument(error_message);
 }
 
 }  // namespace yaml
diff --git a/libminifi/src/core/yaml/YamlConfiguration.cpp b/libminifi/src/core/yaml/YamlConfiguration.cpp
index dbc8df2..a251b0f 100644
--- a/libminifi/src/core/yaml/YamlConfiguration.cpp
+++ b/libminifi/src/core/yaml/YamlConfiguration.cpp
@@ -58,8 +58,7 @@ std::unique_ptr<core::ProcessGroup> YamlConfiguration::parseRootProcessGroupYaml
 std::unique_ptr<core::ProcessGroup> YamlConfiguration::createProcessGroup(const YAML::Node& yamlNode, bool is_root) {
   int version = 0;
 
-  yaml::checkRequiredField(&yamlNode, "name", logger_,
-  CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
+  yaml::checkRequiredField(yamlNode, "name", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
   std::string flowName = yamlNode["name"].as<std::string>();
 
   utils::Identifier uuid;
@@ -170,14 +169,13 @@ void YamlConfiguration::parseProcessorNodeYaml(const YAML::Node& processorsNode,
     core::ProcessorConfig procCfg;
     YAML::Node procNode = iter->as<YAML::Node>();
 
-    yaml::checkRequiredField(&procNode, "name", logger_,
-    CONFIG_YAML_PROCESSORS_KEY);
+    yaml::checkRequiredField(procNode, "name", CONFIG_YAML_PROCESSORS_KEY);
     procCfg.name = procNode["name"].as<std::string>();
     procCfg.id = getOrGenerateId(procNode);
 
     uuid = procCfg.id.c_str();
     logger_->log_debug("parseProcessorNode: name => [%s] id => [%s]", procCfg.name, procCfg.id);
-    yaml::checkRequiredField(&procNode, "class", logger_, CONFIG_YAML_PROCESSORS_KEY);
+    yaml::checkRequiredField(procNode, "class", CONFIG_YAML_PROCESSORS_KEY);
     procCfg.javaClass = procNode["class"].as<std::string>();
     logger_->log_debug("parseProcessorNode: class => [%s]", procCfg.javaClass);
 
@@ -327,8 +325,7 @@ void YamlConfiguration::parseRemoteProcessGroupYaml(const YAML::Node& rpgNode, c
   for (YAML::const_iterator iter = rpgNode.begin(); iter != rpgNode.end(); ++iter) {
     YAML::Node currRpgNode = iter->as<YAML::Node>();
 
-    yaml::checkRequiredField(&currRpgNode, "name", logger_,
-    CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
+    yaml::checkRequiredField(currRpgNode, "name", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
     auto name = currRpgNode["name"].as<std::string>();
     id = getOrGenerateId(currRpgNode);
 
@@ -413,8 +410,7 @@ void YamlConfiguration::parseRemoteProcessGroupYaml(const YAML::Node& rpgNode, c
     group->setTransmitting(true);
     group->setURL(url);
 
-    yaml::checkRequiredField(&currRpgNode, "Input Ports", logger_,
-    CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
+    yaml::checkRequiredField(currRpgNode, "Input Ports", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
     YAML::Node inputPorts = currRpgNode["Input Ports"].as<YAML::Node>();
     if (inputPorts && inputPorts.IsSequence()) {
       for (YAML::const_iterator portIter = inputPorts.begin(); portIter != inputPorts.end(); ++portIter) {
@@ -457,11 +453,9 @@ void YamlConfiguration::parseProvenanceReportingYaml(const YAML::Node& reportNod
 
   YAML::Node node = reportNode.as<YAML::Node>();
 
-  yaml::checkRequiredField(&node, "scheduling strategy", logger_,
-  CONFIG_YAML_PROVENANCE_REPORT_KEY);
+  yaml::checkRequiredField(node, "scheduling strategy", CONFIG_YAML_PROVENANCE_REPORT_KEY);
   auto schedulingStrategyStr = node["scheduling strategy"].as<std::string>();
-  yaml::checkRequiredField(&node, "scheduling period", logger_,
-  CONFIG_YAML_PROVENANCE_REPORT_KEY);
+  yaml::checkRequiredField(node, "scheduling period", CONFIG_YAML_PROVENANCE_REPORT_KEY);
   auto schedulingPeriodStr = node["scheduling period"].as<std::string>();
 
   core::TimeUnit unit;
@@ -496,9 +490,9 @@ void YamlConfiguration::parseProvenanceReportingYaml(const YAML::Node& reportNod
       logger_->log_debug("ProvenanceReportingTask URL %s", urlStr);
     }
   }
-  yaml::checkRequiredField(&node, "port uuid", logger_, CONFIG_YAML_PROVENANCE_REPORT_KEY);
+  yaml::checkRequiredField(node, "port uuid", CONFIG_YAML_PROVENANCE_REPORT_KEY);
   auto portUUIDStr = node["port uuid"].as<std::string>();
-  yaml::checkRequiredField(&node, "batch size", logger_, CONFIG_YAML_PROVENANCE_REPORT_KEY);
+  yaml::checkRequiredField(node, "batch size", CONFIG_YAML_PROVENANCE_REPORT_KEY);
   auto batchSizeStr = node["batch size"].as<std::string>();
 
   logger_->log_debug("ProvenanceReportingTask port uuid %s", portUUIDStr);
@@ -523,20 +517,12 @@ void YamlConfiguration::parseControllerServices(const YAML::Node& controllerServ
   for (const auto& iter : controllerServicesNode) {
     YAML::Node controllerServiceNode = iter.as<YAML::Node>();
     try {
-      yaml::checkRequiredField(&controllerServiceNode, "name", logger_,
-      CONFIG_YAML_CONTROLLER_SERVICES_KEY);
-      yaml::checkRequiredField(&controllerServiceNode, "id", logger_,
-      CONFIG_YAML_CONTROLLER_SERVICES_KEY);
-      std::string type = "";
+      yaml::checkRequiredField(controllerServiceNode, "name", CONFIG_YAML_CONTROLLER_SERVICES_KEY);
+      yaml::checkRequiredField(controllerServiceNode, "id", CONFIG_YAML_CONTROLLER_SERVICES_KEY);
+
+      auto type = yaml::getRequiredField(controllerServiceNode, std::vector<std::string>{"class", "type"}, CONFIG_YAML_CONTROLLER_SERVICES_KEY);
+      logger_->log_debug("Using type %s for controller service node", type);
 
-      try {
-        yaml::checkRequiredField(&controllerServiceNode, "class", logger_, CONFIG_YAML_CONTROLLER_SERVICES_KEY);
-        type = controllerServiceNode["class"].as<std::string>();
-      } catch (const std::invalid_argument &) {
-        yaml::checkRequiredField(&controllerServiceNode, "type", logger_, CONFIG_YAML_CONTROLLER_SERVICES_KEY);
-        type = controllerServiceNode["type"].as<std::string>();
-        logger_->log_debug("Using type %s for controller service node", type);
-      }
       std::string fullType = type;
       auto lastOfIdx = type.find_last_of(".");
       if (lastOfIdx != std::string::npos) {
@@ -625,11 +611,9 @@ void YamlConfiguration::parsePortYaml(const YAML::Node& portNode, core::ProcessG
   YAML::Node inputPortsObj = portNode.as<YAML::Node>();
 
   // Check for required fields
-  yaml::checkRequiredField(&inputPortsObj, "name", logger_,
-  CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
+  yaml::checkRequiredField(inputPortsObj, "name", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
   auto nameStr = inputPortsObj["name"].as<std::string>();
-  yaml::checkRequiredField(&inputPortsObj, "id", logger_,
-  CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY,
+  yaml::checkRequiredField(inputPortsObj, "id", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY,
                      "The field 'id' is required for "
                          "the port named '" + nameStr + "' in the YAML Config. If this port "
                          "is an input port for a NiFi Remote Process Group, the port "
diff --git a/libminifi/src/core/yaml/YamlConnectionParser.cpp b/libminifi/src/core/yaml/YamlConnectionParser.cpp
index b8434d5..b434d9d 100644
--- a/libminifi/src/core/yaml/YamlConnectionParser.cpp
+++ b/libminifi/src/core/yaml/YamlConnectionParser.cpp
@@ -114,7 +114,7 @@ utils::Identifier YamlConnectionParser::getSourceUUIDFromYaml() const {
     throw std::invalid_argument("Invalid source id");
   }
   // if we don't have a source id, try to resolve using source name. config schema v2 will make this unnecessary
-  checkRequiredField(&connectionNode_, "source name", logger_, CONFIG_YAML_CONNECTIONS_KEY);
+  checkRequiredField(connectionNode_, "source name", CONFIG_YAML_CONNECTIONS_KEY);
   const auto connectionSrcProcName = connectionNode_["source name"].as<std::string>();
   const auto srcUUID = utils::Identifier::parse(connectionSrcProcName);
   if (srcUUID && parent_->findProcessorById(srcUUID.value(), ProcessGroup::Traverse::ExcludeChildren)) {
@@ -147,7 +147,7 @@ utils::Identifier YamlConnectionParser::getDestinationUUIDFromYaml() const {
   }
   // we use the same logic as above for resolving the source processor
   // for looking up the destination processor in absence of a processor id
-  checkRequiredField(&connectionNode_, "destination name", logger_, CONFIG_YAML_CONNECTIONS_KEY);
+  checkRequiredField(connectionNode_, "destination name", CONFIG_YAML_CONNECTIONS_KEY);
   std::string connectionDestProcName = connectionNode_["destination name"].as<std::string>();
   const auto destUUID = utils::Identifier::parse(connectionDestProcName);
   if (destUUID && parent_->findProcessorById(destUUID.value(), ProcessGroup::Traverse::ExcludeChildren)) {
diff --git a/libminifi/src/properties/Properties.cpp b/libminifi/src/properties/Properties.cpp
index 061afed..02b2378 100644
--- a/libminifi/src/properties/Properties.cpp
+++ b/libminifi/src/properties/Properties.cpp
@@ -76,6 +76,10 @@ void Properties::loadConfigureFile(const char *fileName) {
   }
 
   properties_file_ = utils::file::getFullPath(utils::file::FileUtils::concat_path(getHome(), fileName));
+  if (properties_file_.empty()) {
+    logger_->log_warn("Configuration file '%s' does not exist, so it could not be loaded.", fileName);
+    return;
+  }
 
   logger_->log_info("Using configuration file to load configuration for %s from %s (located at %s)",
                     getName().c_str(), fileName, properties_file_);