Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MINIFICPP-2314 - Send asset state hash in heartbeat, implement c2 asset sync #1751

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
af01a86
MINIFICPP-2314 - Send asset state hash in heartbeat, implement c2 ass…
adamdebreceni Mar 28, 2024
d4050b2
MINIFICPP-2314 - Build fix
adamdebreceni Apr 3, 2024
3524429
MINIFICPP-2314 - Build fix
adamdebreceni Apr 3, 2024
334a371
MINIFICPP-2314 - Build fix
adamdebreceni Apr 3, 2024
8f4441e
MINIFICPP-2314 - Fix test
adamdebreceni Apr 3, 2024
7350ca4
MINIFICPP-2314 - Fix test
adamdebreceni Apr 3, 2024
857825c
MINIFICPP-2314 - Fix windows build
adamdebreceni Apr 3, 2024
b0f27a9
Update libminifi/src/core/state/nodes/AssetInformation.cpp
adamdebreceni Apr 10, 2024
2acbda5
Update libminifi/src/core/state/nodes/AssetInformation.cpp
adamdebreceni Apr 10, 2024
0e99d13
Update extensions/http-curl/tests/C2AssetSyncTest.cpp
adamdebreceni Apr 10, 2024
503d0f6
MINIFICPP-2314 - Review changes
adamdebreceni Apr 10, 2024
5ba34ca
MINIFICPP-2314 - Linter fix
adamdebreceni Apr 10, 2024
1c5586e
MINIFICPP-2314 - Fix build
adamdebreceni Apr 10, 2024
cc70907
MINIFICPP-2314 - Review changes
adamdebreceni Apr 15, 2024
8a3d70e
MINIFICPP-2314 - Clang tidy fix
adamdebreceni Apr 17, 2024
b5fbf6c
MINIFICPP-2314 - Windows fix
adamdebreceni Apr 17, 2024
63bcddc
MINIFICPP-2314 - Fix test
adamdebreceni Apr 29, 2024
679e0e4
MINIFICPP-2314 - Make sure that home dir is not the temp dir
adamdebreceni May 2, 2024
6734bb1
MINIFICPP-2314 - Change sync operand
adamdebreceni May 29, 2024
e4152e0
MINIFICPP-2314 - Update c2 protocol
adamdebreceni May 29, 2024
7e1a69a
MINIFICPP-2314 - Update c2 protocol
adamdebreceni Jun 5, 2024
52f823b
MINIFICPP-2314 - Linter
adamdebreceni Jun 5, 2024
a8e8888
MINIFICPP-2314 - Windows fix
adamdebreceni Jun 5, 2024
046d318
MINIFICPP-2314 - Linter fix
adamdebreceni Jun 5, 2024
1a480d5
MINIFICPP-2314 - Clang tidy fix
adamdebreceni Jun 6, 2024
ec8d52a
MINIFICPP-2314 - Linter fix
adamdebreceni Jun 11, 2024
a4847a0
MINIFICPP-2314 - Add nifi.c2.rest.path.base agent property
adamdebreceni Jun 19, 2024
7f97cf0
MINIFICPP-2314 - Fix test, log errors
adamdebreceni Jun 19, 2024
04deb54
MINIFICPP-2314 - Review fixes
adamdebreceni Jul 2, 2024
c10232c
Update CONFIGURE.md
adamdebreceni Jul 2, 2024
5820a56
Update C2.md
adamdebreceni Jul 2, 2024
4b55a7f
Update libminifi/test/integration/C2AssetSyncTest.cpp
adamdebreceni Jul 2, 2024
6e64197
Update libminifi/src/utils/file/AssetManager.cpp
adamdebreceni Jul 2, 2024
606356d
Update libminifi/src/utils/file/AssetManager.cpp
adamdebreceni Jul 2, 2024
d9806d0
MINIFICPP-2314 - Properly restore working directory
adamdebreceni Jul 9, 2024
7be2b74
MINIFICPP-2314 - Linter fix
adamdebreceni Jul 10, 2024
d32136b
MINIFICPP-2314 - Linter fix
adamdebreceni Jul 10, 2024
2585412
MINIFICPP-2314 - Build fix
adamdebreceni Jul 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions C2.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ be requested via C2 DESCRIBE manifest command.
# DeviceInfoNode: basic info about the system (OS, number of cores etc)
# AgentInformation: info about the MiNiFi agent, may include the manifest
# FlowInformation: information about the current flow, including queue sizes
# AssetInformation: the state of the asset directory managed by the agent
# ConfigurationChecksums: hashes of the configuration files; can be used to detect unexpected modifications
# the default is
nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation
nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation,AssetInformation

# control c2 heartbeat interval
nifi.c2.agent.heartbeat.period=30 sec
Expand All @@ -80,8 +81,10 @@ be requested via C2 DESCRIBE manifest command.
nifi.c2.rest.listener.cacert=<SSL Cert path>

# specify the rest URIs if using RESTSender
nifi.c2.rest.url=http://<your-c2-server>/<c2-api-path>/c2-protocol/heartbeat
nifi.c2.rest.url.ack=http://<your-c2-server>/<c2-api-path>/c2-protocol/acknowledge
nifi.c2.rest.path.base=https://<your-c2-server>/<c2-api-path>
# specify either absolute url or relative to the nifi.c2.rest.path.base url for hearbeat and acknowledge
nifi.c2.rest.url=/c2-protocol/heartbeat
nifi.c2.rest.url.ack=/c2-protocol/acknowledge
nifi.c2.flow.base.url=http://<your-c2-server>/<c2-api-path>/c2-protocol/

# c2 agent identifier -- must be defined to run agent
Expand Down
9 changes: 7 additions & 2 deletions CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -567,8 +567,13 @@ Additionally, a unique hexadecimal uid.minifi.device.segment should be assigned

### Asset directory

It is possible to make agents download an asset (triggered through the c2 protocol). The target directory can be specified
using the `nifi.asset.directory` agent property, which defaults to `${MINIFI_HOME}/asset`.
There is an asset directory specified using the `nifi.asset.directory` agent property, which defaults to `${MINIFI_HOME}/asset`.
The files referenced in the `.state` file in this directory are managed by the agent. They are deleted, updated, downloaded
using the asset sync c2 command. For the asset sync command to work, the c2 server must be made aware of the current state of the
managed assets by adding the `AssetInformation` entry to the `nifi.c2.root.classes` property.

Files and directories not referenced in the `.state` file are not directly controlled by the agent, although
it is possible to download an asset (triggered through the c2 protocol) into the asset directory instead.

### Controller Services
If you need to reference a controller service in your config.yml file, use the following template. In the example, below, ControllerServiceClass is the name of the class defining the controller Service. ControllerService1
Expand Down
3 changes: 2 additions & 1 deletion conf/minifi.properties
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,11 @@ nifi.content.repository.class.name=DatabaseContentRepository
## base URL of the c2 server,
## very likely the same base url of rest urls
#nifi.c2.flow.base.url=
#nifi.c2.rest.path.base=
#nifi.c2.rest.url=
#nifi.c2.rest.url.ack=
#nifi.c2.rest.ssl.context.service=
nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation
nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation,AssetInformation
martinzink marked this conversation as resolved.
Show resolved Hide resolved
lordgamez marked this conversation as resolved.
Show resolved Hide resolved
## Minimize heartbeat payload size by excluding agent manifest from the heartbeat
nifi.c2.full.heartbeat=false
## heartbeat twice a minute
Expand Down
4 changes: 2 additions & 2 deletions docker/test/integration/cluster/containers/MinifiContainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _create_properties(self):
f.write(f"nifi.c2.rest.url=http://minifi-c2-server-{self.feature_context.id}:10090/c2/config/heartbeat\n")
f.write(f"nifi.c2.rest.url.ack=http://minifi-c2-server-{self.feature_context.id}:10090/c2/config/acknowledge\n")
f.write(f"nifi.c2.flow.base.url=http://minifi-c2-server-{self.feature_context.id}:10090/c2/config/\n")
f.write("nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation\n")
f.write("nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation,AssetInformation\n")
f.write("nifi.c2.full.heartbeat=false\n")
f.write("nifi.c2.agent.class=minifi-test-class\n")
f.write("nifi.c2.agent.identifier=minifi-test-id\n")
Expand All @@ -109,7 +109,7 @@ def _create_properties(self):
f.write(f"nifi.c2.rest.url.ack=https://minifi-c2-server-{self.feature_context.id}:10090/c2/config/acknowledge\n")
f.write("nifi.c2.rest.ssl.context.service=SSLContextService\n")
f.write(f"nifi.c2.flow.base.url=https://minifi-c2-server-{self.feature_context.id}:10090/c2/config/\n")
f.write("nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation\n")
f.write("nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation,AssetInformation\n")
f.write("nifi.c2.full.heartbeat=false\n")
f.write("nifi.c2.agent.class=minifi-test-class\n")
f.write("nifi.c2.agent.identifier=minifi-test-id\n")
Expand Down
2 changes: 1 addition & 1 deletion encrypt-config/tests/resources/minifi.properties
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ nifi.c2.enable=true
nifi.c2.flow.base.url=http://localhost:10080/c2-server/api
nifi.c2.rest.url=http://localhost:10080/c2-server/api/c2-protocol/heartbeat
nifi.c2.rest.url.ack=http://localhost:10080/c2-server/api/c2-protocol/acknowledge
nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation
nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation,AssetInformation
## Minimize heartbeat payload size by excluding agent manifest from the heartbeat
#nifi.c2.full.heartbeat=false
## heartbeat 4 times a second
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ nifi.c2.enable=true
nifi.c2.flow.base.url=http://localhost:10080/c2-server/api
nifi.c2.rest.url=http://localhost:10080/c2-server/api/c2-protocol/heartbeat
nifi.c2.rest.url.ack=http://localhost:10080/c2-server/api/c2-protocol/acknowledge
nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation
nifi.c2.root.classes=DeviceInfoNode,AgentInformation,FlowInformation,AssetInformation
## Minimize heartbeat payload size by excluding agent manifest from the heartbeat
#nifi.c2.full.heartbeat=false
## heartbeat 4 times a second
Expand Down
4 changes: 3 additions & 1 deletion libminifi/include/FlowController.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include "TimerDrivenSchedulingAgent.h"
#include "utils/Id.h"
#include "utils/file/FileSystem.h"
#include "utils/file/AssetManager.h"
#include "core/state/nodes/ResponseNodeLoader.h"
#include "core/state/MetricsPublisher.h"
#include "core/state/MetricsPublisherStore.h"
Expand All @@ -72,7 +73,8 @@ class FlowController : public core::controller::ForwardingControllerServiceProvi
FlowController(std::shared_ptr<core::Repository> provenance_repo, std::shared_ptr<core::Repository> flow_file_repo,
std::shared_ptr<Configure> configure, std::shared_ptr<core::FlowConfiguration> flow_configuration,
std::shared_ptr<core::ContentRepository> content_repo, std::unique_ptr<state::MetricsPublisherStore> metrics_publisher_store = nullptr,
std::shared_ptr<utils::file::FileSystem> filesystem = std::make_shared<utils::file::FileSystem>(), std::function<void()> request_restart = []{});
std::shared_ptr<utils::file::FileSystem> filesystem = std::make_shared<utils::file::FileSystem>(), std::function<void()> request_restart = []{},
std::shared_ptr<utils::file::AssetManager> asset_manager = {});

~FlowController() override;

Expand Down
8 changes: 7 additions & 1 deletion libminifi/include/c2/C2Agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "utils/ThreadPool.h"
#include "utils/file/FileSystem.h"
#include "C2Utils.h"
#include "utils/file/AssetManager.h"

namespace org::apache::nifi::minifi::c2 {

Expand All @@ -62,7 +63,8 @@ class C2Agent : public state::UpdateController {
C2Agent(std::shared_ptr<Configure> configuration,
std::weak_ptr<state::response::NodeReporter> node_reporter,
std::shared_ptr<utils::file::FileSystem> filesystem,
std::function<void()> request_restart);
std::function<void()> request_restart,
std::shared_ptr<utils::file::AssetManager> asset_manager);

void initialize(core::controller::ControllerServiceProvider *controller, state::Pausable *pause_handler, state::StateMonitor* update_sink);
void start() override;
Expand Down Expand Up @@ -131,6 +133,8 @@ class C2Agent : public state::UpdateController {
*/
void handle_describe(const C2ContentResponse &resp);

void handle_sync(const C2ContentResponse &resp);


enum class UpdateResult {
NO_UPDATE,
Expand Down Expand Up @@ -235,6 +239,8 @@ class C2Agent : public state::UpdateController {

// time point the last time we performed a heartbeat.
std::chrono::steady_clock::time_point last_run_;

std::shared_ptr<utils::file::AssetManager> asset_manager_;
};

} // namespace org::apache::nifi::minifi::c2
Expand Down
76 changes: 63 additions & 13 deletions libminifi/include/c2/C2Payload.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "utils/Enum.h"
#include "utils/gsl.h"
#include "utils/span.h"
#include "rapidjson/document.h"

namespace org::apache::nifi::minifi::c2 {

Expand All @@ -43,7 +44,8 @@ enum class Operation : uint8_t {
clear,
transfer,
pause,
resume
resume,
sync
};

enum class DescribeOperand : uint8_t {
Expand All @@ -70,6 +72,10 @@ enum class ClearOperand : uint8_t{
corecomponentstate
};

enum class SyncOperand : uint8_t{
resource
};

#define PAYLOAD_NO_STATUS 0
#define PAYLOAD_SUCCESS 1
#define PAYLOAD_FAILURE 2
Expand All @@ -79,21 +85,65 @@ enum Direction {
RECEIVE
};

struct AnnotatedValue : state::response::ValueNode {
using state::response::ValueNode::ValueNode;
using state::response::ValueNode::operator=;
class C2Value {
public:
friend std::ostream& operator<<(std::ostream& out, const C2Value& val);

C2Value() = default;
C2Value(const C2Value& other) {
(*this) = other;
}
C2Value(C2Value&&) = default;
template<typename T>
requires(std::constructible_from<state::response::ValueNode, T>)
C2Value(T&& value) { value_ = state::response::ValueNode{std::forward<T>(value)}; } // NOLINT(runtime/explicit)
C2Value(const rapidjson::Value& json_value) { // NOLINT(runtime/explicit)
value_.emplace<rapidjson::Document>();
get<rapidjson::Document>(value_).CopyFrom(json_value, get<rapidjson::Document>(value_).GetAllocator());
}
C2Value(rapidjson::Document&& json_doc) { // NOLINT(runtime/explicit)
value_ = std::move(json_doc);
}

[[nodiscard]] std::optional<std::reference_wrapper<const AnnotatedValue>> getAnnotation(const std::string& name) const {
auto it = annotations.find(name);
if (it == annotations.end()) {
return {};
C2Value& operator=(const C2Value& other) {
if (auto* other_val_node = get_if<state::response::ValueNode>(&other.value_)) {
value_ = *other_val_node;
} else {
value_.emplace<rapidjson::Document>();
get<rapidjson::Document>(value_).CopyFrom(get<rapidjson::Document>(other.value_), get<rapidjson::Document>(value_).GetAllocator());
}
return std::cref(it->second);
return *this;
}

C2Value& operator=(C2Value&&) = default;


bool empty() const {
if (auto* val_node = get_if<state::response::ValueNode>(&value_)) {
return val_node->empty();
}
return false;
}

std::string to_string() const {
if (auto* val_node = get_if<state::response::ValueNode>(&value_)) {
return val_node->to_string();
}
return std::string{get<rapidjson::Document>(value_).GetString(), get<rapidjson::Document>(value_).GetStringLength()};
}

const rapidjson::Document* json() const {
return get_if<rapidjson::Document>(&value_);
}

const state::response::ValueNode* valueNode() const {
return get_if<state::response::ValueNode>(&value_);
}

friend std::ostream& operator<<(std::ostream& out, const AnnotatedValue& val);
bool operator==(const C2Value&) const = default;

std::map<std::string, AnnotatedValue> annotations;
private:
std::variant<state::response::ValueNode, rapidjson::Document> value_;
};

struct C2ContentResponse {
Expand All @@ -115,7 +165,7 @@ struct C2ContentResponse {

friend std::ostream& operator<<(std::ostream& out, const C2ContentResponse& response);

std::optional<std::string> getArgument(const std::string& arg_name) const {
std::optional<std::string> getStringArgument(const std::string& arg_name) const {
if (auto it = operation_arguments.find(arg_name); it != operation_arguments.end()) {
return it->second.to_string();
}
Expand All @@ -134,7 +184,7 @@ struct C2ContentResponse {
// name applied to commands
std::string name;
// commands that correspond with the operation.
std::map<std::string, AnnotatedValue> operation_arguments;
std::map<std::string, C2Value> operation_arguments;
};

/**
Expand Down
27 changes: 10 additions & 17 deletions libminifi/include/c2/PayloadParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,27 +138,20 @@ class PayloadParser {
}

template<typename T>
inline T getAs(const std::string &field) {
inline T getAs(const std::string &field, const std::optional<T>& fallback = std::nullopt) {
for (const auto &cmd : ref_.getContent()) {
auto exists = cmd.operation_arguments.find(field);
if (exists != cmd.operation_arguments.end()) {
return convert_if<T>(exists->second.getValue())();
if (auto it = cmd.operation_arguments.find(field); it != cmd.operation_arguments.end()) {
if (auto* val_node = it->second.valueNode()) {
return convert_if<T>(val_node->getValue())();
}
}
}
std::stringstream ss;
ss << "Invalid Field. Could not find " << field << " in " << ref_.getLabel();
throw PayloadParseException(ss.str());
}

template<typename T>
inline T getAs(const std::string &field, const T &fallback) {
for (const auto &cmd : ref_.getContent()) {
auto exists = cmd.operation_arguments.find(field);
if (exists != cmd.operation_arguments.end()) {
return convert_if<T>(exists->second.getValue())();
}
if (!fallback) {
std::stringstream ss;
ss << "Invalid Field. Could not find " << field << " in " << ref_.getLabel();
throw PayloadParseException(ss.str());
}
return fallback;
return fallback.value();
}

size_t getSize() const {
Expand Down
6 changes: 3 additions & 3 deletions libminifi/include/c2/PayloadSerializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class PayloadSerializer {
/**
* Static function that serializes the value nodes
*/
static void serializeValueNode(state::response::ValueNode &value, std::shared_ptr<io::OutputStream> stream) {
static void serializeValueNode(const state::response::ValueNode &value, std::shared_ptr<io::OutputStream> stream) {
auto base_type = value.getValue();
if (!base_type) {
uint8_t type = 0;
Expand Down Expand Up @@ -95,7 +95,7 @@ class PayloadSerializer {
stream->write(size);
for (auto content : payload_content.operation_arguments) {
stream->write(content.first);
serializeValueNode(content.second, stream);
serializeValueNode(*gsl::not_null(content.second.valueNode()), stream);
}
}
if (nested_payload.getNestedPayloads().size() > 0) {
Expand Down Expand Up @@ -170,7 +170,7 @@ class PayloadSerializer {
stream->write(size);
for (auto content : payload_content.operation_arguments) {
stream->write(content.first);
serializeValueNode(content.second, stream);
serializeValueNode(*gsl::not_null(content.second.valueNode()), stream);
}
}
serialize(op, payload, stream);
Expand Down
2 changes: 1 addition & 1 deletion libminifi/include/c2/protocols/RESTProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class RESTProtocol : public HeartbeatJsonSerializer {
protected:
void initialize(core::controller::ControllerServiceProvider* controller, const std::shared_ptr<Configure> &configure);
void serializeNestedPayload(rapidjson::Value& target, const C2Payload& payload, rapidjson::Document::AllocatorType& alloc) override;
static C2Payload parseJsonResponse(const C2Payload &payload, std::span<const std::byte> response);
C2Payload parseJsonResponse(const C2Payload &payload, std::span<const std::byte> response);

private:
bool containsPayload(const C2Payload &o);
Expand Down
3 changes: 2 additions & 1 deletion libminifi/include/core/state/MetricsPublisherStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
#include "core/state/nodes/ResponseNodeLoader.h"
#include "utils/gsl.h"
#include "core/ProcessGroup.h"
#include "utils/file/AssetManager.h"

namespace org::apache::nifi::minifi::state {

class MetricsPublisherStore {
public:
MetricsPublisherStore(std::shared_ptr<Configure> configuration, const std::vector<std::shared_ptr<core::RepositoryMetricsSource>>& repository_metric_sources,
std::shared_ptr<core::FlowConfiguration> flow_configuration);
std::shared_ptr<core::FlowConfiguration> flow_configuration, std::shared_ptr<utils::file::AssetManager> asset_manager = nullptr);
void initialize(core::controller::ControllerServiceProvider* controller, state::StateMonitor* update_sink);
void loadMetricNodes(core::ProcessGroup* root);
void clearMetricNodes();
Expand Down
42 changes: 42 additions & 0 deletions libminifi/include/core/state/nodes/AssetInformation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once

#include "core/state/nodes/MetricsBase.h"
#include "utils/file/AssetManager.h"
#include "core/logging/Logger.h"

namespace org::apache::nifi::minifi::state::response {

class AssetInformation : public ResponseNode {
public:
AssetInformation();
explicit AssetInformation(std::string_view name, const utils::Identifier& uuid = {}) : ResponseNode(name, uuid) {}

MINIFIAPI static constexpr const char* Description = "Metric node that defines hash for all asset identifiers";

void setAssetManager(std::shared_ptr<utils::file::AssetManager> asset_manager);

std::string getName() const override { return "resourceInfo"; }
std::vector<SerializedResponseNode> serialize() override;

private:
std::shared_ptr<utils::file::AssetManager> asset_manager_;
std::shared_ptr<core::logging::Logger> logger_;
};

} // namespace org::apache::nifi::minifi::state::response
Loading
Loading