You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by fg...@apache.org on 2022/03/08 13:54:12 UTC

[nifi-minifi-cpp] 02/05: MINIFICPP-1754 - Always include agentManifestIdentifier in heartbeat

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

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

commit 2e394616de4660e2ba62d85d8227baae144ab4f0
Author: Adam Markovics <nu...@gmail.com>
AuthorDate: Thu Feb 17 13:34:47 2022 +0100

    MINIFICPP-1754 - Always include agentManifestIdentifier in heartbeat
    
    Signed-off-by: Ferenc Gerlits <fg...@gmail.com>
    
    This closes #1269
---
 extensions/http-curl/tests/HTTPHandlers.h          |  7 +++++++
 libminifi/include/core/state/Value.h               |  2 ++
 .../include/core/state/nodes/AgentInformation.h    | 24 ++++++++++++++++------
 libminifi/src/core/state/Value.cpp                 | 23 +++++++++++++++++++++
 4 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/extensions/http-curl/tests/HTTPHandlers.h b/extensions/http-curl/tests/HTTPHandlers.h
index b198677..093deca 100644
--- a/extensions/http-curl/tests/HTTPHandlers.h
+++ b/extensions/http-curl/tests/HTTPHandlers.h
@@ -426,6 +426,13 @@ class HeartbeatHandler : public ServerAwareHandler {
     assert(root.HasMember("agentInfo"));
     assert(root["agentInfo"].HasMember("agentManifest"));
     assert(root["agentInfo"]["agentManifest"].HasMember("bundles"));
+    assert(root["agentInfo"].HasMember("agentManifestHash"));
+    const std::string manifestHash = root["agentInfo"]["agentManifestHash"].GetString();
+    assert(manifestHash.length() == 128);
+
+    // throws if not a valid hexadecimal hash
+    const auto hashVec = utils::StringUtils::from_hex(manifestHash);
+    assert(hashVec.size() == 64);
 
     for (auto &bundle : root["agentInfo"]["agentManifest"]["bundles"].GetArray()) {
       assert(bundle.HasMember("artifact"));
diff --git a/libminifi/include/core/state/Value.h b/libminifi/include/core/state/Value.h
index d8f8995..8aa2702 100644
--- a/libminifi/include/core/state/Value.h
+++ b/libminifi/include/core/state/Value.h
@@ -571,6 +571,8 @@ struct SerializedResponseNode {
   }
 };
 
+std::string hashResponseNodes(const std::vector<SerializedResponseNode>& nodes);
+
 }  // namespace response
 }  // namespace state
 }  // namespace minifi
diff --git a/libminifi/include/core/state/nodes/AgentInformation.h b/libminifi/include/core/state/nodes/AgentInformation.h
index 8eb0fa4..fb54e2e 100644
--- a/libminifi/include/core/state/nodes/AgentInformation.h
+++ b/libminifi/include/core/state/nodes/AgentInformation.h
@@ -600,12 +600,8 @@ class AgentMonitor {
  */
 class AgentManifest : public DeviceInformation {
  public:
-  AgentManifest(const std::string& name, const utils::Identifier& uuid)
-      : DeviceInformation(name, uuid) {
-  }
-
-  AgentManifest(const std::string &name) // NOLINT
-      : DeviceInformation(name) {
+  explicit AgentManifest(std::string name)
+      : DeviceInformation(std::move(name)) {
   }
 
   std::string getName() const {
@@ -710,6 +706,11 @@ class AgentNode : public DeviceInformation, public AgentMonitor, public AgentIde
       serialized.push_back(agentClass);
     }
 
+    SerializedResponseNode agentManifestHash;
+    agentManifestHash.name = "agentManifestHash";
+    agentManifestHash.value = getAgentManifestHash();
+    serialized.push_back(agentManifestHash);
+
     return serialized;
   }
 
@@ -720,6 +721,14 @@ class AgentNode : public DeviceInformation, public AgentMonitor, public AgentIde
     return std::vector<SerializedResponseNode>{ agentManifest };
   }
 
+  std::string getAgentManifestHash() {
+    if (!agentManifestHash_.has_value()) {
+      agentManifestHash_ = hashResponseNodes(getAgentManifest());
+    }
+
+    return *agentManifestHash_;
+  }
+
   std::vector<SerializedResponseNode> getAgentStatus() const {
     std::vector<SerializedResponseNode> serialized;
 
@@ -736,6 +745,9 @@ class AgentNode : public DeviceInformation, public AgentMonitor, public AgentIde
     serialized.push_back(agentStatus);
     return serialized;
   }
+
+ private:
+  std::optional<std::string> agentManifestHash_;
 };
 
 /**
diff --git a/libminifi/src/core/state/Value.cpp b/libminifi/src/core/state/Value.cpp
index 986ed55..49cc8fd 100644
--- a/libminifi/src/core/state/Value.cpp
+++ b/libminifi/src/core/state/Value.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "core/state/Value.h"
+#include <openssl/sha.h>
 #include <utility>
 #include <string>
 
@@ -35,6 +36,28 @@ const std::type_index Value::BOOL_TYPE = std::type_index(typeid(bool));
 const std::type_index Value::DOUBLE_TYPE = std::type_index(typeid(double));
 const std::type_index Value::STRING_TYPE = std::type_index(typeid(std::string));
 
+void hashNode(const SerializedResponseNode& node, SHA512_CTX& ctx) {
+  SHA512_Update(&ctx, node.name.c_str(), node.name.length());
+  const auto valueStr = node.value.to_string();
+  SHA512_Update(&ctx, valueStr.c_str(), valueStr.length());
+  SHA512_Update(&ctx, &node.array, sizeof(node.array));
+  SHA512_Update(&ctx, &node.collapsible, sizeof(node.collapsible));
+  for (const auto& child : node.children) {
+    hashNode(child, ctx);
+  }
+}
+
+std::string hashResponseNodes(const std::vector<SerializedResponseNode>& nodes) {
+  SHA512_CTX ctx;
+  SHA512_Init(&ctx);
+  for (const auto& node : nodes) {
+    hashNode(node, ctx);
+  }
+  std::array<std::byte, SHA512_DIGEST_LENGTH> digest{};
+  SHA512_Final(reinterpret_cast<unsigned char*>(digest.data()), &ctx);
+  return utils::StringUtils::to_hex(digest, true /*uppercase*/);
+}
+
 } /* namespace response */
 } /* namespace state */
 } /* namespace minifi */