This is an automated email from the ASF dual-hosted git repository.
szaszm 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 7988c8b0e MINIFICPP-2765 Move GCP Extension to stable C API (#2153)
7988c8b0e is described below
commit 7988c8b0e3afcb7a191c364524ae2ea3b958c291
Author: Martin Zink <[email protected]>
AuthorDate: Tue Jun 16 14:29:03 2026 +0200
MINIFICPP-2765 Move GCP Extension to stable C API (#2153)
---
.../src/minifi_behave/steps/checking_steps.py | 2 +-
.../include/api/core/ProcessContext.h | 15 +-
.../include/api/utils/ProcessorConfigUtils.h | 6 +-
.../include/api/utils/{Ssl.h => Proxy.h} | 40 +++---
.../cpp-extension-lib/include/api/utils/Ssl.h | 4 -
.../mocklib/include/MockProcessContext.h | 6 +-
.../mocklib/src/MockProcessContext.cpp | 10 +-
.../mocklib/src/mock-minifi-c.cpp | 7 +-
.../cpp-extension-lib/src/core/ProcessContext.cpp | 47 +++++-
extensions/gcp/CMakeLists.txt | 6 +-
extensions/gcp/ExtensionInitializer.cpp | 46 ++++++
extensions/gcp/GCPAttributes.h | 49 +++----
.../GCPCredentialsControllerService.cpp | 34 ++---
.../GCPCredentialsControllerService.h | 27 ++--
extensions/gcp/processors/DeleteGCSObject.cpp | 52 +++----
extensions/gcp/processors/DeleteGCSObject.h | 14 +-
extensions/gcp/processors/FetchGCSObject.cpp | 78 +++++-----
extensions/gcp/processors/FetchGCSObject.h | 16 +--
extensions/gcp/processors/GCSProcessor.cpp | 32 ++---
extensions/gcp/processors/GCSProcessor.h | 22 ++-
extensions/gcp/processors/ListGCSBucket.cpp | 39 +++--
extensions/gcp/processors/ListGCSBucket.h | 13 +-
extensions/gcp/processors/PutGCSObject.cpp | 71 +++++----
extensions/gcp/processors/PutGCSObject.h | 12 +-
extensions/gcp/tests/CMakeLists.txt | 2 +-
extensions/gcp/tests/DeleteGCSObjectTests.cpp | 82 ++++++-----
extensions/gcp/tests/FetchGCSObjectTests.cpp | 83 ++++++-----
.../tests/GCPCredentialsControllerServiceTests.cpp | 59 +++++---
extensions/gcp/tests/ListGCSBucketTests.cpp | 86 +++++------
extensions/gcp/tests/PutGCSObjectTests.cpp | 159 +++++++++++----------
extensions/kafka/KafkaProcessorBase.cpp | 4 +-
extensions/kafka/rdkafka_utils.h | 1 +
libminifi/src/minifi-c.cpp | 49 ++++++-
minifi-api/include/minifi-c/minifi-c.h | 25 +++-
minifi-api/minifi-c-api.def | 3 +-
35 files changed, 665 insertions(+), 536 deletions(-)
diff --git a/behave_framework/src/minifi_behave/steps/checking_steps.py
b/behave_framework/src/minifi_behave/steps/checking_steps.py
index 5f52ee740..418e875c9 100644
--- a/behave_framework/src/minifi_behave/steps/checking_steps.py
+++ b/behave_framework/src/minifi_behave/steps/checking_steps.py
@@ -119,7 +119,7 @@ def verify_minifi_logs_match_regex(context, regex,
duration):
@step('no errors were generated on the http-proxy regarding "{url}"')
def verify_no_errors_on_http_proxy(context: MinifiTestContext, url: str):
http_proxy_container = next(container for container in
context.containers.values() if isinstance(container, HttpProxy))
- assert http_proxy_container.check_http_proxy_access(url) or
http_proxy_container.log_app_output()
+ assert http_proxy_container.check_http_proxy_access(url) or
log_due_to_failure(context)
@then('in the "{container}" container no files are placed in the "{directory}"
directory in {duration} of running time')
diff --git
a/extension-framework/cpp-extension-lib/include/api/core/ProcessContext.h
b/extension-framework/cpp-extension-lib/include/api/core/ProcessContext.h
index 87209577c..26a55a44a 100644
--- a/extension-framework/cpp-extension-lib/include/api/core/ProcessContext.h
+++ b/extension-framework/cpp-extension-lib/include/api/core/ProcessContext.h
@@ -17,10 +17,11 @@
#pragma once
-#include <string>
#include <expected>
+#include <string>
#include "api/core/FlowFile.h"
+#include "api/utils/Proxy.h"
#include "api/utils/Ssl.h"
#include "minifi-c.h"
#include "minifi-cpp/core/PropertyDefinition.h"
@@ -39,12 +40,12 @@ class ProcessContext {
[[nodiscard]] virtual std::expected<std::string, std::error_code>
getProperty(const minifi::core::PropertyReference& prop,
const FlowFile* ff) const = 0;
- [[nodiscard]] virtual std::expected<MinifiControllerService*,
std::error_code> getControllerService(std::string_view name,
- std::string_view type) const = 0;
+ [[nodiscard]] virtual std::expected<MinifiControllerService*,
std::error_code> getControllerService(const minifi::core::PropertyReference&
prop) const = 0;
[[nodiscard]] virtual bool hasNonEmptyProperty(std::string_view name) const
= 0;
[[nodiscard]] virtual std::map<std::string, std::string>
getDynamicProperties(const FlowFile* flow_file) const = 0;
- [[nodiscard]] virtual std::expected<utils::net::SslData, std::error_code>
getSslData(const minifi::core::PropertyReference& prop) const = 0;
+ [[nodiscard]] virtual std::expected<std::optional<utils::net::SslData>,
std::error_code> getSslData(const minifi::core::PropertyReference& prop) const
= 0;
+ [[nodiscard]] virtual std::expected<std::optional<utils::ProxyData>,
std::error_code> getProxyData(const minifi::core::PropertyReference& prop)
const = 0;
};
class CffiProcessContext : public ProcessContext {
@@ -53,12 +54,12 @@ class CffiProcessContext : public ProcessContext {
[[nodiscard]] std::expected<std::string, std::error_code> getProperty(const
minifi::core::PropertyReference& property_reference,
const FlowFile* flow_file) const override;
- [[nodiscard]] std::expected<MinifiControllerService*, std::error_code>
getControllerService(std::string_view name,
- std::string_view type) const override;
+ [[nodiscard]] std::expected<MinifiControllerService*, std::error_code>
getControllerService(const minifi::core::PropertyReference& prop) const
override;
[[nodiscard]] std::map<std::string, std::string> getDynamicProperties(const
FlowFile* flow_file) const override;
[[nodiscard]] bool hasNonEmptyProperty(std::string_view name) const override;
- [[nodiscard]] std::expected<utils::net::SslData, std::error_code>
getSslData(const minifi::core::PropertyReference& prop) const override;
+ [[nodiscard]] std::expected<std::optional<utils::net::SslData>,
std::error_code> getSslData(const minifi::core::PropertyReference& prop) const
override;
+ [[nodiscard]] std::expected<std::optional<utils::ProxyData>,
std::error_code> getProxyData(const minifi::core::PropertyReference& prop)
const override;
private:
[[nodiscard]] std::expected<std::string, std::error_code>
getProperty(std::string_view name, const FlowFile* flow_file) const;
diff --git
a/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h
b/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h
index db44e1cd5..2ec9571ed 100644
---
a/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h
+++
b/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h
@@ -169,12 +169,8 @@ std::optional<T> parseOptionalEnumProperty(const
core::ProcessContext& context,
template<typename ControllerServiceType>
ControllerServiceType* parseOptionalControllerService(const
core::ProcessContext& context, const minifi::core::PropertyReference& prop) {
- const auto controller_service_name = context.getProperty(prop, nullptr);
- if (!controller_service_name || controller_service_name->empty()) {
- return nullptr;
- }
+ auto service = context.getControllerService(prop);
- auto service = context.getControllerService(*controller_service_name,
minifi::core::className<ControllerServiceType>());
if (!service) {
return nullptr;
}
diff --git a/extension-framework/cpp-extension-lib/include/api/utils/Ssl.h
b/extension-framework/cpp-extension-lib/include/api/utils/Proxy.h
similarity index 58%
copy from extension-framework/cpp-extension-lib/include/api/utils/Ssl.h
copy to extension-framework/cpp-extension-lib/include/api/utils/Proxy.h
index b68922477..6add9ef4e 100644
--- a/extension-framework/cpp-extension-lib/include/api/utils/Ssl.h
+++ b/extension-framework/cpp-extension-lib/include/api/utils/Proxy.h
@@ -1,5 +1,5 @@
/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
+* 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
@@ -16,35 +16,27 @@
*/
#pragma once
-#include <string>
-#include <memory>
-#include <optional>
#include <filesystem>
+#include <optional>
+#include <string>
-#include "utils/Enum.h"
-
-namespace org::apache::nifi::minifi::api::utils::net {
+namespace org::apache::nifi::minifi::api::utils {
-enum class ClientAuthOption {
- NONE,
- WANT,
- REQUIRED
+enum class ProxyType {
+ DIRECT,
+ HTTP
};
-struct SslData {
- std::filesystem::path ca_loc;
- std::filesystem::path cert_loc;
- std::filesystem::path key_loc;
- std::string key_pw;
-
- bool isValid() const {
- return !cert_loc.empty() && !key_loc.empty();
- }
+struct BasicAuthCredentials {
+ std::string username;
+ std::string password;
};
-struct SslServerOptions {
- SslData cert_data;
- ClientAuthOption client_auth_option;
+struct ProxyData {
+ ProxyType proxy_type;
+ std::string host;
+ uint16_t port;
+ std::optional<BasicAuthCredentials> proxy_credentials;
};
-} // namespace org::apache::nifi::minifi::api::utils::net
+} // namespace org::apache::nifi::minifi::api::utils
diff --git a/extension-framework/cpp-extension-lib/include/api/utils/Ssl.h
b/extension-framework/cpp-extension-lib/include/api/utils/Ssl.h
index b68922477..c34965abb 100644
--- a/extension-framework/cpp-extension-lib/include/api/utils/Ssl.h
+++ b/extension-framework/cpp-extension-lib/include/api/utils/Ssl.h
@@ -17,12 +17,8 @@
#pragma once
#include <string>
-#include <memory>
-#include <optional>
#include <filesystem>
-#include "utils/Enum.h"
-
namespace org::apache::nifi::minifi::api::utils::net {
enum class ClientAuthOption {
diff --git
a/extension-framework/cpp-extension-lib/mocklib/include/MockProcessContext.h
b/extension-framework/cpp-extension-lib/mocklib/include/MockProcessContext.h
index 76a13c8d8..cddcc9761 100644
--- a/extension-framework/cpp-extension-lib/mocklib/include/MockProcessContext.h
+++ b/extension-framework/cpp-extension-lib/mocklib/include/MockProcessContext.h
@@ -29,12 +29,12 @@ class MockProcessContext : public api::core::ProcessContext
{
[[nodiscard]] std::expected<std::string, std::error_code> getProperty(const
core::PropertyReference& property_reference,
const api::core::FlowFile* flow_file) const override;
- [[nodiscard]] std::expected<MinifiControllerService*, std::error_code>
getControllerService(std::string_view controller_service_name,
- std::string_view controller_service_class) const override;
+ [[nodiscard]] std::expected<MinifiControllerService*, std::error_code>
getControllerService(const minifi::core::PropertyReference& prop) const
override;
[[nodiscard]] std::map<std::string, std::string> getDynamicProperties(const
api::core::FlowFile* flow_file) const override;
[[nodiscard]] bool hasNonEmptyProperty(std::string_view name) const override;
- [[nodiscard]] std::expected<api::utils::net::SslData, std::error_code>
getSslData(const minifi::core::PropertyReference& prop) const override;
+ [[nodiscard]] std::expected<std::optional<api::utils::net::SslData>,
std::error_code> getSslData(const minifi::core::PropertyReference& prop) const
override;
+ [[nodiscard]] std::expected<std::optional<api::utils::ProxyData>,
std::error_code> getProxyData(const minifi::core::PropertyReference& prop)
const override;
std::map<std::string, std::string, std::less<>> properties_;
diff --git
a/extension-framework/cpp-extension-lib/mocklib/src/MockProcessContext.cpp
b/extension-framework/cpp-extension-lib/mocklib/src/MockProcessContext.cpp
index afd5b9b2f..2b571afcf 100644
--- a/extension-framework/cpp-extension-lib/mocklib/src/MockProcessContext.cpp
+++ b/extension-framework/cpp-extension-lib/mocklib/src/MockProcessContext.cpp
@@ -32,7 +32,7 @@ std::expected<std::string, std::error_code>
MockProcessContext::getProperty(cons
return
std::unexpected{make_error_code(core::PropertyErrorCode::PropertyNotSet)};
}
-std::expected<MinifiControllerService*, std::error_code>
MockProcessContext::getControllerService(std::string_view, std::string_view)
const {
+std::expected<MinifiControllerService*, std::error_code>
MockProcessContext::getControllerService(const
minifi::core::PropertyReference&) const {
return nullptr;
}
@@ -44,7 +44,11 @@ bool MockProcessContext::hasNonEmptyProperty(const
std::string_view name) const
return properties_.contains(name);
}
-std::expected<api::utils::net::SslData, std::error_code>
MockProcessContext::getSslData(const minifi::core::PropertyReference&) const {
- return api::utils::net::SslData{};
+std::expected<std::optional<api::utils::net::SslData>, std::error_code>
MockProcessContext::getSslData(const minifi::core::PropertyReference&) const {
+ return std::nullopt;
+}
+
+[[nodiscard]] std::expected<std::optional<api::utils::ProxyData>,
std::error_code> MockProcessContext::getProxyData(const
minifi::core::PropertyReference&) const {
+ return std::nullopt;
}
} // namespace org::apache::nifi::minifi::mock
diff --git
a/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp
b/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp
index a50ca712b..873b6527a 100644
--- a/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp
+++ b/extension-framework/cpp-extension-lib/mocklib/src/mock-minifi-c.cpp
@@ -44,7 +44,7 @@ MinifiBool
MinifiProcessContextHasNonEmptyProperty(MinifiProcessContext*, Minifi
throw std::runtime_error("Not implemented");
}
-MinifiStatus MinifiProcessContextGetControllerService(MinifiProcessContext*,
MinifiStringView, MinifiStringView, MinifiControllerService**) {
+MinifiStatus
MinifiProcessContextGetControllerServiceFromProperty(MinifiProcessContext*,
MinifiStringView, MinifiStringView, MinifiControllerService**) {
throw std::runtime_error("Not implemented");
}
void MinifiProcessContextGetDynamicProperties(MinifiProcessContext*,
MinifiFlowFile*,
@@ -134,4 +134,9 @@ MinifiStatus
MinifiControllerServiceContextGetProperty(MinifiControllerServiceCo
void (*)(void* user_ctx, MinifiStringView property_value), void*) {
throw std::runtime_error("Not implemented");
}
+
+MinifiStatus
MinifiProcessContextGetProxyDataFromProperty(MinifiProcessContext*,
MinifiStringView,
+ void (*)(void* user_ctx, const MinifiProxyData* proxy_data), void*) {
+ throw std::runtime_error("Not implemented");
+}
} // extern "C"
diff --git a/extension-framework/cpp-extension-lib/src/core/ProcessContext.cpp
b/extension-framework/cpp-extension-lib/src/core/ProcessContext.cpp
index 90c333f0d..e2f3a65c2 100644
--- a/extension-framework/cpp-extension-lib/src/core/ProcessContext.cpp
+++ b/extension-framework/cpp-extension-lib/src/core/ProcessContext.cpp
@@ -44,14 +44,17 @@ bool
CffiProcessContext::hasNonEmptyProperty(std::string_view name) const {
return MinifiProcessContextHasNonEmptyProperty(impl_,
utils::minifiStringView(name));
}
-std::expected<MinifiControllerService*, std::error_code>
CffiProcessContext::getControllerService(const std::string_view name,
- const std::string_view type) const {
+std::expected<MinifiControllerService*, std::error_code>
CffiProcessContext::getControllerService(const minifi::core::PropertyReference&
prop) const {
MinifiControllerService* controller_service = nullptr;
- if (const MinifiStatus status =
MinifiProcessContextGetControllerService(impl_,
- utils::minifiStringView(name),
- utils::minifiStringView(type),
+ gsl_Assert(prop.allowed_types.size() == 1);
+ const MinifiStatus status =
MinifiProcessContextGetControllerServiceFromProperty(impl_,
+ utils::minifiStringView(prop.name),
+ utils::minifiStringView(prop.allowed_types[0]),
&controller_service);
- status != MINIFI_STATUS_SUCCESS) {
+ if (status == MINIFI_STATUS_PROPERTY_NOT_SET) {
+ return nullptr;
+ }
+ if (status != MINIFI_STATUS_SUCCESS) {
return std::unexpected{utils::make_error_code(status)};
}
return controller_service;
@@ -69,7 +72,10 @@ std::map<std::string, std::string>
CffiProcessContext::getDynamicProperties(cons
return result;
}
-std::expected<utils::net::SslData, std::error_code>
CffiProcessContext::getSslData(const minifi::core::PropertyReference& prop)
const {
+std::expected<std::optional<utils::net::SslData>, std::error_code>
CffiProcessContext::getSslData(const minifi::core::PropertyReference& prop)
const {
+ const auto controller_name = getProperty(prop, nullptr);
+ if (!controller_name) { return std::nullopt; }
+
auto ssl_data = utils::net::SslData{};
if (const auto status = MinifiProcessContextGetSslDataFromProperty(impl_,
utils::minifiStringView(prop.name), [](void* data, const MinifiSslData*
minifi_ssl_data) {
@@ -86,4 +92,31 @@ std::expected<utils::net::SslData, std::error_code>
CffiProcessContext::getSslDa
return ssl_data;
}
+std::expected<std::optional<utils::ProxyData>, std::error_code>
CffiProcessContext::getProxyData(const minifi::core::PropertyReference& prop)
const {
+ auto proxy_data = utils::ProxyData{};
+ const auto status = MinifiProcessContextGetProxyDataFromProperty(
+ impl_,
+ utils::minifiStringView(prop.name),
+ [](void* data, const MinifiProxyData* minifi_proxy_data) {
+ auto* proxy = static_cast<utils::ProxyData*>(data);
+ proxy->host = utils::toString(minifi_proxy_data->hostname);
+ proxy->port = minifi_proxy_data->port;
+ if (minifi_proxy_data->password && minifi_proxy_data->username) {
+ proxy->proxy_credentials = utils::BasicAuthCredentials{.username =
utils::toString(*minifi_proxy_data->username),
+ .password = utils::toString(*minifi_proxy_data->password)};
+ } else {
+ proxy->proxy_credentials = std::nullopt;
+ }
+ if (minifi_proxy_data->proxy_type == MINIFI_PROXY_TYPE_HTTP) {
+ proxy->proxy_type = utils::ProxyType::HTTP;
+ } else {
+ proxy->proxy_type = utils::ProxyType::DIRECT;
+ }
+ },
+ &proxy_data);
+ if (status == MINIFI_STATUS_PROPERTY_NOT_SET) { return std::nullopt; }
+ if (status == MINIFI_STATUS_SUCCESS) { return proxy_data; }
+ return std::unexpected{utils::make_error_code(status)};
+}
+
} // namespace org::apache::nifi::minifi::api::core
diff --git a/extensions/gcp/CMakeLists.txt b/extensions/gcp/CMakeLists.txt
index 654209d08..2fc42260c 100644
--- a/extensions/gcp/CMakeLists.txt
+++ b/extensions/gcp/CMakeLists.txt
@@ -30,8 +30,8 @@ add_minifi_library(minifi-gcp SHARED ${SOURCES})
if (NOT WIN32)
target_compile_options(minifi-gcp PRIVATE
-Wno-error=deprecated-declarations) # Suppress deprecation warnings for
std::rel_ops usage
endif()
-target_link_libraries(minifi-gcp ${LIBMINIFI} google-cloud-cpp::storage)
-target_include_directories(minifi-gcp SYSTEM PUBLIC
${google-cloud-cpp_INCLUDE_DIRS})
+target_link_libraries(minifi-gcp minifi-cpp-extension-lib
google-cloud-cpp::storage)
-register_extension(minifi-gcp "GCP EXTENSIONS" GCP-EXTENSIONS "This enables
Google Cloud Platform support" "extensions/gcp/tests")
+target_include_directories(minifi-gcp SYSTEM PUBLIC
${google-cloud-cpp_INCLUDE_DIRS})
+register_c_api_extension(minifi-gcp "GCP EXTENSIONS" GCP-EXTENSIONS "This
enables Google Cloud Platform support" "extensions/gcp/tests")
diff --git a/extensions/gcp/ExtensionInitializer.cpp
b/extensions/gcp/ExtensionInitializer.cpp
new file mode 100644
index 000000000..89b00e9ff
--- /dev/null
+++ b/extensions/gcp/ExtensionInitializer.cpp
@@ -0,0 +1,46 @@
+/**
+ * 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.
+ */
+
+#include
"../../extension-framework/cpp-extension-lib/include/api/core/Resource.h"
+#include "api/core/Resource.h"
+#include "api/utils/minifi-c-utils.h"
+#include "processors/DeleteGCSObject.h"
+#include "processors/FetchGCSObject.h"
+#include "processors/ListGCSBucket.h"
+#include "processors/PutGCSObject.h"
+
+#define MKSOC(x) #x
+#define MAKESTRING(x) MKSOC(x) // NOLINT(cppcoreguidelines-macro-usage)
+
+namespace minifi = org::apache::nifi::minifi;
+
+CEXTENSIONAPI const uint32_t MinifiApiVersion = MINIFI_API_VERSION;
+
+CEXTENSIONAPI void MinifiInitExtension(MinifiExtensionContext*
extension_context) {
+ const MinifiExtensionDefinition extension_definition{
+ .name = minifi::api::utils::minifiStringView(MAKESTRING(EXTENSION_NAME)),
+ .version =
minifi::api::utils::minifiStringView(MAKESTRING(EXTENSION_VERSION)),
+ .deinit = nullptr,
+ .user_data = nullptr
+ };
+ auto* extension = MinifiRegisterExtension(extension_context,
&extension_definition);
+
minifi::api::core::registerProcessors<minifi::extensions::gcp::DeleteGCSObject,
+ minifi::extensions::gcp::FetchGCSObject,
+ minifi::extensions::gcp::ListGCSBucket,
+ minifi::extensions::gcp::PutGCSObject>(extension);
+
minifi::api::core::registerControllerServices<minifi::extensions::gcp::GCPCredentialsControllerService>(extension);
+}
diff --git a/extensions/gcp/GCPAttributes.h b/extensions/gcp/GCPAttributes.h
index 5657e7200..0ec973ea6 100644
--- a/extensions/gcp/GCPAttributes.h
+++ b/extensions/gcp/GCPAttributes.h
@@ -19,8 +19,9 @@
#include <string_view>
+#include "api/core/FlowFile.h"
+#include "api/core/ProcessSession.h"
#include "google/cloud/storage/object_metadata.h"
-#include "minifi-cpp/core/FlowFile.h"
namespace org::apache::nifi::minifi::extensions::gcp {
@@ -50,32 +51,32 @@ constexpr std::string_view GCS_SELF_LINK_ATTR =
"gcs.self.link";
constexpr std::string_view GCS_ENCRYPTION_ALGORITHM_ATTR =
"gcs.encryption.algorithm";
constexpr std::string_view GCS_ENCRYPTION_SHA256_ATTR =
"gcs.encryption.sha256";
-inline void setAttributesFromObjectMetadata(core::FlowFile& flow_file, const
::google::cloud::storage::ObjectMetadata& object_metadata) {
- flow_file.setAttribute(GCS_BUCKET_ATTR, object_metadata.bucket());
- flow_file.setAttribute(GCS_OBJECT_NAME_ATTR, object_metadata.name());
- flow_file.setAttribute(GCS_SIZE_ATTR,
std::to_string(object_metadata.size()));
- flow_file.setAttribute(GCS_CRC32C_ATTR, object_metadata.crc32c());
- flow_file.setAttribute(GCS_MD5_ATTR, object_metadata.md5_hash());
- flow_file.setAttribute(GCS_CONTENT_ENCODING_ATTR,
object_metadata.content_encoding());
- flow_file.setAttribute(GCS_CONTENT_LANGUAGE_ATTR,
object_metadata.content_language());
- flow_file.setAttribute(GCS_CONTENT_DISPOSITION_ATTR,
object_metadata.content_disposition());
- flow_file.setAttribute(GCS_CREATE_TIME_ATTR,
std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(object_metadata.time_created().time_since_epoch()).count()));
- flow_file.setAttribute(GCS_UPDATE_TIME_ATTR,
std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(object_metadata.updated().time_since_epoch()).count()));
- flow_file.setAttribute(GCS_DELETE_TIME_ATTR,
std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(object_metadata.time_deleted().time_since_epoch()).count()));
- flow_file.setAttribute(GCS_MEDIA_LINK_ATTR, object_metadata.media_link());
- flow_file.setAttribute(GCS_SELF_LINK_ATTR, object_metadata.self_link());
- flow_file.setAttribute(GCS_ETAG_ATTR, object_metadata.etag());
- flow_file.setAttribute(GCS_GENERATED_ID, object_metadata.id());
- flow_file.setAttribute(GCS_META_GENERATION,
std::to_string(object_metadata.metageneration()));
- flow_file.setAttribute(GCS_GENERATION,
std::to_string(object_metadata.generation()));
- flow_file.setAttribute(GCS_STORAGE_CLASS, object_metadata.storage_class());
+inline void setAttributesFromObjectMetadata(api::core::FlowFile& flow_file,
const ::google::cloud::storage::ObjectMetadata& object_metadata,
api::core::ProcessSession& session) {
+ session.setAttribute(flow_file, GCS_BUCKET_ATTR, object_metadata.bucket());
+ session.setAttribute(flow_file, GCS_OBJECT_NAME_ATTR,
object_metadata.name());
+ session.setAttribute(flow_file, GCS_SIZE_ATTR,
std::to_string(object_metadata.size()));
+ session.setAttribute(flow_file, GCS_CRC32C_ATTR, object_metadata.crc32c());
+ session.setAttribute(flow_file, GCS_MD5_ATTR, object_metadata.md5_hash());
+ session.setAttribute(flow_file, GCS_CONTENT_ENCODING_ATTR,
object_metadata.content_encoding());
+ session.setAttribute(flow_file, GCS_CONTENT_LANGUAGE_ATTR,
object_metadata.content_language());
+ session.setAttribute(flow_file, GCS_CONTENT_DISPOSITION_ATTR,
object_metadata.content_disposition());
+ session.setAttribute(flow_file, GCS_CREATE_TIME_ATTR,
std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(object_metadata.time_created().time_since_epoch()).count()));
+ session.setAttribute(flow_file, GCS_UPDATE_TIME_ATTR,
std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(object_metadata.updated().time_since_epoch()).count()));
+ session.setAttribute(flow_file, GCS_DELETE_TIME_ATTR,
std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(object_metadata.time_deleted().time_since_epoch()).count()));
+ session.setAttribute(flow_file, GCS_MEDIA_LINK_ATTR,
object_metadata.media_link());
+ session.setAttribute(flow_file, GCS_SELF_LINK_ATTR,
object_metadata.self_link());
+ session.setAttribute(flow_file, GCS_ETAG_ATTR, object_metadata.etag());
+ session.setAttribute(flow_file, GCS_GENERATED_ID, object_metadata.id());
+ session.setAttribute(flow_file, GCS_META_GENERATION,
std::to_string(object_metadata.metageneration()));
+ session.setAttribute(flow_file, GCS_GENERATION,
std::to_string(object_metadata.generation()));
+ session.setAttribute(flow_file, GCS_STORAGE_CLASS,
object_metadata.storage_class());
if (object_metadata.has_customer_encryption()) {
- flow_file.setAttribute(GCS_ENCRYPTION_ALGORITHM_ATTR,
object_metadata.customer_encryption().encryption_algorithm);
- flow_file.setAttribute(GCS_ENCRYPTION_SHA256_ATTR,
object_metadata.customer_encryption().key_sha256);
+ session.setAttribute(flow_file, GCS_ENCRYPTION_ALGORITHM_ATTR,
object_metadata.customer_encryption().encryption_algorithm);
+ session.setAttribute(flow_file, GCS_ENCRYPTION_SHA256_ATTR,
object_metadata.customer_encryption().key_sha256);
}
if (object_metadata.has_owner()) {
- flow_file.setAttribute(GCS_OWNER_ENTITY_ATTR,
object_metadata.owner().entity);
- flow_file.setAttribute(GCS_OWNER_ENTITY_ID_ATTR,
object_metadata.owner().entity_id);
+ session.setAttribute(flow_file, GCS_OWNER_ENTITY_ATTR,
object_metadata.owner().entity);
+ session.setAttribute(flow_file, GCS_OWNER_ENTITY_ID_ATTR,
object_metadata.owner().entity_id);
}
}
diff --git
a/extensions/gcp/controllerservices/GCPCredentialsControllerService.cpp
b/extensions/gcp/controllerservices/GCPCredentialsControllerService.cpp
index 9e93c2942..d84bbeb4b 100644
--- a/extensions/gcp/controllerservices/GCPCredentialsControllerService.cpp
+++ b/extensions/gcp/controllerservices/GCPCredentialsControllerService.cpp
@@ -18,34 +18,36 @@
#include "GCPCredentialsControllerService.h"
-#include "core/Resource.h"
#include "google/cloud/storage/client.h"
-#include "utils/ProcessorConfigUtils.h"
-#include "utils/file/FileUtils.h"
namespace org::apache::nifi::minifi::extensions::gcp {
-void GCPCredentialsControllerService::initialize() {
- setSupportedProperties(Properties);
+namespace {
+// TODO(MINIFICPP-2763) use utils::file::get_content instead
+std::string get_content(const std::filesystem::path& file_name) {
+ std::ifstream file(file_name, std::ifstream::binary);
+ std::string content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
+ return content;
+}
}
-std::shared_ptr<google::cloud::Credentials>
GCPCredentialsControllerService::createCredentialsFromJsonPath() const {
- const auto json_path = getProperty(JsonFilePath.name);
+std::shared_ptr<google::cloud::Credentials>
GCPCredentialsControllerService::createCredentialsFromJsonPath(api::core::ControllerServiceContext&
ctx) const {
+ const auto json_path = ctx.getProperty(JsonFilePath.name);
if (!json_path) {
logger_->log_error("Missing or invalid {}", JsonFilePath.name);
return nullptr;
}
- if (!utils::file::exists(*json_path)) {
+ if (std::error_code ec; !std::filesystem::exists(*json_path, ec) || ec) {
logger_->log_error("JSON file for GCP credentials '{}' does not exist",
*json_path);
return nullptr;
}
- return
google::cloud::MakeServiceAccountCredentials(utils::file::get_content(*json_path));
+ return google::cloud::MakeServiceAccountCredentials(get_content(*json_path));
}
-std::shared_ptr<google::cloud::Credentials>
GCPCredentialsControllerService::createCredentialsFromJsonContents() const {
- auto json_contents = getProperty(JsonContents.name);
+std::shared_ptr<google::cloud::Credentials>
GCPCredentialsControllerService::createCredentialsFromJsonContents(api::core::ControllerServiceContext&
ctx) const {
+ auto json_contents = ctx.getProperty(JsonContents.name);
if (!json_contents) {
logger_->log_error("Missing or invalid {}", JsonContents.name);
return nullptr;
@@ -54,9 +56,9 @@ std::shared_ptr<google::cloud::Credentials>
GCPCredentialsControllerService::cre
return google::cloud::MakeServiceAccountCredentials(*json_contents);
}
-void GCPCredentialsControllerService::onEnable() {
+MinifiStatus
GCPCredentialsControllerService::enableImpl(api::core::ControllerServiceContext&
ctx) {
std::optional<CredentialsLocation> credentials_location;
- if (const auto value = getProperty(CredentialsLoc.name)) {
+ if (const auto value = ctx.getProperty(CredentialsLoc.name)) {
credentials_location = magic_enum::enum_cast<CredentialsLocation>(*value);
}
if (!credentials_location) {
@@ -68,15 +70,15 @@ void GCPCredentialsControllerService::onEnable() {
} else if (*credentials_location ==
CredentialsLocation::USE_COMPUTE_ENGINE_CREDENTIALS) {
credentials_ = google::cloud::MakeComputeEngineCredentials();
} else if (*credentials_location == CredentialsLocation::USE_JSON_FILE) {
- credentials_ = createCredentialsFromJsonPath();
+ credentials_ = createCredentialsFromJsonPath(ctx);
} else if (*credentials_location == CredentialsLocation::USE_JSON_CONTENTS) {
- credentials_ = createCredentialsFromJsonContents();
+ credentials_ = createCredentialsFromJsonContents(ctx);
} else if (*credentials_location ==
CredentialsLocation::USE_ANONYMOUS_CREDENTIALS) {
credentials_ = google::cloud::MakeInsecureCredentials();
}
if (!credentials_)
logger_->log_error("Couldn't create valid credentials");
+ return MINIFI_STATUS_SUCCESS;
}
-REGISTER_RESOURCE(GCPCredentialsControllerService, ControllerService);
} // namespace org::apache::nifi::minifi::extensions::gcp
diff --git
a/extensions/gcp/controllerservices/GCPCredentialsControllerService.h
b/extensions/gcp/controllerservices/GCPCredentialsControllerService.h
index 0eb8fbf8a..b53971ae2 100644
--- a/extensions/gcp/controllerservices/GCPCredentialsControllerService.h
+++ b/extensions/gcp/controllerservices/GCPCredentialsControllerService.h
@@ -18,17 +18,15 @@
#pragma once
#include <filesystem>
-#include <string>
#include <memory>
+#include <string>
-#include "core/controller/ControllerServiceBase.h"
-#include "minifi-cpp/core/logging/Logger.h"
-#include "core/logging/LoggerFactory.h"
-#include "minifi-cpp/core/PropertyDefinition.h"
+#include "api/core/ControllerServiceImpl.h"
+#include "api/utils/Export.h"
#include "core/PropertyDefinitionBuilder.h"
-#include "utils/Enum.h"
-
#include "google/cloud/credentials.h"
+#include "minifi-cpp/core/PropertyDefinition.h"
+#include "utils/Enum.h"
namespace org::apache::nifi::minifi::extensions::gcp {
enum class CredentialsLocation {
@@ -63,7 +61,7 @@ constexpr customize_t
enum_name<CredentialsLocation>(CredentialsLocation value)
namespace org::apache::nifi::minifi::extensions::gcp {
-class GCPCredentialsControllerService : public
core::controller::ControllerServiceBase, public
core::controller::ControllerServiceHandle {
+class GCPCredentialsControllerService : public
api::core::ControllerServiceImpl {
public:
EXTENSIONAPI static constexpr const char* Description = "Manages the
credentials for Google Cloud Platform. This allows for multiple Google Cloud
Platform related processors "
"to reference this single controller service so that Google Cloud
Platform credentials can be managed and controlled in a central location.";
@@ -91,21 +89,16 @@ class GCPCredentialsControllerService : public
core::controller::ControllerServi
EXTENSIONAPI static constexpr bool SupportsDynamicProperties = false;
- ADD_COMMON_VIRTUAL_FUNCTIONS_FOR_CONTROLLER_SERVICES
-
- using ControllerServiceBase::ControllerServiceBase;
-
- void initialize() override;
- void onEnable() override;
+ using ControllerServiceImpl::ControllerServiceImpl;
- [[nodiscard]] ControllerServiceHandle* getControllerServiceHandle() override
{return this;}
+ MinifiStatus enableImpl(api::core::ControllerServiceContext& ctx) override;
[[nodiscard]] const auto& getCredentials() const { return credentials_; }
protected:
- [[nodiscard]] std::shared_ptr<google::cloud::Credentials>
createCredentialsFromJsonPath() const;
- [[nodiscard]] std::shared_ptr<google::cloud::Credentials>
createCredentialsFromJsonContents() const;
+ [[nodiscard]] std::shared_ptr<google::cloud::Credentials>
createCredentialsFromJsonPath(api::core::ControllerServiceContext& ctx) const;
+ [[nodiscard]] std::shared_ptr<google::cloud::Credentials>
createCredentialsFromJsonContents(api::core::ControllerServiceContext& ctx)
const;
std::shared_ptr<google::cloud::Credentials> credentials_;
diff --git a/extensions/gcp/processors/DeleteGCSObject.cpp
b/extensions/gcp/processors/DeleteGCSObject.cpp
index 4ad4b4327..35206f17e 100644
--- a/extensions/gcp/processors/DeleteGCSObject.cpp
+++ b/extensions/gcp/processors/DeleteGCSObject.cpp
@@ -17,69 +17,61 @@
#include "DeleteGCSObject.h"
-#include "utils/ProcessorConfigUtils.h"
-
#include "../GCPAttributes.h"
-#include "minifi-cpp/core/FlowFile.h"
-#include "minifi-cpp/core/ProcessContext.h"
-#include "core/ProcessSession.h"
-#include "core/Resource.h"
+#include "api/core/ProcessContext.h"
+#include "api/core/ProcessSession.h"
+#include "api/core/Resource.h"
+#include "api/utils/ProcessorConfigUtils.h"
namespace gcs = ::google::cloud::storage;
namespace org::apache::nifi::minifi::extensions::gcp {
-void DeleteGCSObject::initialize() {
- setSupportedProperties(Properties);
- setSupportedRelationships(Relationships);
-}
-void DeleteGCSObject::onTrigger(core::ProcessContext& context,
core::ProcessSession& session) {
+MinifiStatus DeleteGCSObject::onTriggerImpl(api::core::ProcessContext&
context, api::core::ProcessSession& session) {
gsl_Expects(gcp_credentials_);
auto flow_file = session.get();
if (!flow_file) {
- context.yield();
- return;
+ return MINIFI_STATUS_PROCESSOR_YIELD;
}
- auto bucket = context.getProperty(Bucket, flow_file.get());
+ auto bucket = api::utils::parseOptionalProperty(context, Bucket, &flow_file);
if (!bucket || bucket->empty()) {
logger_->log_error("Missing bucket name");
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
- auto object_name = context.getProperty(Key, flow_file.get());
+ auto object_name = api::utils::parseOptionalProperty(context, Key,
&flow_file);
if (!object_name || object_name->empty()) {
logger_->log_error("Missing object name");
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
gcs::Generation generation;
- if (const auto object_generation_str =
context.getProperty(ObjectGeneration, flow_file.get()); object_generation_str
&& !object_generation_str->empty()) {
+ if (auto object_generation_str = api::utils::parseOptionalProperty(context,
ObjectGeneration, &flow_file); object_generation_str &&
!object_generation_str->empty()) {
if (const auto geni64 =
parsing::parseIntegral<int64_t>(*object_generation_str)) {
generation = gcs::Generation{*geni64};
} else {
logger_->log_error("Invalid generation: {}", *object_generation_str);
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
}
auto status = getClient().DeleteObject(*bucket, *object_name, generation,
gcs::IfGenerationNotMatch(0));
if (!status.ok()) {
- flow_file->setAttribute(GCS_STATUS_MESSAGE, status.message());
- flow_file->setAttribute(GCS_ERROR_REASON, status.error_info().reason());
- flow_file->setAttribute(GCS_ERROR_DOMAIN, status.error_info().domain());
+ session.setAttribute(flow_file, GCS_STATUS_MESSAGE, status.message());
+ session.setAttribute(flow_file, GCS_ERROR_REASON,
status.error_info().reason());
+ session.setAttribute(flow_file, GCS_ERROR_DOMAIN,
status.error_info().domain());
logger_->log_error("Failed to delete {} object from {} bucket on Google
Cloud Storage {} {}", *object_name, *bucket, status.message(),
status.error_info().reason());
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
- session.transfer(flow_file, Success);
+ session.transfer(std::move(flow_file), Success);
+ return MINIFI_STATUS_SUCCESS;
}
-REGISTER_RESOURCE(DeleteGCSObject, Processor);
-
} // namespace org::apache::nifi::minifi::extensions::gcp
diff --git a/extensions/gcp/processors/DeleteGCSObject.h
b/extensions/gcp/processors/DeleteGCSObject.h
index a5d022847..48364cd45 100644
--- a/extensions/gcp/processors/DeleteGCSObject.h
+++ b/extensions/gcp/processors/DeleteGCSObject.h
@@ -17,24 +17,20 @@
#pragma once
-#include <memory>
-#include <string>
-#include <utility>
-
#include "../GCPAttributes.h"
#include "GCSProcessor.h"
-#include "core/logging/LoggerFactory.h"
#include "minifi-cpp/core/OutputAttributeDefinition.h"
#include "minifi-cpp/core/PropertyDefinition.h"
#include "core/PropertyDefinitionBuilder.h"
#include "utils/ArrayUtils.h"
+#include "minifi-cpp/core/Annotation.h"
+
namespace org::apache::nifi::minifi::extensions::gcp {
class DeleteGCSObject : public GCSProcessor {
public:
using GCSProcessor::GCSProcessor;
- ~DeleteGCSObject() override = default;
EXTENSIONAPI static constexpr const char* Description = "Deletes an object
from a Google Cloud Bucket.";
@@ -79,10 +75,8 @@ class DeleteGCSObject : public GCSProcessor {
EXTENSIONAPI static constexpr core::annotation::Input InputRequirement =
core::annotation::Input::INPUT_REQUIRED;
EXTENSIONAPI static constexpr bool IsSingleThreaded = false;
- ADD_COMMON_VIRTUAL_FUNCTIONS_FOR_PROCESSORS
-
- void initialize() override;
- void onTrigger(core::ProcessContext& context, core::ProcessSession& session)
override;
+ protected:
+ MinifiStatus onTriggerImpl(api::core::ProcessContext& context,
api::core::ProcessSession& session) override;
};
} // namespace org::apache::nifi::minifi::extensions::gcp
diff --git a/extensions/gcp/processors/FetchGCSObject.cpp
b/extensions/gcp/processors/FetchGCSObject.cpp
index e43b80415..93f500806 100644
--- a/extensions/gcp/processors/FetchGCSObject.cpp
+++ b/extensions/gcp/processors/FetchGCSObject.cpp
@@ -19,11 +19,9 @@
#include <utility>
-#include "core/Resource.h"
-#include "minifi-cpp/core/FlowFile.h"
-#include "minifi-cpp/core/ProcessContext.h"
-#include "core/ProcessSession.h"
#include "../GCPAttributes.h"
+#include "api/utils/ProcessorConfigUtils.h"
+#include "minifi-cpp/io/OutputStream.h"
namespace gcs = ::google::cloud::storage;
@@ -82,80 +80,78 @@ class FetchFromGCSCallback {
};
} // namespace
-
-void FetchGCSObject::initialize() {
- setSupportedProperties(Properties);
- setSupportedRelationships(Relationships);
-}
-
-void FetchGCSObject::onSchedule(core::ProcessContext& context,
core::ProcessSessionFactory& session_factory) {
- GCSProcessor::onSchedule(context, session_factory);
- if (auto encryption_key = context.getProperty(EncryptionKey)) {
+MinifiStatus FetchGCSObject::onScheduleImpl(api::core::ProcessContext&
context) {
+ const auto status = GCSProcessor::onScheduleImpl(context);
+ if (MINIFI_STATUS_SUCCESS != status) { return status; }
+ if (auto encryption_key = context.getProperty(EncryptionKey, nullptr)) {
try {
encryption_key_ = gcs::EncryptionKey::FromBase64Key(*encryption_key);
} catch (const google::cloud::RuntimeStatusError&) {
- throw minifi::Exception(ExceptionType::PROCESS_SCHEDULE_EXCEPTION,
"Could not decode the base64-encoded encryption key from property " +
std::string(EncryptionKey.name)); }
+ logger_->log_error("Could not decode the base64-encoded encryption key
from property {}", std::string(EncryptionKey.name));
+ return MINIFI_STATUS_UNKNOWN_ERROR;
+ }
}
+ return MINIFI_STATUS_SUCCESS;
}
-void FetchGCSObject::onTrigger(core::ProcessContext& context,
core::ProcessSession& session) {
+MinifiStatus FetchGCSObject::onTriggerImpl(api::core::ProcessContext& context,
api::core::ProcessSession& session) {
gsl_Expects(gcp_credentials_);
auto flow_file = session.get();
if (!flow_file) {
- context.yield();
- return;
+ return MINIFI_STATUS_PROCESSOR_YIELD;
}
- auto bucket = context.getProperty(Bucket, flow_file.get());
+ auto bucket = api::utils::parseOptionalProperty(context, Bucket, &flow_file);
if (!bucket || bucket->empty()) {
logger_->log_error("Missing bucket name");
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
- auto object_name = context.getProperty(Key, flow_file.get());
+ auto object_name = api::utils::parseOptionalProperty(context, Key,
&flow_file);
if (!object_name || object_name->empty()) {
logger_->log_error("Missing object name");
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
gcs::Client client = getClient();
FetchFromGCSCallback callback(client, *bucket, *object_name);
callback.setEncryptionKey(encryption_key_);
- if (const auto object_generation_str =
context.getProperty(ObjectGeneration, flow_file.get()); object_generation_str
&& !object_generation_str->empty()) {
+ if (const auto object_generation_str =
api::utils::parseOptionalProperty(context, ObjectGeneration, &flow_file);
object_generation_str && !object_generation_str->empty()) {
if (const auto geni64 =
parsing::parseIntegral<int64_t>(*object_generation_str)) {
gcs::Generation generation = gcs::Generation{*geni64};
callback.setGeneration(generation);
} else {
logger_->log_error("Invalid generation: {}", *object_generation_str);
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
}
-
session.write(flow_file, std::ref(callback));
if (!callback.getStatus().ok()) {
- flow_file->setAttribute(GCS_STATUS_MESSAGE,
callback.getStatus().message());
- flow_file->setAttribute(GCS_ERROR_REASON,
callback.getStatus().error_info().reason());
- flow_file->setAttribute(GCS_ERROR_DOMAIN,
callback.getStatus().error_info().domain());
+ session.setAttribute(flow_file, GCS_STATUS_MESSAGE,
callback.getStatus().message());
+ session.setAttribute(flow_file, GCS_ERROR_REASON,
callback.getStatus().error_info().reason());
+ session.setAttribute(flow_file, GCS_ERROR_DOMAIN,
callback.getStatus().error_info().domain());
logger_->log_error("Failed to fetch from Google Cloud Storage {} {}",
callback.getStatus().message(), callback.getStatus().error_info().reason());
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
- if (auto generation = callback.getGeneration())
- flow_file->setAttribute(GCS_GENERATION, std::to_string(*generation));
- if (auto meta_generation = callback.getMetaGeneration())
- flow_file->setAttribute(GCS_META_GENERATION,
std::to_string(*meta_generation));
- if (auto storage_class = callback.getStorageClass())
- flow_file->setAttribute(GCS_STORAGE_CLASS, *storage_class);
- session.transfer(flow_file, Success);
+ if (auto generation = callback.getGeneration()) {
+ session.setAttribute(flow_file, GCS_GENERATION,
std::to_string(*generation));
+ }
+ if (auto meta_generation = callback.getMetaGeneration()) {
+ session.setAttribute(flow_file, GCS_META_GENERATION,
std::to_string(*meta_generation));
+ }
+ if (auto storage_class = callback.getStorageClass()) {
+ session.setAttribute(flow_file, GCS_STORAGE_CLASS, *storage_class);
+ }
+ session.transfer(std::move(flow_file), Success);
+ return MINIFI_STATUS_SUCCESS;
}
-REGISTER_RESOURCE(FetchGCSObject, Processor);
-
} // namespace org::apache::nifi::minifi::extensions::gcp
diff --git a/extensions/gcp/processors/FetchGCSObject.h
b/extensions/gcp/processors/FetchGCSObject.h
index 694ad1f5e..51d72dab9 100644
--- a/extensions/gcp/processors/FetchGCSObject.h
+++ b/extensions/gcp/processors/FetchGCSObject.h
@@ -17,24 +17,20 @@
#pragma once
-#include <memory>
-#include <string>
-#include <utility>
-
#include "../GCPAttributes.h"
#include "GCSProcessor.h"
#include "minifi-cpp/core/PropertyDefinition.h"
#include "minifi-cpp/core/RelationshipDefinition.h"
#include "google/cloud/storage/well_known_headers.h"
-#include "core/logging/LoggerFactory.h"
#include "utils/ArrayUtils.h"
+#include "minifi-cpp/core/Annotation.h"
+
namespace org::apache::nifi::minifi::extensions::gcp {
class FetchGCSObject : public GCSProcessor {
public:
using GCSProcessor::GCSProcessor;
- ~FetchGCSObject() override = default;
EXTENSIONAPI static constexpr const char* Description = "Fetches a file from
a Google Cloud Bucket. Designed to be used in tandem with ListGCSBucket.";
@@ -80,11 +76,9 @@ class FetchGCSObject : public GCSProcessor {
EXTENSIONAPI static constexpr core::annotation::Input InputRequirement =
core::annotation::Input::INPUT_REQUIRED;
EXTENSIONAPI static constexpr bool IsSingleThreaded = false;
- ADD_COMMON_VIRTUAL_FUNCTIONS_FOR_PROCESSORS
-
- void initialize() override;
- void onSchedule(core::ProcessContext& context, core::ProcessSessionFactory&
session_factory) override;
- void onTrigger(core::ProcessContext& context, core::ProcessSession& session)
override;
+ protected:
+ MinifiStatus onScheduleImpl(api::core::ProcessContext& context) override;
+ MinifiStatus onTriggerImpl(api::core::ProcessContext& context,
api::core::ProcessSession& session) override;
private:
google::cloud::storage::EncryptionKey encryption_key_;
diff --git a/extensions/gcp/processors/GCSProcessor.cpp
b/extensions/gcp/processors/GCSProcessor.cpp
index 274b3f93c..bf9342af8 100644
--- a/extensions/gcp/processors/GCSProcessor.cpp
+++ b/extensions/gcp/processors/GCSProcessor.cpp
@@ -17,45 +17,42 @@
#include "GCSProcessor.h"
-#include "utils/ProcessorConfigUtils.h"
-
#include "../controllerservices/GCPCredentialsControllerService.h"
-#include "minifi-cpp/core/ProcessContext.h"
-#include "core/ProcessSession.h"
+#include "api/utils/ProcessorConfigUtils.h"
namespace gcs = ::google::cloud::storage;
namespace org::apache::nifi::minifi::extensions::gcp {
-std::shared_ptr<google::cloud::Credentials>
GCSProcessor::getCredentials(core::ProcessContext& context) const {
- auto gcp_credentials_controller_service =
utils::parseOptionalControllerService<GCPCredentialsControllerService>(context,
GCSProcessor::GCPCredentials, getUUID());
- if (gcp_credentials_controller_service) {
+std::shared_ptr<google::cloud::Credentials> GCSProcessor::getCredentials(const
api::core::ProcessContext& context) {
+ if (const auto gcp_credentials_controller_service =
api::utils::parseOptionalControllerService<GCPCredentialsControllerService>(context,
GCPCredentials)) {
return gcp_credentials_controller_service->getCredentials();
}
return nullptr;
}
-void GCSProcessor::onSchedule(core::ProcessContext& context,
core::ProcessSessionFactory&) {
- if (auto number_of_retries = utils::parseOptionalU64Property(context,
NumberOfRetries)) {
+MinifiStatus GCSProcessor::onScheduleImpl(api::core::ProcessContext& context) {
+ if (const auto number_of_retries =
api::utils::parseOptionalU64Property(context, NumberOfRetries)) {
retry_policy_ =
std::make_shared<google::cloud::storage::LimitedErrorCountRetryPolicy>(gsl::narrow<int>(*number_of_retries));
}
gcp_credentials_ = getCredentials(context);
if (!gcp_credentials_) {
- throw minifi::Exception(ExceptionType::PROCESS_SCHEDULE_EXCEPTION,
"Missing GCP Credentials");
+ logger_->log_error("Couldnt find valid credentials");
+ return MINIFI_STATUS_UNKNOWN_ERROR;
}
- endpoint_url_ = context.getProperty(EndpointOverrideURL) |
utils::toOptional();
+ endpoint_url_ = context.getProperty(EndpointOverrideURL, nullptr) |
utils::toOptional();
if (endpoint_url_)
logger_->log_debug("Endpoint overwritten: {}", *endpoint_url_);
- auto proxy_controller_service =
minifi::utils::parseOptionalControllerService<minifi::controllers::ProxyConfigurationServiceInterface>(context,
ProxyConfigurationService, getUUID());
- if (proxy_controller_service && proxy_controller_service->getProxyType() !=
minifi::controllers::ProxyType::DIRECT) {
+ const auto proxy_data = context.getProxyData(ProxyConfigurationService) |
utils::orThrow("Couldnt query ProxyConfigurationService");
+ if (proxy_data && proxy_data->proxy_type != api::utils::ProxyType::DIRECT) {
logger_->log_debug("Proxy configuration is set for GCS processor");
proxy_ = google::cloud::ProxyConfig{};
-
proxy_->set_scheme(minifi::utils::string::startsWith(proxy_controller_service->getHost(),
"https") ? "https" : "http");
- auto proxy_host = proxy_controller_service->getHost();
+ proxy_->set_scheme(minifi::utils::string::startsWith(proxy_data->host,
"https") ? "https" : "http");
+ auto proxy_host = proxy_data->host;
constexpr std::string_view https_prefix = "https://";
constexpr std::string_view http_prefix = "http://";
if (minifi::utils::string::startsWith(proxy_host, https_prefix)) {
@@ -64,12 +61,13 @@ void GCSProcessor::onSchedule(core::ProcessContext&
context, core::ProcessSessio
proxy_host = proxy_host.substr(http_prefix.size());
}
proxy_->set_hostname(proxy_host);
- proxy_->set_port(std::to_string(proxy_controller_service->getPort()));
- if (auto proxy_credentials =
proxy_controller_service->getProxyCredentials()) {
+ proxy_->set_port(std::to_string(proxy_data->port));
+ if (auto proxy_credentials = proxy_data->proxy_credentials) {
proxy_->set_username(proxy_credentials->username);
proxy_->set_password(proxy_credentials->password);
}
}
+ return MINIFI_STATUS_SUCCESS;
}
gcs::Client GCSProcessor::getClient() const {
diff --git a/extensions/gcp/processors/GCSProcessor.h
b/extensions/gcp/processors/GCSProcessor.h
index af6a92ace..a05dde421 100644
--- a/extensions/gcp/processors/GCSProcessor.h
+++ b/extensions/gcp/processors/GCSProcessor.h
@@ -16,24 +16,21 @@
*/
#pragma once
-#include <string>
#include <memory>
-#include <utility>
#include <optional>
+#include <string>
#include "../controllerservices/GCPCredentialsControllerService.h"
-#include "minifi-cpp/core/logging/Logger.h"
-#include "core/ProcessorImpl.h"
-#include "minifi-cpp/core/PropertyDefinition.h"
+#include "api/core/ProcessorImpl.h"
#include "core/PropertyDefinitionBuilder.h"
-#include "minifi-cpp/core/PropertyValidator.h"
#include "google/cloud/credentials.h"
#include "google/cloud/storage/client.h"
#include "google/cloud/storage/retry_policy.h"
-#include "minifi-cpp/controllers/ProxyConfigurationServiceInterface.h"
+#include "minifi-cpp/core/PropertyDefinition.h"
+#include "minifi-cpp/core/PropertyValidator.h"
namespace org::apache::nifi::minifi::extensions::gcp {
-class GCSProcessor : public core::ProcessorImpl {
+class GCSProcessor : public api::core::ProcessorImpl {
public:
using ProcessorImpl::ProcessorImpl;
@@ -56,7 +53,7 @@ class GCSProcessor : public core::ProcessorImpl {
.build();
EXTENSIONAPI static constexpr auto ProxyConfigurationService =
core::PropertyDefinitionBuilder<>::createProperty("Proxy Configuration Service")
.withDescription("Specifies the Proxy Configuration Controller Service
to proxy network requests.")
-
.withAllowedTypes<minifi::controllers::ProxyConfigurationServiceInterface>()
+ .withAllowedType<MINIFI_PROXY_CONFIGURATION_SERVICE_PROPERTY_TYPE>()
.build();
EXTENSIONAPI static constexpr auto Properties =
std::to_array<core::PropertyReference>({
GCPCredentials,
@@ -65,12 +62,11 @@ class GCSProcessor : public core::ProcessorImpl {
ProxyConfigurationService
});
-
- void onSchedule(core::ProcessContext& context, core::ProcessSessionFactory&
session_factory) override;
-
protected:
+ MinifiStatus onScheduleImpl(api::core::ProcessContext& context) override;
+
virtual google::cloud::storage::Client getClient() const;
- std::shared_ptr<google::cloud::Credentials>
getCredentials(core::ProcessContext& context) const;
+ static std::shared_ptr<google::cloud::Credentials> getCredentials(const
api::core::ProcessContext& context);
std::optional<std::string> endpoint_url_;
std::shared_ptr<google::cloud::Credentials> gcp_credentials_;
diff --git a/extensions/gcp/processors/ListGCSBucket.cpp
b/extensions/gcp/processors/ListGCSBucket.cpp
index 13426e441..ac4cadd40 100644
--- a/extensions/gcp/processors/ListGCSBucket.cpp
+++ b/extensions/gcp/processors/ListGCSBucket.cpp
@@ -17,47 +17,44 @@
#include "ListGCSBucket.h"
-#include "utils/ProcessorConfigUtils.h"
-
#include "../GCPAttributes.h"
-#include "minifi-cpp/core/FlowFile.h"
-#include "minifi-cpp/core/ProcessContext.h"
-#include "core/ProcessSession.h"
-#include "core/Resource.h"
+#include "api/core/ProcessContext.h"
+#include "api/core/ProcessSession.h"
+#include "api/core/Resource.h"
+#include "api/utils/ProcessorConfigUtils.h"
+#include "minifi-cpp/core/SpecialFlowAttribute.h"
namespace gcs = ::google::cloud::storage;
namespace org::apache::nifi::minifi::extensions::gcp {
-void ListGCSBucket::initialize() {
- setSupportedProperties(Properties);
- setSupportedRelationships(Relationships);
-}
-
-void ListGCSBucket::onSchedule(core::ProcessContext& context,
core::ProcessSessionFactory& session_factory) {
- GCSProcessor::onSchedule(context, session_factory);
- bucket_ = utils::parseProperty(context, Bucket);
+MinifiStatus ListGCSBucket::onScheduleImpl(api::core::ProcessContext& context)
{
+ const auto status = GCSProcessor::onScheduleImpl(context);
+ if (status != MinifiStatus::MINIFI_STATUS_SUCCESS) {
+ return status;
+ }
+ bucket_ = api::utils::parseProperty(context, Bucket);
+ return MinifiStatus::MINIFI_STATUS_SUCCESS;
}
-void ListGCSBucket::onTrigger(core::ProcessContext& context,
core::ProcessSession& session) {
+MinifiStatus ListGCSBucket::onTriggerImpl(api::core::ProcessContext& context,
api::core::ProcessSession& session) {
gsl_Expects(gcp_credentials_);
gcs::Client client = getClient();
- auto list_all_versions = utils::parseOptionalBoolProperty(context,
ListAllVersions);
+ auto list_all_versions = api::utils::parseOptionalBoolProperty(context,
ListAllVersions);
gcs::Versions versions = (list_all_versions && *list_all_versions) ?
gcs::Versions(true) : gcs::Versions(false);
auto objects_in_bucket = client.ListObjects(bucket_, versions);
for (const auto& object_in_bucket : objects_in_bucket) {
if (object_in_bucket.ok()) {
auto flow_file = session.create();
- flow_file->updateAttribute(core::SpecialFlowAttribute::FILENAME,
object_in_bucket->name());
- setAttributesFromObjectMetadata(*flow_file, *object_in_bucket);
- session.transfer(flow_file, Success);
+ session.setAttribute(flow_file, core::SpecialFlowAttribute::FILENAME,
object_in_bucket->name());
+ setAttributesFromObjectMetadata(flow_file, *object_in_bucket, session);
+ session.transfer(std::move(flow_file), Success);
} else {
logger_->log_error("Invalid object in bucket {}", bucket_);
}
}
+ return MinifiStatus::MINIFI_STATUS_SUCCESS;
}
-REGISTER_RESOURCE(ListGCSBucket, Processor);
-
} // namespace org::apache::nifi::minifi::extensions::gcp
diff --git a/extensions/gcp/processors/ListGCSBucket.h
b/extensions/gcp/processors/ListGCSBucket.h
index 36c4ac1e0..e654a314d 100644
--- a/extensions/gcp/processors/ListGCSBucket.h
+++ b/extensions/gcp/processors/ListGCSBucket.h
@@ -17,19 +17,17 @@
#pragma once
-#include <memory>
#include <string>
-#include <utility>
#include "../GCPAttributes.h"
#include "GCSProcessor.h"
-#include "core/logging/LoggerFactory.h"
#include "minifi-cpp/core/OutputAttributeDefinition.h"
#include "minifi-cpp/core/PropertyDefinition.h"
#include "core/PropertyDefinitionBuilder.h"
#include "minifi-cpp/core/PropertyValidator.h"
#include "minifi-cpp/core/RelationshipDefinition.h"
#include "utils/ArrayUtils.h"
+#include "minifi-cpp/core/Annotation.h"
namespace org::apache::nifi::minifi::extensions::gcp {
@@ -44,7 +42,6 @@ inline constexpr auto FILENAME_OUTPUT_ATTRIBUTE_DESCRIPTION =
utils::array_to_st
class ListGCSBucket : public GCSProcessor {
public:
using GCSProcessor::GCSProcessor;
- ~ListGCSBucket() override = default;
EXTENSIONAPI static constexpr const char* Description = "Retrieves a listing
of objects from an GCS bucket. "
"For each object that is listed, creates a FlowFile that represents the
object so that it can be fetched in conjunction with FetchGCSObject.";
@@ -120,11 +117,9 @@ class ListGCSBucket : public GCSProcessor {
EXTENSIONAPI static constexpr core::annotation::Input InputRequirement =
core::annotation::Input::INPUT_FORBIDDEN;
EXTENSIONAPI static constexpr bool IsSingleThreaded = true;
- ADD_COMMON_VIRTUAL_FUNCTIONS_FOR_PROCESSORS
-
- void initialize() override;
- void onSchedule(core::ProcessContext& context, core::ProcessSessionFactory&
session_factory) override;
- void onTrigger(core::ProcessContext& context, core::ProcessSession& session)
override;
+ protected:
+ MinifiStatus onScheduleImpl(api::core::ProcessContext& context) override;
+ MinifiStatus onTriggerImpl(api::core::ProcessContext& context,
api::core::ProcessSession& session) override;
private:
std::string bucket_;
diff --git a/extensions/gcp/processors/PutGCSObject.cpp
b/extensions/gcp/processors/PutGCSObject.cpp
index a05380f32..97178eb9a 100644
--- a/extensions/gcp/processors/PutGCSObject.cpp
+++ b/extensions/gcp/processors/PutGCSObject.cpp
@@ -19,12 +19,12 @@
#include <utility>
-#include "core/Resource.h"
-#include "minifi-cpp/core/FlowFile.h"
-#include "minifi-cpp/core/ProcessContext.h"
-#include "core/ProcessSession.h"
#include "../GCPAttributes.h"
-#include "utils/ProcessorConfigUtils.h"
+#include "api/core/ProcessContext.h"
+#include "api/core/ProcessSession.h"
+#include "api/core/Resource.h"
+#include "api/utils/ProcessorConfigUtils.h"
+#include "minifi-cpp/io/InputStream.h"
namespace gcs = ::google::cloud::storage;
@@ -102,80 +102,79 @@ class UploadToGCSCallback {
} // namespace
-void PutGCSObject::initialize() {
- setSupportedProperties(Properties);
- setSupportedRelationships(Relationships);
-}
-
+MinifiStatus PutGCSObject::onScheduleImpl(api::core::ProcessContext& context) {
+ const auto status = GCSProcessor::onScheduleImpl(context);
+ if (status != MinifiStatus::MINIFI_STATUS_SUCCESS) {
+ return status;
+ }
-void PutGCSObject::onSchedule(core::ProcessContext& context,
core::ProcessSessionFactory& session_factory) {
- GCSProcessor::onSchedule(context, session_factory);
- if (auto encryption_key = context.getProperty(EncryptionKey)) {
+ if (auto encryption_key = context.getProperty(EncryptionKey, nullptr)) {
try {
encryption_key_ = gcs::EncryptionKey::FromBase64Key(*encryption_key);
} catch (const google::cloud::RuntimeStatusError&) {
- throw minifi::Exception(ExceptionType::PROCESS_SCHEDULE_EXCEPTION,
"Could not decode the base64-encoded encryption key from property " +
std::string(EncryptionKey.name));
+ logger_->log_error("Could not decode the base64-encoded encryption key
from property {}", std::string(EncryptionKey.name));
+ return MINIFI_STATUS_UNKNOWN_ERROR;
}
}
+ return MINIFI_STATUS_SUCCESS;
}
-void PutGCSObject::onTrigger(core::ProcessContext& context,
core::ProcessSession& session) {
+MinifiStatus PutGCSObject::onTriggerImpl(api::core::ProcessContext& context,
api::core::ProcessSession& session) {
gsl_Expects(gcp_credentials_);
auto flow_file = session.get();
if (!flow_file) {
- context.yield();
- return;
+ return MINIFI_STATUS_PROCESSOR_YIELD;
}
- auto bucket = context.getProperty(Bucket, flow_file.get());
+ auto bucket = api::utils::parseOptionalProperty(context, Bucket, &flow_file);
+
if (!bucket || bucket->empty()) {
logger_->log_error("Missing bucket name");
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
- auto object_name = context.getProperty(Key, flow_file.get());
+ auto object_name = api::utils::parseOptionalProperty(context, Key,
&flow_file);
if (!object_name || object_name->empty()) {
logger_->log_error("Missing object name");
- session.transfer(flow_file, Failure);
- return;
+ session.transfer(std::move(flow_file), Failure);
+ return MINIFI_STATUS_SUCCESS;
}
gcs::Client client = getClient();
UploadToGCSCallback callback(client, *bucket, *object_name);
- if (auto crc32_checksum = context.getProperty(Crc32cChecksum,
flow_file.get())) {
+ if (auto crc32_checksum = api::utils::parseOptionalProperty(context,
Crc32cChecksum, &flow_file)) {
callback.setCrc32CChecksumValue(*crc32_checksum);
}
- if (auto md5_hash = context.getProperty(MD5Hash, flow_file.get())) {
+ if (auto md5_hash = api::utils::parseOptionalProperty(context, MD5Hash,
&flow_file)) {
callback.setHashValue(*md5_hash);
}
- auto content_type = context.getProperty(ContentType, flow_file.get());
+ auto content_type = api::utils::parseOptionalProperty(context, ContentType,
&flow_file);
if (content_type && !content_type->empty())
callback.setContentType(*content_type);
- if (auto predefined_acl =
utils::parseOptionalEnumProperty<put_gcs_object::PredefinedAcl>(context,
ObjectACL))
+ if (auto predefined_acl =
api::utils::parseOptionalEnumProperty<put_gcs_object::PredefinedAcl>(context,
ObjectACL))
callback.setPredefinedAcl(*predefined_acl);
- callback.setIfGenerationMatch(utils::parseOptionalBoolProperty(context,
OverwriteObject));
+ callback.setIfGenerationMatch(api::utils::parseOptionalBoolProperty(context,
OverwriteObject));
callback.setEncryptionKey(encryption_key_);
session.read(flow_file, std::ref(callback));
auto& result = callback.getResult();
if (!result.ok()) {
- flow_file->setAttribute(GCS_STATUS_MESSAGE, result.status().message());
- flow_file->setAttribute(GCS_ERROR_REASON,
result.status().error_info().reason());
- flow_file->setAttribute(GCS_ERROR_DOMAIN,
result.status().error_info().domain());
+ session.setAttribute(flow_file, GCS_STATUS_MESSAGE,
result.status().message());
+ session.setAttribute(flow_file, GCS_ERROR_REASON,
result.status().error_info().reason());
+ session.setAttribute(flow_file, GCS_ERROR_DOMAIN,
result.status().error_info().domain());
logger_->log_error("Failed to upload to Google Cloud Storage {} {}",
result.status().message(), result.status().error_info().reason());
- session.transfer(flow_file, Failure);
+ session.transfer(std::move(flow_file), Failure);
} else {
- setAttributesFromObjectMetadata(*flow_file, *result);
- session.transfer(flow_file, Success);
+ setAttributesFromObjectMetadata(flow_file, *result, session);
+ session.transfer(std::move(flow_file), Success);
}
+ return MINIFI_STATUS_SUCCESS;
}
-REGISTER_RESOURCE(PutGCSObject, Processor);
-
} // namespace org::apache::nifi::minifi::extensions::gcp
diff --git a/extensions/gcp/processors/PutGCSObject.h
b/extensions/gcp/processors/PutGCSObject.h
index 58d7675fa..73d8c8218 100644
--- a/extensions/gcp/processors/PutGCSObject.h
+++ b/extensions/gcp/processors/PutGCSObject.h
@@ -19,17 +19,16 @@
#include <memory>
#include <string>
-#include <utility>
#include "../GCPAttributes.h"
#include "GCSProcessor.h"
#include "minifi-cpp/core/PropertyDefinition.h"
#include "minifi-cpp/core/PropertyValidator.h"
#include "minifi-cpp/core/RelationshipDefinition.h"
-#include "core/logging/LoggerFactory.h"
#include "utils/ArrayUtils.h"
#include "utils/Enum.h"
#include "google/cloud/storage/well_known_headers.h"
+#include "minifi-cpp/core/Annotation.h"
namespace org::apache::nifi::minifi::extensions::gcp::put_gcs_object {
enum class PredefinedAcl {
@@ -73,7 +72,6 @@ namespace org::apache::nifi::minifi::extensions::gcp {
class PutGCSObject : public GCSProcessor {
public:
using GCSProcessor::GCSProcessor;
- ~PutGCSObject() override = default;
EXTENSIONAPI static constexpr const char* Description = "Puts flow files to
a Google Cloud Storage Bucket.";
@@ -191,11 +189,9 @@ class PutGCSObject : public GCSProcessor {
EXTENSIONAPI static constexpr core::annotation::Input InputRequirement =
core::annotation::Input::INPUT_REQUIRED;
EXTENSIONAPI static constexpr bool IsSingleThreaded = false;
- ADD_COMMON_VIRTUAL_FUNCTIONS_FOR_PROCESSORS
-
- void initialize() override;
- void onSchedule(core::ProcessContext& context, core::ProcessSessionFactory&
session_factory) override;
- void onTrigger(core::ProcessContext& context, core::ProcessSession& session)
override;
+ protected:
+ MinifiStatus onScheduleImpl(api::core::ProcessContext& context) override;
+ MinifiStatus onTriggerImpl(api::core::ProcessContext& context,
api::core::ProcessSession& session) override;
private:
google::cloud::storage::EncryptionKey encryption_key_;
diff --git a/extensions/gcp/tests/CMakeLists.txt
b/extensions/gcp/tests/CMakeLists.txt
index 0acc5241b..89fe308e9 100644
--- a/extensions/gcp/tests/CMakeLists.txt
+++ b/extensions/gcp/tests/CMakeLists.txt
@@ -36,8 +36,8 @@ FOREACH(testfile ${GCS_TESTS})
createTests("${testfilename}")
target_link_libraries(${testfilename} minifi-gcp)
- target_link_libraries(${testfilename} minifi-standard-processors)
target_link_libraries(${testfilename} gtest_main gmock)
+ target_link_libraries(${testfilename} libminifi-c-unittest)
gtest_add_tests(TARGET "${testfilename}")
ENDFOREACH()
diff --git a/extensions/gcp/tests/DeleteGCSObjectTests.cpp
b/extensions/gcp/tests/DeleteGCSObjectTests.cpp
index bde7e010f..aee457a60 100644
--- a/extensions/gcp/tests/DeleteGCSObjectTests.cpp
+++ b/extensions/gcp/tests/DeleteGCSObjectTests.cpp
@@ -14,60 +14,65 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "../processors/DeleteGCSObject.h"
#include "../controllerservices/GCPCredentialsControllerService.h"
+#include "../processors/DeleteGCSObject.h"
+#include "CProcessorTestUtils.h"
#include "GCPAttributes.h"
#include "core/Resource.h"
-#include "unit/SingleProcessorTestController.h"
-#include "google/cloud/storage/testing/mock_client.h"
#include "google/cloud/storage/internal/object_metadata_parser.h"
#include "google/cloud/storage/testing/canonical_errors.h"
+#include "google/cloud/storage/testing/mock_client.h"
#include "unit/ProcessorUtils.h"
+#include "unit/SingleProcessorTestController.h"
namespace gcs = ::google::cloud::storage;
-namespace minifi_gcp = org::apache::nifi::minifi::extensions::gcp;
+namespace minifi_gcp = minifi::extensions::gcp;
-using DeleteGCSObject =
org::apache::nifi::minifi::extensions::gcp::DeleteGCSObject;
-using GCPCredentialsControllerService =
org::apache::nifi::minifi::extensions::gcp::GCPCredentialsControllerService;
+using DeleteGCSObject = minifi::extensions::gcp::DeleteGCSObject;
+using GCPCredentialsControllerService =
minifi::extensions::gcp::GCPCredentialsControllerService;
using DeleteObjectRequest = gcs::internal::DeleteObjectRequest;
-using ::google::cloud::storage::testing::canonical_errors::TransientError;
using ::google::cloud::storage::testing::canonical_errors::PermanentError;
+using ::google::cloud::storage::testing::canonical_errors::TransientError;
namespace {
class DeleteGCSObjectMocked : public DeleteGCSObject {
- using
org::apache::nifi::minifi::extensions::gcp::DeleteGCSObject::DeleteGCSObject;
+ using DeleteGCSObject::DeleteGCSObject;
+
public:
- static constexpr const char* Description = "DeleteGCSObjectMocked";
+ DeleteGCSObjectMocked(minifi::core::ProcessorMetadata metadata,
std::shared_ptr<gcs::testing::MockClient> mock_client)
+ : DeleteGCSObject(std::move(metadata)),
+ mock_client_(std::move(mock_client)) {}
- gcs::Client getClient() const override {
- return gcs::testing::UndecoratedClientFromMock(mock_client_);
- }
- std::shared_ptr<gcs::testing::MockClient> mock_client_ =
std::make_shared<gcs::testing::MockClient>();
+ protected:
+ gcs::Client getClient() const override { return
gcs::testing::UndecoratedClientFromMock(mock_client_); }
+ std::shared_ptr<gcs::testing::MockClient> mock_client_;
};
-REGISTER_RESOURCE(DeleteGCSObjectMocked, Processor);
} // namespace
class DeleteGCSObjectTests : public ::testing::Test {
- public:
+ protected:
void SetUp() override {
- delete_gcs_object_ = test_controller_.getProcessor();
- gcp_credentials_node_ =
test_controller_.plan->addController("GCPCredentialsControllerService",
"gcp_credentials_controller_service");
- test_controller_.plan->setProperty(gcp_credentials_node_,
-
GCPCredentialsControllerService::CredentialsLoc,
-
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS));
- test_controller_.plan->setProperty(delete_gcs_object_,
- DeleteGCSObject::GCPCredentials,
- "gcp_credentials_controller_service");
+ const auto gcp_credential_controller_service =
+
minifi::test::utils::make_custom_c_controller_service<GCPCredentialsControllerService>(core::ControllerServiceMetadata{utils::Identifier{},
+ "GCPCredentialsControllerService",
+
logging::LoggerFactory<GCPCredentialsControllerService>::getLogger()});
+ gcp_credentials_node_ =
test_controller_.plan->addController("gcp_credentials_controller_service",
gcp_credential_controller_service);
+
EXPECT_TRUE(gcp_credential_controller_service->setProperty(GCPCredentialsControllerService::CredentialsLoc.name,
+
std::string(magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS))));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(DeleteGCSObject::GCPCredentials.name,
"gcp_credentials_controller_service"));
}
- org::apache::nifi::minifi::test::SingleProcessorTestController
test_controller_{minifi::test::utils::make_processor<DeleteGCSObjectMocked>("DeleteGCSObjectMocked")};
- std::shared_ptr<minifi::core::controller::ControllerServiceNode>
gcp_credentials_node_;
- TypedProcessorWrapper<DeleteGCSObjectMocked> delete_gcs_object_ = nullptr;
+ public:
+ std::shared_ptr<gcs::testing::MockClient> mock_client_ =
std::make_shared<gcs::testing::MockClient>();
+ minifi::test::SingleProcessorTestController
test_controller_{minifi::test::utils::make_custom_c_processor<DeleteGCSObjectMocked>(
+ core::ProcessorMetadata{utils::Identifier{}, "DeleteGCSObjectMocked",
logging::LoggerFactory<DeleteGCSObjectMocked>::getLogger()},
+ mock_client_)};
+ std::shared_ptr<core::controller::ControllerServiceNode>
gcp_credentials_node_;
};
TEST_F(DeleteGCSObjectTests, MissingBucket) {
- EXPECT_CALL(*delete_gcs_object_.get().mock_client_,
CreateResumableUpload).Times(0);
- EXPECT_TRUE(test_controller_.plan->setProperty(delete_gcs_object_,
DeleteGCSObject::Bucket, ""));
+ EXPECT_CALL(*mock_client_, CreateResumableUpload).Times(0);
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(DeleteGCSObject::Bucket.name,
""));
const auto& result = test_controller_.trigger("hello world");
EXPECT_EQ(0, result.at(DeleteGCSObject::Success).size());
ASSERT_EQ(1, result.at(DeleteGCSObject::Failure).size());
@@ -77,9 +82,9 @@ TEST_F(DeleteGCSObjectTests, MissingBucket) {
}
TEST_F(DeleteGCSObjectTests, ServerGivesPermaError) {
- EXPECT_CALL(*delete_gcs_object_.get().mock_client_, DeleteObject)
+ EXPECT_CALL(*mock_client_, DeleteObject)
.WillOnce(testing::Return(PermanentError()));
- EXPECT_TRUE(test_controller_.plan->setProperty(delete_gcs_object_,
DeleteGCSObject::Bucket, "bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(DeleteGCSObject::Bucket.name,
"bucket-from-property"));
const auto& result = test_controller_.trigger("hello world");
EXPECT_EQ(0, result.at(DeleteGCSObject::Success).size());
ASSERT_EQ(1, result.at(DeleteGCSObject::Failure).size());
@@ -89,9 +94,9 @@ TEST_F(DeleteGCSObjectTests, ServerGivesPermaError) {
}
TEST_F(DeleteGCSObjectTests, ServerGivesTransientErrors) {
- EXPECT_CALL(*delete_gcs_object_.get().mock_client_,
DeleteObject).WillOnce(testing::Return(TransientError()));
- EXPECT_TRUE(test_controller_.plan->setProperty(delete_gcs_object_,
DeleteGCSObject::NumberOfRetries, "1"));
- EXPECT_TRUE(test_controller_.plan->setProperty(delete_gcs_object_,
DeleteGCSObject::Bucket, "bucket-from-property"));
+ EXPECT_CALL(*mock_client_,
DeleteObject).WillOnce(testing::Return(TransientError()));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(DeleteGCSObject::NumberOfRetries.name,
"1"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(DeleteGCSObject::Bucket.name,
"bucket-from-property"));
const auto& result = test_controller_.trigger("hello world",
{{std::string(minifi_gcp::GCS_BUCKET_ATTR), "bucket-from-attribute"}});
EXPECT_EQ(0, result.at(DeleteGCSObject::Success).size());
ASSERT_EQ(1, result.at(DeleteGCSObject::Failure).size());
@@ -100,9 +105,8 @@ TEST_F(DeleteGCSObjectTests, ServerGivesTransientErrors) {
EXPECT_EQ("hello world",
test_controller_.plan->getContent(result.at(DeleteGCSObject::Failure)[0]));
}
-
TEST_F(DeleteGCSObjectTests, HandlingSuccessfullDeletion) {
- EXPECT_CALL(*delete_gcs_object_.get().mock_client_, DeleteObject)
+ EXPECT_CALL(*mock_client_, DeleteObject)
.WillOnce([](DeleteObjectRequest const& request) {
EXPECT_EQ("bucket-from-attribute", request.bucket_name());
EXPECT_TRUE(request.HasOption<gcs::Generation>());
@@ -110,7 +114,7 @@ TEST_F(DeleteGCSObjectTests, HandlingSuccessfullDeletion) {
EXPECT_EQ(23, request.GetOption<gcs::Generation>().value());
return google::cloud::make_status_or(gcs::internal::EmptyResponse{});
});
- EXPECT_TRUE(test_controller_.plan->setProperty(delete_gcs_object_,
DeleteGCSObject::ObjectGeneration, "${gcs.generation}"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(DeleteGCSObject::ObjectGeneration.name,
"${gcs.generation}"));
const auto& result = test_controller_.trigger("hello world",
{{std::string(minifi_gcp::GCS_BUCKET_ATTR), "bucket-from-attribute"},
{std::string(minifi_gcp::GCS_GENERATION), "23"}});
ASSERT_EQ(1, result.at(DeleteGCSObject::Success).size());
EXPECT_EQ(0, result.at(DeleteGCSObject::Failure).size());
@@ -118,13 +122,13 @@ TEST_F(DeleteGCSObjectTests, HandlingSuccessfullDeletion)
{
}
TEST_F(DeleteGCSObjectTests, EmptyGeneration) {
- EXPECT_CALL(*delete_gcs_object_.get().mock_client_, DeleteObject)
+ EXPECT_CALL(*mock_client_, DeleteObject)
.WillOnce([](DeleteObjectRequest const& request) {
EXPECT_EQ("bucket-from-attribute", request.bucket_name());
EXPECT_FALSE(request.HasOption<gcs::Generation>());
return google::cloud::make_status_or(gcs::internal::EmptyResponse{});
});
- EXPECT_TRUE(test_controller_.plan->setProperty(delete_gcs_object_,
DeleteGCSObject::ObjectGeneration, "${gcs.generation}"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(DeleteGCSObject::ObjectGeneration.name,
"${gcs.generation}"));
const auto& result = test_controller_.trigger("hello world",
{{std::string(minifi_gcp::GCS_BUCKET_ATTR), "bucket-from-attribute"}});
ASSERT_EQ(1, result.at(DeleteGCSObject::Success).size());
EXPECT_EQ(0, result.at(DeleteGCSObject::Failure).size());
@@ -132,7 +136,7 @@ TEST_F(DeleteGCSObjectTests, EmptyGeneration) {
}
TEST_F(DeleteGCSObjectTests, InvalidGeneration) {
- EXPECT_TRUE(test_controller_.plan->setProperty(delete_gcs_object_,
DeleteGCSObject::ObjectGeneration, "${gcs.generation}"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(DeleteGCSObject::ObjectGeneration.name,
"${gcs.generation}"));
const auto& result = test_controller_.trigger("hello world",
{{std::string(minifi_gcp::GCS_BUCKET_ATTR), "bucket-from-attribute"},
{std::string(minifi_gcp::GCS_GENERATION), "23 banana"}});
ASSERT_EQ(0, result.at(DeleteGCSObject::Success).size());
EXPECT_EQ(1, result.at(DeleteGCSObject::Failure).size());
diff --git a/extensions/gcp/tests/FetchGCSObjectTests.cpp
b/extensions/gcp/tests/FetchGCSObjectTests.cpp
index ea87c7e63..764d57ffe 100644
--- a/extensions/gcp/tests/FetchGCSObjectTests.cpp
+++ b/extensions/gcp/tests/FetchGCSObjectTests.cpp
@@ -14,56 +14,63 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "../processors/FetchGCSObject.h"
+#include <memory>
+
#include "../controllerservices/GCPCredentialsControllerService.h"
+#include "../processors/FetchGCSObject.h"
+#include "CProcessorTestUtils.h"
#include "GCPAttributes.h"
#include "core/Resource.h"
-#include "unit/SingleProcessorTestController.h"
-#include "google/cloud/storage/testing/mock_client.h"
#include "google/cloud/storage/internal/object_metadata_parser.h"
#include "google/cloud/storage/testing/canonical_errors.h"
+#include "google/cloud/storage/testing/mock_client.h"
#include "unit/ProcessorUtils.h"
+#include "unit/SingleProcessorTestController.h"
namespace gcs = ::google::cloud::storage;
-namespace minifi_gcp = org::apache::nifi::minifi::extensions::gcp;
+namespace minifi_gcp = minifi::extensions::gcp;
-using FetchGCSObject =
org::apache::nifi::minifi::extensions::gcp::FetchGCSObject;
-using GCPCredentialsControllerService =
org::apache::nifi::minifi::extensions::gcp::GCPCredentialsControllerService;
+using FetchGCSObject = minifi::extensions::gcp::FetchGCSObject;
+using GCPCredentialsControllerService =
minifi::extensions::gcp::GCPCredentialsControllerService;
namespace {
class FetchGCSObjectMocked : public FetchGCSObject {
- using
org::apache::nifi::minifi::extensions::gcp::FetchGCSObject::FetchGCSObject;
+ using FetchGCSObject::FetchGCSObject;
+
public:
- static constexpr const char* Description = "FetchGCSObjectMocked";
+ FetchGCSObjectMocked(minifi::core::ProcessorMetadata metadata,
std::shared_ptr<gcs::testing::MockClient> mock_client)
+ : FetchGCSObject(std::move(metadata)),
+ mock_client_(std::move(mock_client)) {}
- gcs::Client getClient() const override {
- return gcs::testing::UndecoratedClientFromMock(mock_client_);
- }
- std::shared_ptr<gcs::testing::MockClient> mock_client_ =
std::make_shared<gcs::testing::MockClient>();
+ protected:
+ gcs::Client getClient() const override { return
gcs::testing::UndecoratedClientFromMock(mock_client_); }
+ std::shared_ptr<gcs::testing::MockClient> mock_client_;
};
-REGISTER_RESOURCE(FetchGCSObjectMocked, Processor);
} // namespace
class FetchGCSObjectTests : public ::testing::Test {
- public:
+ protected:
void SetUp() override {
- fetch_gcs_object_ = test_controller_.getProcessor();
- gcp_credentials_node_ =
test_controller_.plan->addController("GCPCredentialsControllerService",
"gcp_credentials_controller_service");
- test_controller_.plan->setProperty(gcp_credentials_node_,
-
GCPCredentialsControllerService::CredentialsLoc,
-
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS));
- test_controller_.plan->setProperty(fetch_gcs_object_,
- FetchGCSObject::GCPCredentials,
- "gcp_credentials_controller_service");
+ const auto gcp_credential_controller_service =
+
minifi::test::utils::make_custom_c_controller_service<GCPCredentialsControllerService>(core::ControllerServiceMetadata{utils::Identifier{},
+ "GCPCredentialsControllerService",
+
logging::LoggerFactory<GCPCredentialsControllerService>::getLogger()});
+ gcp_credentials_node_ =
test_controller_.plan->addController("gcp_credentials_controller_service",
gcp_credential_controller_service);
+
EXPECT_TRUE(gcp_credential_controller_service->setProperty(GCPCredentialsControllerService::CredentialsLoc.name,
+
std::string(magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS))));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(FetchGCSObjectMocked::GCPCredentials.name,
"gcp_credentials_controller_service"));
}
- TypedProcessorWrapper<FetchGCSObjectMocked> fetch_gcs_object_;
- org::apache::nifi::minifi::test::SingleProcessorTestController
test_controller_{minifi::test::utils::make_processor<FetchGCSObjectMocked>("FetchGCSObjectMocked")};
- std::shared_ptr<minifi::core::controller::ControllerServiceNode>
gcp_credentials_node_;
+
+ public:
+ std::shared_ptr<gcs::testing::MockClient> mock_client_ =
std::make_shared<gcs::testing::MockClient>();
+ minifi::test::SingleProcessorTestController
test_controller_{minifi::test::utils::make_custom_c_processor<FetchGCSObjectMocked>(
+ core::ProcessorMetadata{utils::Identifier{}, "FetchGCSObjectMocked",
logging::LoggerFactory<FetchGCSObjectMocked>::getLogger()}, mock_client_)};
+ std::shared_ptr<minifi::core::controller::ControllerServiceNode>
gcp_credentials_node_;
};
TEST_F(FetchGCSObjectTests, MissingBucket) {
- EXPECT_CALL(*fetch_gcs_object_.get().mock_client_,
CreateResumableUpload).Times(0);
- EXPECT_TRUE(test_controller_.plan->setProperty(fetch_gcs_object_,
FetchGCSObject::Bucket, ""));
+ EXPECT_CALL(*mock_client_, CreateResumableUpload).Times(0);
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(FetchGCSObject::Bucket.name,
""));
const auto& result = test_controller_.trigger("hello world");
EXPECT_EQ(0, result.at(FetchGCSObject::Success).size());
ASSERT_EQ(1, result.at(FetchGCSObject::Failure).size());
@@ -73,7 +80,7 @@ TEST_F(FetchGCSObjectTests, MissingBucket) {
}
TEST_F(FetchGCSObjectTests, ServerError) {
- EXPECT_CALL(*fetch_gcs_object_.get().mock_client_, ReadObject)
+ EXPECT_CALL(*mock_client_, ReadObject)
.WillOnce([](gcs::internal::ReadObjectRangeRequest const& request) {
EXPECT_EQ(request.bucket_name(), "bucket-from-property") << request;
auto mock_source =
std::make_unique<gcs::testing::MockObjectReadSource>();
@@ -88,7 +95,7 @@ TEST_F(FetchGCSObjectTests, ServerError) {
std::unique_ptr<gcs::internal::ObjectReadSource> object_read_source =
std::move(mock_source);
return google::cloud::make_status_or(std::move(object_read_source));
});
- EXPECT_TRUE(test_controller_.plan->setProperty(fetch_gcs_object_,
FetchGCSObject::Bucket, "bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(FetchGCSObject::Bucket.name,
"bucket-from-property"));
const auto& result = test_controller_.trigger("hello world",
{{std::string(minifi_gcp::GCS_BUCKET_ATTR), "bucket-from-attribute"}});
EXPECT_EQ(0, result.at(FetchGCSObject::Success).size());
ASSERT_EQ(1, result.at(FetchGCSObject::Failure).size());
@@ -97,7 +104,7 @@ TEST_F(FetchGCSObjectTests, ServerError) {
}
TEST_F(FetchGCSObjectTests, HappyPath) {
- std::string const text = "stored text";
+ constexpr std::string_view text = "stored text";
std::size_t offset = 0;
// Simulate a Read() call in the MockObjectReadSource object created below
auto simulate_read = [&text, &offset](void* buf, std::size_t n) {
@@ -107,13 +114,13 @@ TEST_F(FetchGCSObjectTests, HappyPath) {
return gcs::internal::ReadSourceResult{
l, gcs::internal::HttpResponse{200, {}, {}}};
};
- EXPECT_CALL(*fetch_gcs_object_.get().mock_client_, ReadObject)
+ EXPECT_CALL(*mock_client_, ReadObject)
.WillOnce([&](gcs::internal::ReadObjectRangeRequest const& request) {
EXPECT_EQ(request.bucket_name(), "bucket-from-attribute") << request;
EXPECT_TRUE(request.HasOption<gcs::Generation>());
EXPECT_TRUE(request.GetOption<gcs::Generation>().has_value());
EXPECT_EQ(23, request.GetOption<gcs::Generation>().value());
- std::unique_ptr<gcs::testing::MockObjectReadSource> mock_source(new
gcs::testing::MockObjectReadSource);
+ auto mock_source =
std::make_unique<gcs::testing::MockObjectReadSource>();
::testing::InSequence seq;
EXPECT_CALL(*mock_source,
IsOpen()).WillRepeatedly(testing::Return(true));
EXPECT_CALL(*mock_source, Read).WillOnce(simulate_read);
@@ -123,7 +130,7 @@ TEST_F(FetchGCSObjectTests, HappyPath) {
std::unique_ptr<gcs::internal::ObjectReadSource>(
std::move(mock_source)));
});
- EXPECT_TRUE(test_controller_.plan->setProperty(fetch_gcs_object_,
FetchGCSObject::ObjectGeneration, "${gcs.generation}"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(FetchGCSObject::ObjectGeneration.name,
"${gcs.generation}"));
const auto& result = test_controller_.trigger("hello world",
{{std::string(minifi_gcp::GCS_BUCKET_ATTR), "bucket-from-attribute"},
{std::string(minifi_gcp::GCS_GENERATION), "23"}});
ASSERT_EQ(1, result.at(FetchGCSObject::Success).size());
EXPECT_EQ(0, result.at(FetchGCSObject::Failure).size());
@@ -131,7 +138,7 @@ TEST_F(FetchGCSObjectTests, HappyPath) {
}
TEST_F(FetchGCSObjectTests, EmptyGeneration) {
- std::string const text = "stored text";
+ constexpr std::string_view text = "stored text";
std::size_t offset = 0;
// Simulate a Read() call in the MockObjectReadSource object created below
auto simulate_read = [&text, &offset](void* buf, std::size_t n) {
@@ -141,11 +148,11 @@ TEST_F(FetchGCSObjectTests, EmptyGeneration) {
return gcs::internal::ReadSourceResult{
l, gcs::internal::HttpResponse{200, {}, {}}};
};
- EXPECT_CALL(*fetch_gcs_object_.get().mock_client_, ReadObject)
+ EXPECT_CALL(*mock_client_, ReadObject)
.WillOnce([&](gcs::internal::ReadObjectRangeRequest const& request) {
EXPECT_EQ(request.bucket_name(), "bucket-from-attribute") << request;
EXPECT_FALSE(request.HasOption<gcs::Generation>());
- std::unique_ptr<gcs::testing::MockObjectReadSource> mock_source(new
gcs::testing::MockObjectReadSource);
+ auto mock_source =
std::make_unique<gcs::testing::MockObjectReadSource>();
::testing::InSequence seq;
EXPECT_CALL(*mock_source,
IsOpen()).WillRepeatedly(testing::Return(true));
EXPECT_CALL(*mock_source, Read).WillOnce(simulate_read);
@@ -155,7 +162,7 @@ TEST_F(FetchGCSObjectTests, EmptyGeneration) {
std::unique_ptr<gcs::internal::ObjectReadSource>(
std::move(mock_source)));
});
- EXPECT_TRUE(test_controller_.plan->setProperty(fetch_gcs_object_,
FetchGCSObject::ObjectGeneration, "${gcs.generation}"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(FetchGCSObject::ObjectGeneration.name,
"${gcs.generation}"));
const auto& result = test_controller_.trigger("hello world",
{{std::string(minifi_gcp::GCS_BUCKET_ATTR), "bucket-from-attribute"}});
ASSERT_EQ(1, result.at(FetchGCSObject::Success).size());
EXPECT_EQ(0, result.at(FetchGCSObject::Failure).size());
@@ -163,7 +170,7 @@ TEST_F(FetchGCSObjectTests, EmptyGeneration) {
}
TEST_F(FetchGCSObjectTests, InvalidGeneration) {
- EXPECT_TRUE(test_controller_.plan->setProperty(fetch_gcs_object_,
FetchGCSObject::ObjectGeneration, "${gcs.generation}"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(FetchGCSObject::ObjectGeneration.name,
"${gcs.generation}"));
const auto& result = test_controller_.trigger("hello world",
{{std::string(minifi_gcp::GCS_BUCKET_ATTR), "bucket-from-attribute"},
{std::string(minifi_gcp::GCS_GENERATION), "23 banana"}});
ASSERT_EQ(0, result.at(FetchGCSObject::Success).size());
EXPECT_EQ(1, result.at(FetchGCSObject::Failure).size());
diff --git a/extensions/gcp/tests/GCPCredentialsControllerServiceTests.cpp
b/extensions/gcp/tests/GCPCredentialsControllerServiceTests.cpp
index 0334cb4d9..bedbac924 100644
--- a/extensions/gcp/tests/GCPCredentialsControllerServiceTests.cpp
+++ b/extensions/gcp/tests/GCPCredentialsControllerServiceTests.cpp
@@ -16,19 +16,20 @@
*/
#define EXTENSION_LIST "minifi-gcp" // NOLINT(cppcoreguidelines-macro-usage)
-#include "unit/TestBase.h"
-#include "gtest/gtest.h"
#include "../controllerservices/GCPCredentialsControllerService.h"
-#include "core/Resource.h"
+#include "CProcessorTestUtils.h"
#include "core/Processor.h"
+#include "core/Resource.h"
#include "core/controller/ControllerServiceNode.h"
+#include "gtest/gtest.h"
#include "rapidjson/document.h"
#include "rapidjson/stream.h"
#include "rapidjson/writer.h"
#include "unit/DummyProcessor.h"
+#include "unit/TestBase.h"
#include "utils/Environment.h"
-namespace minifi_gcp = org::apache::nifi::minifi::extensions::gcp;
+namespace minifi_gcp = minifi::extensions::gcp;
using GCPCredentialsControllerService =
minifi_gcp::GCPCredentialsControllerService;
namespace {
@@ -70,14 +71,20 @@ std::optional<std::filesystem::path>
create_mock_json_file(const std::filesystem
class GCPCredentialsTests : public ::testing::Test {
protected:
void SetUp() override {
- ASSERT_TRUE(gcp_credentials_node_);
- ASSERT_TRUE(gcp_credentials_);
plan_->addProcessor("DummyProcessor", "dummy_processor");
+ auto gcp_credential_controller_service =
+
minifi::test::utils::make_custom_c_controller_service<GCPCredentialsControllerService>(core::ControllerServiceMetadata{utils::Identifier{},
+ "GCPCredentialsControllerService",
+
logging::LoggerFactory<GCPCredentialsControllerService>::getLogger()});
+ gcp_credentials_node_ =
plan_->addController("gcp_credentials_controller_service",
gcp_credential_controller_service);
+ gcp_credentials_ = static_cast<GCPCredentialsControllerService*>(
+
gcp_credentials_node_->getControllerServiceImplementation<utils::CControllerService>()->getImpl());
}
TestController test_controller_;
std::shared_ptr<TestPlan> plan_ = test_controller_.createPlan();
- std::shared_ptr<minifi::core::controller::ControllerServiceNode>
gcp_credentials_node_ = plan_->addController("GCPCredentialsControllerService",
"gcp_credentials_controller_service");
- std::shared_ptr<GCPCredentialsControllerService> gcp_credentials_ =
gcp_credentials_node_->getControllerServiceImplementation<GCPCredentialsControllerService>();
+
+ std::shared_ptr<minifi::core::controller::ControllerServiceNode>
gcp_credentials_node_;
+ GCPCredentialsControllerService* gcp_credentials_ = nullptr;
};
TEST_F(GCPCredentialsTests, DefaultGCPCredentialsWithEnv) {
@@ -85,13 +92,17 @@ TEST_F(GCPCredentialsTests, DefaultGCPCredentialsWithEnv) {
auto path = create_mock_json_file(temp_directory);
ASSERT_TRUE(path.has_value());
minifi::utils::Environment::setEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS",
path->string().c_str());
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::CredentialsLoc,
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_DEFAULT_CREDENTIALS));
+ EXPECT_TRUE(plan_->setProperty(gcp_credentials_node_,
+ GCPCredentialsControllerService::CredentialsLoc,
+
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_DEFAULT_CREDENTIALS)));
ASSERT_NO_THROW(test_controller_.runSession(plan_));
EXPECT_NE(nullptr, gcp_credentials_->getCredentials());
}
TEST_F(GCPCredentialsTests, CredentialsFromJsonWithoutProperty) {
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::CredentialsLoc,
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_FILE));
+ EXPECT_TRUE(plan_->setProperty(gcp_credentials_node_,
+ GCPCredentialsControllerService::CredentialsLoc,
+ magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_FILE)));
ASSERT_NO_THROW(test_controller_.runSession(plan_));
EXPECT_EQ(nullptr, gcp_credentials_->getCredentials());
}
@@ -100,8 +111,10 @@ TEST_F(GCPCredentialsTests,
CredentialsFromJsonWithProperty) {
auto temp_directory = test_controller_.createTempDirectory();
auto path = create_mock_json_file(temp_directory);
ASSERT_TRUE(path.has_value());
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::CredentialsLoc,
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_FILE));
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::JsonFilePath, path->string());
+ EXPECT_TRUE(plan_->setProperty(gcp_credentials_node_,
+ GCPCredentialsControllerService::CredentialsLoc,
+ magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_FILE)));
+ ASSERT_TRUE(plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::JsonFilePath, path->string()));
ASSERT_NO_THROW(test_controller_.runSession(plan_));
EXPECT_NE(nullptr, gcp_credentials_->getCredentials());
}
@@ -110,32 +123,42 @@ TEST_F(GCPCredentialsTests,
CredentialsFromJsonWithInvalidPath) {
auto temp_directory = test_controller_.createTempDirectory();
auto path = create_mock_json_file(temp_directory);
ASSERT_TRUE(path.has_value());
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::CredentialsLoc,
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_FILE));
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::JsonFilePath,
"/invalid/path/to/credentials.json");
+ EXPECT_TRUE(plan_->setProperty(gcp_credentials_node_,
+ GCPCredentialsControllerService::CredentialsLoc,
+ magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_FILE)));
+ ASSERT_TRUE(plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::JsonFilePath,
"/invalid/path/to/credentials.json"));
ASSERT_NO_THROW(test_controller_.runSession(plan_));
EXPECT_EQ(nullptr, gcp_credentials_->getCredentials());
}
TEST_F(GCPCredentialsTests, CredentialsFromComputeEngineVM) {
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::CredentialsLoc,
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_COMPUTE_ENGINE_CREDENTIALS));
+ EXPECT_TRUE(plan_->setProperty(gcp_credentials_node_,
+ GCPCredentialsControllerService::CredentialsLoc,
+
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_COMPUTE_ENGINE_CREDENTIALS)));
ASSERT_NO_THROW(test_controller_.runSession(plan_));
EXPECT_NE(nullptr, gcp_credentials_->getCredentials());
}
TEST_F(GCPCredentialsTests, AnonymousCredentials) {
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::CredentialsLoc,
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS));
+ EXPECT_TRUE(plan_->setProperty(gcp_credentials_node_,
+ GCPCredentialsControllerService::CredentialsLoc,
+
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS)));
ASSERT_NO_THROW(test_controller_.runSession(plan_));
EXPECT_NE(nullptr, gcp_credentials_->getCredentials());
}
TEST_F(GCPCredentialsTests, CredentialsFromJsonContentsWithoutProperty) {
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::CredentialsLoc,
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_CONTENTS));
+ EXPECT_TRUE(plan_->setProperty(gcp_credentials_node_,
+ GCPCredentialsControllerService::CredentialsLoc,
+
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_CONTENTS)));
ASSERT_NO_THROW(test_controller_.runSession(plan_));
EXPECT_EQ(nullptr, gcp_credentials_->getCredentials());
}
TEST_F(GCPCredentialsTests, CredentialsFromJsonContentsWithProperty) {
- plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::CredentialsLoc,
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_CONTENTS));
+ EXPECT_TRUE(plan_->setProperty(gcp_credentials_node_,
+ GCPCredentialsControllerService::CredentialsLoc,
+
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_JSON_CONTENTS)));
plan_->setProperty(gcp_credentials_node_,
GCPCredentialsControllerService::JsonContents, create_mock_service_json());
ASSERT_NO_THROW(test_controller_.runSession(plan_));
EXPECT_NE(nullptr, gcp_credentials_->getCredentials());
diff --git a/extensions/gcp/tests/ListGCSBucketTests.cpp
b/extensions/gcp/tests/ListGCSBucketTests.cpp
index 16b2c8dad..d286fc739 100644
--- a/extensions/gcp/tests/ListGCSBucketTests.cpp
+++ b/extensions/gcp/tests/ListGCSBucketTests.cpp
@@ -14,37 +14,39 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "../processors/ListGCSBucket.h"
#include "../controllerservices/GCPCredentialsControllerService.h"
+#include "../processors/ListGCSBucket.h"
+#include "CProcessorTestUtils.h"
#include "core/Resource.h"
-#include "unit/SingleProcessorTestController.h"
-#include "google/cloud/storage/testing/mock_client.h"
#include "google/cloud/storage/internal/object_metadata_parser.h"
#include "google/cloud/storage/testing/canonical_errors.h"
+#include "google/cloud/storage/testing/mock_client.h"
#include "unit/ProcessorUtils.h"
+#include "unit/SingleProcessorTestController.h"
namespace gcs = ::google::cloud::storage;
-namespace minifi_gcp = org::apache::nifi::minifi::extensions::gcp;
+namespace minifi_gcp = minifi::extensions::gcp;
-using ListGCSBucket =
org::apache::nifi::minifi::extensions::gcp::ListGCSBucket;
+using ListGCSBucket = minifi::extensions::gcp::ListGCSBucket;
using ListObjectsRequest = gcs::internal::ListObjectsRequest;
using ListObjectsResponse = gcs::internal::ListObjectsResponse;
-using GCPCredentialsControllerService =
org::apache::nifi::minifi::extensions::gcp::GCPCredentialsControllerService;
-using ::google::cloud::storage::testing::canonical_errors::TransientError;
+using GCPCredentialsControllerService =
minifi::extensions::gcp::GCPCredentialsControllerService;
using ::google::cloud::storage::testing::canonical_errors::PermanentError;
+using ::google::cloud::storage::testing::canonical_errors::TransientError;
namespace {
class ListGCSBucketMocked : public ListGCSBucket {
- using
org::apache::nifi::minifi::extensions::gcp::ListGCSBucket::ListGCSBucket;
+ using ListGCSBucket::ListGCSBucket;
+
public:
- static constexpr const char* Description = "ListGCSBucketMocked";
+ ListGCSBucketMocked(minifi::core::ProcessorMetadata metadata,
std::shared_ptr<gcs::testing::MockClient> mock_client)
+ : ListGCSBucket(std::move(metadata)),
+ mock_client_(std::move(mock_client)) {}
- gcs::Client getClient() const override {
- return gcs::testing::UndecoratedClientFromMock(mock_client_);
- }
- std::shared_ptr<gcs::testing::MockClient> mock_client_ =
std::make_shared<gcs::testing::MockClient>();
+ protected:
+ gcs::Client getClient() const override { return
gcs::testing::UndecoratedClientFromMock(mock_client_); }
+ std::shared_ptr<gcs::testing::MockClient> mock_client_;
};
-REGISTER_RESOURCE(ListGCSBucketMocked, Processor);
auto CreateObject(int index, int generation = 1) {
std::string id = "object-" + std::to_string(index);
@@ -64,34 +66,34 @@ auto CreateObject(int index, int generation = 1) {
} // namespace
class ListGCSBucketTests : public ::testing::Test {
- public:
+ protected:
void SetUp() override {
- list_gcs_bucket_ = test_controller_.getProcessor();
- gcp_credentials_node_ =
test_controller_.plan->addController("GCPCredentialsControllerService",
"gcp_credentials_controller_service");
- test_controller_.plan->setProperty(gcp_credentials_node_,
-
GCPCredentialsControllerService::CredentialsLoc,
-
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS));
- test_controller_.plan->setProperty(list_gcs_bucket_,
- ListGCSBucket::GCPCredentials,
- "gcp_credentials_controller_service");
+ const auto gcp_credential_controller_service =
+
minifi::test::utils::make_custom_c_controller_service<GCPCredentialsControllerService>(core::ControllerServiceMetadata{utils::Identifier{},
+ "GCPCredentialsControllerService",
+
logging::LoggerFactory<GCPCredentialsControllerService>::getLogger()});
+ gcp_credentials_node_ =
test_controller_.plan->addController("gcp_credentials_controller_service",
gcp_credential_controller_service);
+
EXPECT_TRUE(gcp_credential_controller_service->setProperty(GCPCredentialsControllerService::CredentialsLoc.name,
+
std::string(magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS))));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(ListGCSBucketMocked::GCPCredentials.name,
"gcp_credentials_controller_service"));
}
- org::apache::nifi::minifi::test::SingleProcessorTestController
test_controller_{minifi::test::utils::make_processor<ListGCSBucketMocked>("ListGCSBucketMocked")};
- TypedProcessorWrapper<ListGCSBucketMocked> list_gcs_bucket_;
- std::shared_ptr<minifi::core::controller::ControllerServiceNode>
gcp_credentials_node_;
+
+ public:
+ std::shared_ptr<gcs::testing::MockClient> mock_client_ =
std::make_shared<gcs::testing::MockClient>();
+ minifi::test::SingleProcessorTestController
test_controller_{minifi::test::utils::make_custom_c_processor<ListGCSBucketMocked>(
+ core::ProcessorMetadata{utils::Identifier{}, "ListGCSBucketMocked",
logging::LoggerFactory<ListGCSBucketMocked>::getLogger()}, mock_client_)};
+ std::shared_ptr<minifi::core::controller::ControllerServiceNode>
gcp_credentials_node_;
};
TEST_F(ListGCSBucketTests, MissingBucket) {
- EXPECT_CALL(*list_gcs_bucket_.get().mock_client_,
CreateResumableUpload).Times(0);
+ EXPECT_CALL(*mock_client_, CreateResumableUpload).Times(0);
EXPECT_THROW(test_controller_.trigger(), std::runtime_error);
}
TEST_F(ListGCSBucketTests, ServerGivesPermaError) {
- auto return_permanent_error = [](ListObjectsRequest const&) {
- return google::cloud::StatusOr<ListObjectsResponse>(PermanentError());
- };
- EXPECT_CALL(*list_gcs_bucket_.get().mock_client_, ListObjects)
- .WillOnce(return_permanent_error);
- EXPECT_TRUE(test_controller_.plan->setProperty(list_gcs_bucket_,
ListGCSBucket::Bucket, "bucket-from-property"));
+ auto return_permanent_error = [](ListObjectsRequest const&) { return
google::cloud::StatusOr<ListObjectsResponse>(PermanentError()); };
+ EXPECT_CALL(*mock_client_, ListObjects).WillOnce(return_permanent_error);
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(ListGCSBucket::Bucket.name,
"bucket-from-property"));
const auto& result = test_controller_.trigger();
EXPECT_EQ(0, result.at(ListGCSBucket::Success).size());
}
@@ -100,15 +102,15 @@ TEST_F(ListGCSBucketTests, ServerGivesTransientErrors) {
auto return_temp_error = [](ListObjectsRequest const&) {
return google::cloud::StatusOr<ListObjectsResponse>(TransientError());
};
- EXPECT_CALL(*list_gcs_bucket_.get().mock_client_,
ListObjects).WillOnce(return_temp_error);
- EXPECT_TRUE(test_controller_.plan->setProperty(list_gcs_bucket_,
ListGCSBucket::NumberOfRetries, "1"));
- EXPECT_TRUE(test_controller_.plan->setProperty(list_gcs_bucket_,
ListGCSBucket::Bucket, "bucket-from-property"));
+ EXPECT_CALL(*mock_client_, ListObjects).WillOnce(return_temp_error);
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(ListGCSBucket::NumberOfRetries.name,
"1"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(ListGCSBucket::Bucket.name,
"bucket-from-property"));
const auto& result = test_controller_.trigger();
EXPECT_EQ(0, result.at(ListGCSBucket::Success).size());
}
TEST_F(ListGCSBucketTests, WithoutVersions) {
- EXPECT_CALL(*list_gcs_bucket_.get().mock_client_, ListObjects)
+ EXPECT_CALL(*mock_client_, ListObjects)
.WillOnce([](ListObjectsRequest const& req)
-> google::cloud::StatusOr<ListObjectsResponse> {
EXPECT_EQ("bucket-from-property", req.bucket_name());
@@ -121,14 +123,13 @@ TEST_F(ListGCSBucketTests, WithoutVersions) {
response.items.emplace_back(CreateObject(1, 3));
return response;
});
- EXPECT_TRUE(test_controller_.plan->setProperty(list_gcs_bucket_,
ListGCSBucket::Bucket, "bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(ListGCSBucket::Bucket.name,
"bucket-from-property"));
const auto& result = test_controller_.trigger();
EXPECT_EQ(3, result.at(ListGCSBucket::Success).size());
}
-
TEST_F(ListGCSBucketTests, WithVersions) {
- EXPECT_CALL(*list_gcs_bucket_.get().mock_client_, ListObjects)
+ EXPECT_CALL(*mock_client_, ListObjects)
.WillOnce([](ListObjectsRequest const& req)
-> google::cloud::StatusOr<ListObjectsResponse> {
EXPECT_EQ("bucket-from-property", req.bucket_name());
@@ -141,9 +142,8 @@ TEST_F(ListGCSBucketTests, WithVersions) {
response.items.emplace_back(CreateObject(3));
return response;
});
- EXPECT_TRUE(test_controller_.plan->setProperty(list_gcs_bucket_,
ListGCSBucket::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(list_gcs_bucket_,
ListGCSBucket::ListAllVersions, "true"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(ListGCSBucket::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(ListGCSBucket::ListAllVersions.name,
"true"));
const auto& result = test_controller_.trigger();
EXPECT_EQ(3, result.at(ListGCSBucket::Success).size());
}
-
diff --git a/extensions/gcp/tests/PutGCSObjectTests.cpp
b/extensions/gcp/tests/PutGCSObjectTests.cpp
index a8355b50f..01b58104e 100644
--- a/extensions/gcp/tests/PutGCSObjectTests.cpp
+++ b/extensions/gcp/tests/PutGCSObjectTests.cpp
@@ -14,56 +14,59 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "../processors/PutGCSObject.h"
#include "../controllerservices/GCPCredentialsControllerService.h"
+#include "../processors/PutGCSObject.h"
+#include "CProcessorTestUtils.h"
#include "GCPAttributes.h"
#include "core/Resource.h"
-#include "unit/SingleProcessorTestController.h"
-#include "google/cloud/storage/testing/mock_client.h"
#include "google/cloud/storage/internal/object_metadata_parser.h"
-#include "google/cloud/storage/retry_policy.h"
#include "google/cloud/storage/testing/canonical_errors.h"
+#include "google/cloud/storage/testing/mock_client.h"
#include "unit/ProcessorUtils.h"
+#include "unit/SingleProcessorTestController.h"
namespace gcs = ::google::cloud::storage;
-namespace minifi_gcp = org::apache::nifi::minifi::extensions::gcp;
+namespace minifi_gcp = minifi::extensions::gcp;
-using PutGCSObject = org::apache::nifi::minifi::extensions::gcp::PutGCSObject;
-using GCPCredentialsControllerService =
org::apache::nifi::minifi::extensions::gcp::GCPCredentialsControllerService;
+using PutGCSObject = minifi::extensions::gcp::PutGCSObject;
+using GCPCredentialsControllerService =
minifi::extensions::gcp::GCPCredentialsControllerService;
using ResumableUploadRequest = gcs::internal::ResumableUploadRequest;
using QueryResumableUploadResponse =
gcs::internal::QueryResumableUploadResponse;
-using ::google::cloud::storage::testing::canonical_errors::TransientError;
using ::google::cloud::storage::testing::canonical_errors::PermanentError;
+using ::google::cloud::storage::testing::canonical_errors::TransientError;
namespace {
class PutGCSObjectMocked : public PutGCSObject {
- using org::apache::nifi::minifi::extensions::gcp::PutGCSObject::PutGCSObject;
+ using PutGCSObject::PutGCSObject;
+
public:
- static constexpr const char* Description = "PutGCSObjectMocked";
+ PutGCSObjectMocked(minifi::core::ProcessorMetadata metadata,
std::shared_ptr<gcs::testing::MockClient> mock_client)
+ : PutGCSObject(std::move(metadata)),
+ mock_client_(std::move(mock_client)) {}
- gcs::Client getClient() const override {
- return gcs::testing::UndecoratedClientFromMock(mock_client_);
- }
- std::shared_ptr<gcs::testing::MockClient> mock_client_ =
std::make_shared<gcs::testing::MockClient>();
+ protected:
+ gcs::Client getClient() const override { return
gcs::testing::UndecoratedClientFromMock(mock_client_); }
+ std::shared_ptr<gcs::testing::MockClient> mock_client_;
};
-REGISTER_RESOURCE(PutGCSObjectMocked, Processor);
} // namespace
class PutGCSObjectTests : public ::testing::Test {
- public:
+ protected:
void SetUp() override {
- put_gcs_object_ = test_controller_.getProcessor();
- gcp_credentials_node_ =
test_controller_.plan->addController("GCPCredentialsControllerService",
"gcp_credentials_controller_service");
- test_controller_.plan->setProperty(gcp_credentials_node_,
-
GCPCredentialsControllerService::CredentialsLoc,
-
magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS));
- test_controller_.plan->setProperty(put_gcs_object_,
- PutGCSObject::GCPCredentials,
- "gcp_credentials_controller_service");
+ const auto gcp_credential_controller_service =
+
minifi::test::utils::make_custom_c_controller_service<GCPCredentialsControllerService>(core::ControllerServiceMetadata{utils::Identifier{},
+ "GCPCredentialsControllerService",
+
logging::LoggerFactory<GCPCredentialsControllerService>::getLogger()});
+ gcp_credentials_node_ =
test_controller_.plan->addController("gcp_credentials_controller_service",
gcp_credential_controller_service);
+
EXPECT_TRUE(gcp_credential_controller_service->setProperty(GCPCredentialsControllerService::CredentialsLoc.name,
+
std::string(magic_enum::enum_name(minifi_gcp::CredentialsLocation::USE_ANONYMOUS_CREDENTIALS))));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObjectMocked::GCPCredentials.name,
"gcp_credentials_controller_service"));
}
- TypedProcessorWrapper<PutGCSObjectMocked> put_gcs_object_;
- org::apache::nifi::minifi::test::SingleProcessorTestController
test_controller_{minifi::test::utils::make_processor<PutGCSObjectMocked>("PutGCSObjectMocked")};
- std::shared_ptr<minifi::core::controller::ControllerServiceNode>
gcp_credentials_node_;
+
+ std::shared_ptr<gcs::testing::MockClient> mock_client_ =
std::make_shared<gcs::testing::MockClient>();
+ minifi::test::SingleProcessorTestController
test_controller_{minifi::test::utils::make_custom_c_processor<PutGCSObjectMocked>(
+ core::ProcessorMetadata{utils::Identifier{}, "PutGCSObjectMocked",
logging::LoggerFactory<PutGCSObjectMocked>::getLogger()}, mock_client_)};
+ std::shared_ptr<minifi::core::controller::ControllerServiceNode>
gcp_credentials_node_;
static auto return_upload_done(const ResumableUploadRequest& request) {
using ObjectMetadataParser = gcs::internal::ObjectMetadataParser;
@@ -75,13 +78,14 @@ class PutGCSObjectTests : public ::testing::Test {
metadata_json["customerEncryption"]["encryptionAlgorithm"] = "AES256";
metadata_json["customerEncryption"]["keySha256"] =
"zkeXIcAB56dkHp0z1023TQZ+mzm+fZ5JRVgmAQ3bEVE=";
}
- return
testing::Return(google::cloud::make_status_or(QueryResumableUploadResponse{absl::nullopt,
*ObjectMetadataParser::FromJson(metadata_json)}));
+ return
testing::Return(google::cloud::make_status_or(QueryResumableUploadResponse{absl::nullopt,
+ *ObjectMetadataParser::FromJson(metadata_json)}));
}
};
TEST_F(PutGCSObjectTests, MissingBucket) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
CreateResumableUpload).Times(0);
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, ""));
+ EXPECT_CALL(*mock_client_, CreateResumableUpload).Times(0);
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
""));
const auto& result = test_controller_.trigger("hello world");
EXPECT_EQ(0, result.at(PutGCSObject::Success).size());
ASSERT_EQ(1, result.at(PutGCSObject::Failure).size());
@@ -91,13 +95,13 @@ TEST_F(PutGCSObjectTests, MissingBucket) {
}
TEST_F(PutGCSObjectTests, BucketFromAttribute) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_, CreateResumableUpload)
+ EXPECT_CALL(*mock_client_, CreateResumableUpload)
.WillOnce([this](const ResumableUploadRequest& request) {
EXPECT_EQ("bucket-from-attribute", request.bucket_name());
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
+ EXPECT_CALL(*mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
return
gcs::internal::CreateResumableUploadResponse{"test-only-upload-id"};
});
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "${gcs.bucket}"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"${gcs.bucket}"));
const auto& result = test_controller_.trigger("hello world",
{{std::string(minifi_gcp::GCS_BUCKET_ATTR), "bucket-from-attribute"}});
ASSERT_EQ(1, result.at(PutGCSObject::Success).size());
EXPECT_EQ(0, result.at(PutGCSObject::Failure).size());
@@ -105,10 +109,10 @@ TEST_F(PutGCSObjectTests, BucketFromAttribute) {
}
TEST_F(PutGCSObjectTests, ServerGivesTransientErrors) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
CreateResumableUpload).WillOnce(testing::Return(TransientError()));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::NumberOfRetries, "2"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
+ EXPECT_CALL(*mock_client_,
CreateResumableUpload).WillOnce(testing::Return(TransientError()));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::NumberOfRetries.name,
"2"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
const auto& result = test_controller_.trigger("hello world");
EXPECT_EQ(0, result.at(PutGCSObject::Success).size());
ASSERT_EQ(1, result.at(PutGCSObject::Failure).size());
@@ -118,9 +122,9 @@ TEST_F(PutGCSObjectTests, ServerGivesTransientErrors) {
}
TEST_F(PutGCSObjectTests, ServerGivesPermaError) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
CreateResumableUpload).WillOnce(testing::Return(PermanentError()));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
+ EXPECT_CALL(*mock_client_,
CreateResumableUpload).WillOnce(testing::Return(PermanentError()));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
const auto& result = test_controller_.trigger("hello world");
EXPECT_EQ(0, result.at(PutGCSObject::Success).size());
ASSERT_EQ(1, result.at(PutGCSObject::Failure).size());
@@ -130,51 +134,51 @@ TEST_F(PutGCSObjectTests, ServerGivesPermaError) {
}
TEST_F(PutGCSObjectTests, NonRequiredPropertiesAreMissing) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_, CreateResumableUpload)
+ EXPECT_CALL(*mock_client_, CreateResumableUpload)
.WillOnce([this](const ResumableUploadRequest& request) {
EXPECT_FALSE(request.HasOption<gcs::MD5HashValue>());
EXPECT_FALSE(request.HasOption<gcs::Crc32cChecksumValue>());
EXPECT_FALSE(request.HasOption<gcs::PredefinedAcl>());
EXPECT_FALSE(request.HasOption<gcs::IfGenerationMatch>());
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
+ EXPECT_CALL(*mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
return
gcs::internal::CreateResumableUploadResponse{"test-only-upload-id"};
});
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
const auto& result = test_controller_.trigger("hello world");
EXPECT_EQ(1, result.at(PutGCSObject::Success).size());
EXPECT_EQ(0, result.at(PutGCSObject::Failure).size());
}
TEST_F(PutGCSObjectTests, Crc32cMD5LocationTest) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_, CreateResumableUpload)
+ EXPECT_CALL(*mock_client_, CreateResumableUpload)
.WillOnce([this](const ResumableUploadRequest& request) {
EXPECT_TRUE(request.HasOption<gcs::Crc32cChecksumValue>());
EXPECT_EQ("yZRlqg==",
request.GetOption<gcs::Crc32cChecksumValue>().value());
EXPECT_TRUE(request.HasOption<gcs::MD5HashValue>());
EXPECT_EQ("XrY7u+Ae7tCTyyK7j1rNww==",
request.GetOption<gcs::MD5HashValue>().value());
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
+ EXPECT_CALL(*mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
return
gcs::internal::CreateResumableUploadResponse{"test-only-upload-id"};
});
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::MD5Hash, "${md5}"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Crc32cChecksum, "${crc32c}"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::MD5Hash.name,
"${md5}"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Crc32cChecksum.name,
"${crc32c}"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
const auto& result = test_controller_.trigger("hello world", {{"crc32c",
"yZRlqg=="}, {"md5", "XrY7u+Ae7tCTyyK7j1rNww=="}});
EXPECT_EQ(1, result.at(PutGCSObject::Success).size());
EXPECT_EQ(0, result.at(PutGCSObject::Failure).size());
}
TEST_F(PutGCSObjectTests, DontOverwriteTest) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_, CreateResumableUpload)
+ EXPECT_CALL(*mock_client_, CreateResumableUpload)
.WillOnce([this](const ResumableUploadRequest& request) {
EXPECT_TRUE(request.HasOption<gcs::IfGenerationMatch>());
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
+ EXPECT_CALL(*mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
return
gcs::internal::CreateResumableUploadResponse{"test-only-upload-id"};
});
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::OverwriteObject, "false"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::OverwriteObject.name,
"false"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
const auto& result = test_controller_.trigger("hello world", {{"crc32c",
"yZRlqg=="}, {"md5", "XrY7u+Ae7tCTyyK7j1rNww=="}});
ASSERT_EQ(1, result.at(PutGCSObject::Success).size());
EXPECT_EQ(0, result.at(PutGCSObject::Failure).size());
@@ -182,15 +186,15 @@ TEST_F(PutGCSObjectTests, DontOverwriteTest) {
}
TEST_F(PutGCSObjectTests, ValidServerSideEncryptionTest) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_, CreateResumableUpload)
+ EXPECT_CALL(*mock_client_, CreateResumableUpload)
.WillOnce([this](const ResumableUploadRequest& request) {
EXPECT_TRUE(request.HasOption<gcs::EncryptionKey>());
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
+ EXPECT_CALL(*mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
return
gcs::internal::CreateResumableUploadResponse{"test-only-upload-id"};
});
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::EncryptionKey, "ZW5jcnlwdGlvbl9rZXk="));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::EncryptionKey.name,
"ZW5jcnlwdGlvbl9rZXk="));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
const auto& result = test_controller_.trigger("hello world");
ASSERT_EQ(1, result.at(PutGCSObject::Success).size());
EXPECT_EQ(0, result.at(PutGCSObject::Failure).size());
@@ -200,22 +204,22 @@ TEST_F(PutGCSObjectTests, ValidServerSideEncryptionTest) {
}
TEST_F(PutGCSObjectTests, InvalidServerSideEncryptionTest) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
CreateResumableUpload).Times(0);
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::EncryptionKey, "not_base64_key"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
+ EXPECT_CALL(*mock_client_, CreateResumableUpload).Times(0);
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::EncryptionKey.name,
"not_base64_key"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
EXPECT_THROW(test_controller_.trigger("hello world"), minifi::Exception);
}
TEST_F(PutGCSObjectTests, NoContentType) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_, CreateResumableUpload)
+ EXPECT_CALL(*mock_client_, CreateResumableUpload)
.WillOnce([this](const ResumableUploadRequest& request) {
EXPECT_FALSE(request.HasOption<gcs::ContentType>());
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
+ EXPECT_CALL(*mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
return
gcs::internal::CreateResumableUploadResponse{"test-only-upload-id"};
});
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
const auto& result = test_controller_.trigger("hello world");
ASSERT_EQ(1, result.at(PutGCSObject::Success).size());
EXPECT_EQ(0, result.at(PutGCSObject::Failure).size());
@@ -223,15 +227,15 @@ TEST_F(PutGCSObjectTests, NoContentType) {
}
TEST_F(PutGCSObjectTests, ContentTypeFromAttribute) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_, CreateResumableUpload)
+ EXPECT_CALL(*mock_client_, CreateResumableUpload)
.WillOnce([this](const ResumableUploadRequest& request) {
EXPECT_TRUE(request.HasOption<gcs::ContentType>());
EXPECT_EQ("text/attribute",
request.GetOption<gcs::ContentType>().value());
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
+ EXPECT_CALL(*mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
return
gcs::internal::CreateResumableUploadResponse{"test-only-upload-id"};
});
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
const auto& result = test_controller_.trigger("hello world", {{"mime.type",
"text/attribute"}});
ASSERT_EQ(1, result.at(PutGCSObject::Success).size());
EXPECT_EQ(0, result.at(PutGCSObject::Failure).size());
@@ -239,16 +243,17 @@ TEST_F(PutGCSObjectTests, ContentTypeFromAttribute) {
}
TEST_F(PutGCSObjectTests, ObjectACLTest) {
- EXPECT_CALL(*put_gcs_object_.get().mock_client_, CreateResumableUpload)
+ EXPECT_CALL(*mock_client_, CreateResumableUpload)
.WillOnce([this](const ResumableUploadRequest& request) {
EXPECT_TRUE(request.HasOption<gcs::PredefinedAcl>());
EXPECT_EQ(gcs::PredefinedAcl::AuthenticatedRead().value(),
request.GetOption<gcs::PredefinedAcl>().value());
- EXPECT_CALL(*put_gcs_object_.get().mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
+ EXPECT_CALL(*mock_client_,
UploadChunk).WillOnce(return_upload_done(request));
return
gcs::internal::CreateResumableUploadResponse{"test-only-upload-id"};
});
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Bucket, "bucket-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::Key, "object-name-from-property"));
- EXPECT_TRUE(test_controller_.plan->setProperty(put_gcs_object_,
PutGCSObject::ObjectACL,
magic_enum::enum_name(minifi_gcp::put_gcs_object::PredefinedAcl::AUTHENTICATED_READ)));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Bucket.name,
"bucket-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::Key.name,
"object-name-from-property"));
+
EXPECT_TRUE(test_controller_.getProcessor()->setProperty(PutGCSObject::ObjectACL.name,
+
std::string(magic_enum::enum_name(minifi_gcp::put_gcs_object::PredefinedAcl::AUTHENTICATED_READ))));
const auto& result = test_controller_.trigger("hello world");
ASSERT_EQ(1, result.at(PutGCSObject::Success).size());
EXPECT_EQ(0, result.at(PutGCSObject::Failure).size());
diff --git a/extensions/kafka/KafkaProcessorBase.cpp
b/extensions/kafka/KafkaProcessorBase.cpp
index 02233edff..e4e224015 100644
--- a/extensions/kafka/KafkaProcessorBase.cpp
+++ b/extensions/kafka/KafkaProcessorBase.cpp
@@ -25,7 +25,7 @@
KafkaProcessorBase::KafkaProcessorBase(core::ProcessorMetadata metadata) : Proce
}
std::optional<api::utils::net::SslData>
KafkaProcessorBase::getSslData(api::core::ProcessContext& context) const {
- return context.getSslData(SSLContextService) | utils::toOptional();
+ return context.getSslData(SSLContextService).value_or(std::nullopt);
}
void
KafkaProcessorBase::setKafkaAuthenticationParameters(api::core::ProcessContext&
context, gsl::not_null<rd_kafka_conf_t*> config) { //
NOLINT(performance-unnecessary-value-param)
@@ -33,7 +33,7 @@ void
KafkaProcessorBase::setKafkaAuthenticationParameters(api::core::ProcessCont
utils::setKafkaConfigurationField(*config, "security.protocol",
std::string{magic_enum::enum_name(security_protocol_)});
logger_->log_debug("Kafka security.protocol [{}]",
magic_enum::enum_name(security_protocol_));
if (security_protocol_ == kafka::SecurityProtocolOption::ssl ||
security_protocol_ == kafka::SecurityProtocolOption::sasl_ssl) {
- if (auto ssl_data = context.getSslData(SSLContextService) |
utils::toOptional()) {
+ if (auto ssl_data = getSslData(context)) {
if (ssl_data->ca_loc.empty() && ssl_data->cert_loc.empty() &&
ssl_data->key_loc.empty() && ssl_data->key_pw.empty()) {
logger_->log_warn("Security protocol is set to {}, but no valid
security parameters are set in the properties or in the SSL Context Service.",
magic_enum::enum_name(security_protocol_));
diff --git a/extensions/kafka/rdkafka_utils.h b/extensions/kafka/rdkafka_utils.h
index 96d0d79fe..91f59deb8 100644
--- a/extensions/kafka/rdkafka_utils.h
+++ b/extensions/kafka/rdkafka_utils.h
@@ -25,6 +25,7 @@
#include "rdkafka.h"
#include "api/utils/Ssl.h"
#include "minifi-cpp/core/logging/Logger.h"
+#include "magic_enum/magic_enum.hpp"
namespace org::apache::nifi::minifi::utils {
diff --git a/libminifi/src/minifi-c.cpp b/libminifi/src/minifi-c.cpp
index 4cb3da553..220ec9513 100644
--- a/libminifi/src/minifi-c.cpp
+++ b/libminifi/src/minifi-c.cpp
@@ -25,6 +25,7 @@
#include "core/extension/ExtensionManager.h"
#include "minifi-cpp/Exception.h"
#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
+#include "minifi-cpp/controllers/ProxyConfigurationServiceInterface.h"
#include "minifi-cpp/core/Annotation.h"
#include "minifi-cpp/core/ClassLoader.h"
#include "minifi-cpp/core/ProcessContext.h"
@@ -180,6 +181,16 @@ class CControllerServiceFactory : public
minifi::core::controller::ControllerSer
minifi::utils::CControllerServiceClassDescription class_description_;
};
+MinifiProxyType minifiProxyType(const minifi::controllers::ProxyType&
proxy_type) {
+ switch (proxy_type) {
+ case minifi::controllers::ProxyType::DIRECT:
+ return MinifiProxyType::MINIFI_PROXY_TYPE_DIRECT;
+ case minifi::controllers::ProxyType::HTTP:
+ return MinifiProxyType::MINIFI_PROXY_TYPE_HTTP;
+ }
+ std::unreachable();
+}
+
} // namespace
namespace org::apache::nifi::minifi::utils {
@@ -578,9 +589,9 @@ MinifiStatus
MinifiControllerServiceContextGetProperty(MinifiControllerServiceCo
}
}
-MinifiStatus MinifiProcessContextGetControllerService(
+MinifiStatus MinifiProcessContextGetControllerServiceFromProperty(
MinifiProcessContext* process_context,
- const MinifiStringView controller_service_name,
+ const MinifiStringView property_name,
const MinifiStringView controller_service_type,
MinifiControllerService** controller_service_out) {
if (!controller_service_out) {
@@ -589,8 +600,10 @@ MinifiStatus MinifiProcessContextGetControllerService(
gsl_Assert(process_context != MINIFI_NULL);
const auto context =
reinterpret_cast<minifi::core::ProcessContext*>(process_context);
- const auto name_str = std::string{toStringView(controller_service_name)};
- const auto service_shared_ptr = context->getControllerService(name_str,
context->getProcessorInfo().getUUID());
+ const auto property_name_str = std::string{toStringView(property_name)};
+ const auto name_str = context->getProperty(property_name_str, nullptr);
+ if (!name_str) { return MINIFI_STATUS_PROPERTY_NOT_SET; }
+ const auto service_shared_ptr = context->getControllerService(*name_str,
context->getProcessorInfo().getUUID());
if (!service_shared_ptr) {
return MINIFI_STATUS_VALIDATION_FAILED;
}
@@ -645,4 +658,32 @@ MinifiStatus
MinifiProcessContextGetSslDataFromProperty(MinifiProcessContext* pr
}
+MinifiStatus
MinifiProcessContextGetProxyDataFromProperty(MinifiProcessContext*
process_context, MinifiStringView property_name,
+ void (*cb)(void* user_ctx, const MinifiProxyData* proxy_data), void*
user_ctx) {
+ gsl_Assert(process_context != MINIFI_NULL);
+ const auto context =
reinterpret_cast<minifi::core::ProcessContext*>(process_context);
+ const auto property_name_str = std::string{toStringView(property_name)};
+ const auto name_str = context->getProperty(property_name_str, nullptr);
+ if (!name_str) { return MINIFI_STATUS_PROPERTY_NOT_SET; }
+ const auto service_shared_ptr = context->getControllerService(*name_str,
context->getProcessorInfo().getUUID());
+ if (!service_shared_ptr) { return MINIFI_STATUS_VALIDATION_FAILED; }
+ if (const auto proxy_service =
dynamic_cast<minifi::controllers::ProxyConfigurationServiceInterface*>(service_shared_ptr.get()))
{
+ const std::string hostname = proxy_service->getHost();
+ const auto basic_auth_data = proxy_service->getProxyCredentials();
+ MinifiStringView username_holder = basic_auth_data ?
minifiStringView(basic_auth_data->username) : MinifiStringView{};
+ MinifiStringView password_holder = basic_auth_data ?
minifiStringView(basic_auth_data->password) : MinifiStringView{};
+
+ MinifiProxyData proxy_data{
+ .hostname = minifiStringView(hostname),
+ .port = proxy_service->getPort(),
+ .username = basic_auth_data ? &username_holder : nullptr,
+ .password = basic_auth_data ? &password_holder : nullptr,
+ .proxy_type = minifiProxyType(proxy_service->getProxyType()),
+ };
+ cb(user_ctx, &proxy_data);
+ return MINIFI_STATUS_SUCCESS;
+ }
+ return MINIFI_STATUS_VALIDATION_FAILED;
+}
+
} // extern "C"
diff --git a/minifi-api/include/minifi-c/minifi-c.h
b/minifi-api/include/minifi-c/minifi-c.h
index b885cd614..8294dd91f 100644
--- a/minifi-api/include/minifi-c/minifi-c.h
+++ b/minifi-api/include/minifi-c/minifi-c.h
@@ -45,6 +45,11 @@ extern "C" {
/// use MINIFI_SSL_CONTEXT_SERVICE_PROPERTY_TYPE in the type field of the
property definition (MinifiPropertyDefinition::type)
#define MINIFI_SSL_CONTEXT_SERVICE_PROPERTY_TYPE
"org.apache.nifi.minifi.controllers.SSLContextServiceInterface"
+/// To declare a processor property that expects an ProxyConfigurationService,
+/// use MINIFI_PROXY_CONFIGURATION_SERVICE_PROPERTY_TYPE in the type field of
the property definition (MinifiPropertyDefinition::type)
+#define MINIFI_PROXY_CONFIGURATION_SERVICE_PROPERTY_TYPE
"org.apache.nifi.minifi.controllers.ProxyConfigurationServiceInterface"
+
+
enum : uint32_t {
MINIFI_API_VERSION = 3
};
@@ -233,8 +238,8 @@ MinifiStatus
MinifiProcessContextGetProperty(MinifiProcessContext* context, Mini
void(*cb)(void* user_ctx,
MinifiStringView property_value), void* user_ctx);
MinifiBool MinifiProcessContextHasNonEmptyProperty(MinifiProcessContext*
context, MinifiStringView property_name);
-MinifiStatus MinifiProcessContextGetControllerService(
- MinifiProcessContext* process_context, MinifiStringView
controller_service_name, MinifiStringView controller_service_type,
MinifiControllerService** controller_service_out);
+MinifiStatus MinifiProcessContextGetControllerServiceFromProperty(
+ MinifiProcessContext* process_context, MinifiStringView property_name,
MinifiStringView controller_service_type, MinifiControllerService**
controller_service_out);
void MinifiProcessContextGetDynamicProperties(MinifiProcessContext* context,
MinifiFlowFile* minifi_flow_file,
void (*cb)(void* user_ctx, MinifiStringView dynamic_property_name,
MinifiStringView dynamic_property_value), void* user_ctx);
@@ -283,6 +288,22 @@ typedef struct MinifiSslData {
MinifiStatus MinifiProcessContextGetSslDataFromProperty(MinifiProcessContext*
process_context, MinifiStringView property_name,
void (*cb)(void* user_ctx, const MinifiSslData* ssl_data), void* user_ctx);
+typedef enum MinifiProxyType : uint8_t {
+ MINIFI_PROXY_TYPE_DIRECT,
+ MINIFI_PROXY_TYPE_HTTP
+} MinifiProxyType;
+
+typedef struct MinifiProxyData {
+ MinifiStringView hostname;
+ uint16_t port;
+ MinifiStringView* username;
+ MinifiStringView* password;
+ MinifiProxyType proxy_type;
+} MinifiProxyData;
+
+MinifiStatus
MinifiProcessContextGetProxyDataFromProperty(MinifiProcessContext*
process_context, MinifiStringView property_name,
+ void (*cb)(void* user_ctx, const MinifiProxyData* proxy_data), void*
user_ctx);
+
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
diff --git a/minifi-api/minifi-c-api.def b/minifi-api/minifi-c-api.def
index 0baa3063c..e74b9b9f1 100644
--- a/minifi-api/minifi-c-api.def
+++ b/minifi-api/minifi-c-api.def
@@ -4,7 +4,7 @@ EXPORTS
MinifiRegisterProcessor
MinifiRegisterControllerService
MinifiPublishedMetricsCreate
- MinifiProcessContextGetControllerService
+ MinifiProcessContextGetControllerServiceFromProperty
MinifiProcessContextGetProperty
MinifiProcessContextHasNonEmptyProperty
MinifiControllerServiceContextGetProperty
@@ -30,3 +30,4 @@ EXPORTS
MinifiProcessSessionGetFlowFileId
MinifiProcessContextGetDynamicProperties
MinifiProcessContextGetSslDataFromProperty
+ MinifiProcessContextGetProxyDataFromProperty