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
commit 9f8dec516a4aacee35aff698aff0641f985cafd2 Author: Gabor Gyimesi <[email protected]> AuthorDate: Thu Apr 20 18:24:34 2023 +0200 MINIFICPP-2106 Add 'Use Path Style Access' property to PutS3Object Closes #1562 Signed-off-by: Marton Szasz <[email protected]> --- PROCESSORS.md | 3 ++- extensions/aws/processors/PutS3Object.cpp | 6 ++++++ extensions/aws/processors/PutS3Object.h | 5 ++++- extensions/aws/processors/S3ProcessorStaticDefinitions.cpp | 8 ++++++++ extensions/aws/s3/S3ClientRequestSender.cpp | 5 +++-- extensions/aws/s3/S3ClientRequestSender.h | 3 ++- extensions/aws/s3/S3RequestSender.h | 3 ++- extensions/aws/s3/S3Wrapper.cpp | 2 +- extensions/aws/s3/S3Wrapper.h | 1 + extensions/aws/tests/MockS3RequestSender.h | 9 ++++++++- extensions/aws/tests/PutS3ObjectTests.cpp | 9 +++++++++ 11 files changed, 46 insertions(+), 8 deletions(-) diff --git a/PROCESSORS.md b/PROCESSORS.md index 70de1ceed..1fe86736b 100644 --- a/PROCESSORS.md +++ b/PROCESSORS.md @@ -641,7 +641,7 @@ In the list below, the names of required properties appear in bold. Any other pr ### Description -ExecuteJavaClass runs NiFi processors given a provided system path +ExecuteJavaClass runs NiFi processors given a provided system path ### Properties @@ -2248,6 +2248,7 @@ In the list below, the names of required properties appear in bold. Any other pr | Read ACL User List | | [...] | Write ACL User List | | [...] | Canned ACL | | [...] +| **Use Path Style Access** | false | [...] ### Relationships diff --git a/extensions/aws/processors/PutS3Object.cpp b/extensions/aws/processors/PutS3Object.cpp index 22407b896..19b2bd693 100644 --- a/extensions/aws/processors/PutS3Object.cpp +++ b/extensions/aws/processors/PutS3Object.cpp @@ -73,6 +73,10 @@ void PutS3Object::onSchedule(const std::shared_ptr<core::ProcessContext> &contex } logger_->log_debug("PutS3Object: Server Side Encryption [%s]", server_side_encryption_); + if (auto use_path_style_access = context->getProperty<bool>(UsePathStyleAccess)) { + use_virtual_addressing_ = !*use_path_style_access; + } + fillUserMetadata(context); } @@ -152,6 +156,8 @@ std::optional<aws::s3::PutObjectRequestParameters> PutS3Object::buildPutS3Reques if (!setAccessControl(context, flow_file, params)) { return std::nullopt; } + + params.use_virtual_addressing = use_virtual_addressing_; return params; } diff --git a/extensions/aws/processors/PutS3Object.h b/extensions/aws/processors/PutS3Object.h index fd4c910ea..4763c6e2f 100644 --- a/extensions/aws/processors/PutS3Object.h +++ b/extensions/aws/processors/PutS3Object.h @@ -58,6 +58,7 @@ class PutS3Object : public S3Processor { static const core::Property ReadACLUserList; static const core::Property WriteACLUserList; static const core::Property CannedACL; + static const core::Property UsePathStyleAccess; static auto properties() { return minifi::utils::array_cat(S3Processor::properties(), std::array{ ObjectKey, @@ -68,7 +69,8 @@ class PutS3Object : public S3Processor { ReadPermissionUserList, ReadACLUserList, WriteACLUserList, - CannedACL + CannedACL, + UsePathStyleAccess }); } @@ -161,6 +163,7 @@ class PutS3Object : public S3Processor { std::map<std::string, std::string> user_metadata_map_; std::string storage_class_; std::string server_side_encryption_; + bool use_virtual_addressing_ = true; }; } // namespace org::apache::nifi::minifi::aws::processors diff --git a/extensions/aws/processors/S3ProcessorStaticDefinitions.cpp b/extensions/aws/processors/S3ProcessorStaticDefinitions.cpp index f3abed5d1..b79910b08 100644 --- a/extensions/aws/processors/S3ProcessorStaticDefinitions.cpp +++ b/extensions/aws/processors/S3ProcessorStaticDefinitions.cpp @@ -265,6 +265,14 @@ const core::Property PutS3Object::ServerSideEncryption( ->withAllowableValues<std::string>(PutS3Object::SERVER_SIDE_ENCRYPTIONS) ->withDescription("Specifies the algorithm used for server side encryption.") ->build()); +const core::Property PutS3Object::UsePathStyleAccess( + core::PropertyBuilder::createProperty("Use Path Style Access") + ->withDescription("Path-style access can be enforced by setting this property to true. Set it to true if your endpoint does not support " + "virtual-hosted-style requests, only path-style requests.") + ->withDefaultValue<bool>(false) + ->isRequired(true) + ->build()); + const core::Relationship PutS3Object::Success("success", "FlowFiles are routed to success relationship"); const core::Relationship PutS3Object::Failure("failure", "FlowFiles are routed to failure relationship"); diff --git a/extensions/aws/s3/S3ClientRequestSender.cpp b/extensions/aws/s3/S3ClientRequestSender.cpp index d24322e41..e95e57556 100644 --- a/extensions/aws/s3/S3ClientRequestSender.cpp +++ b/extensions/aws/s3/S3ClientRequestSender.cpp @@ -26,8 +26,9 @@ namespace org::apache::nifi::minifi::aws::s3 { std::optional<Aws::S3::Model::PutObjectResult> S3ClientRequestSender::sendPutObjectRequest( const Aws::S3::Model::PutObjectRequest& request, const Aws::Auth::AWSCredentials& credentials, - const Aws::Client::ClientConfiguration& client_config) { - Aws::S3::S3Client s3_client(credentials, client_config, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, true); + const Aws::Client::ClientConfiguration& client_config, + bool use_virtual_addressing) { + Aws::S3::S3Client s3_client(credentials, client_config, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, use_virtual_addressing); auto outcome = s3_client.PutObject(request); if (outcome.IsSuccess()) { diff --git a/extensions/aws/s3/S3ClientRequestSender.h b/extensions/aws/s3/S3ClientRequestSender.h index 769d7c6d1..904024b49 100644 --- a/extensions/aws/s3/S3ClientRequestSender.h +++ b/extensions/aws/s3/S3ClientRequestSender.h @@ -30,7 +30,8 @@ class S3ClientRequestSender : public S3RequestSender { std::optional<Aws::S3::Model::PutObjectResult> sendPutObjectRequest( const Aws::S3::Model::PutObjectRequest& request, const Aws::Auth::AWSCredentials& credentials, - const Aws::Client::ClientConfiguration& client_config) override; + const Aws::Client::ClientConfiguration& client_config, + bool use_virtual_addressing) override; bool sendDeleteObjectRequest( const Aws::S3::Model::DeleteObjectRequest& request, const Aws::Auth::AWSCredentials& credentials, diff --git a/extensions/aws/s3/S3RequestSender.h b/extensions/aws/s3/S3RequestSender.h index dd8f04375..c0cce8fee 100644 --- a/extensions/aws/s3/S3RequestSender.h +++ b/extensions/aws/s3/S3RequestSender.h @@ -62,7 +62,8 @@ class S3RequestSender { virtual std::optional<Aws::S3::Model::PutObjectResult> sendPutObjectRequest( const Aws::S3::Model::PutObjectRequest& request, const Aws::Auth::AWSCredentials& credentials, - const Aws::Client::ClientConfiguration& client_config) = 0; + const Aws::Client::ClientConfiguration& client_config, + bool use_virtual_addressing) = 0; virtual bool sendDeleteObjectRequest( const Aws::S3::Model::DeleteObjectRequest& request, const Aws::Auth::AWSCredentials& credentials, diff --git a/extensions/aws/s3/S3Wrapper.cpp b/extensions/aws/s3/S3Wrapper.cpp index dab76976f..ca3aa13e5 100644 --- a/extensions/aws/s3/S3Wrapper.cpp +++ b/extensions/aws/s3/S3Wrapper.cpp @@ -90,7 +90,7 @@ std::optional<PutObjectResult> S3Wrapper::putObject(const PutObjectRequestParame request.SetGrantWriteACP(put_object_params.write_acl_user_list); setCannedAcl(request, put_object_params.canned_acl); - auto aws_result = request_sender_->sendPutObjectRequest(request, put_object_params.credentials, put_object_params.client_config); + auto aws_result = request_sender_->sendPutObjectRequest(request, put_object_params.credentials, put_object_params.client_config, put_object_params.use_virtual_addressing); if (!aws_result) { return std::nullopt; } diff --git a/extensions/aws/s3/S3Wrapper.h b/extensions/aws/s3/S3Wrapper.h index 038d0d029..a622d5e72 100644 --- a/extensions/aws/s3/S3Wrapper.h +++ b/extensions/aws/s3/S3Wrapper.h @@ -126,6 +126,7 @@ struct PutObjectRequestParameters : public RequestParameters { std::string read_acl_user_list; std::string write_acl_user_list; std::string canned_acl; + bool use_virtual_addressing = true; }; struct DeleteObjectRequestParameters : public RequestParameters { diff --git a/extensions/aws/tests/MockS3RequestSender.h b/extensions/aws/tests/MockS3RequestSender.h index 6e4c4b6aa..19e3a0fb6 100644 --- a/extensions/aws/tests/MockS3RequestSender.h +++ b/extensions/aws/tests/MockS3RequestSender.h @@ -94,10 +94,12 @@ class MockS3RequestSender : public minifi::aws::s3::S3RequestSender { std::optional<Aws::S3::Model::PutObjectResult> sendPutObjectRequest( const Aws::S3::Model::PutObjectRequest& request, const Aws::Auth::AWSCredentials& credentials, - const Aws::Client::ClientConfiguration& client_config) override { + const Aws::Client::ClientConfiguration& client_config, + bool use_virtual_addressing) override { put_object_request = request; credentials_ = credentials; client_config_ = client_config; + use_virtual_addressing_ = use_virtual_addressing; Aws::S3::Model::PutObjectResult put_s3_result; if (!return_empty_result_) { @@ -250,6 +252,10 @@ class MockS3RequestSender : public minifi::aws::s3::S3RequestSender { return client_config_; } + bool getUseVirtualAddressing() const { + return use_virtual_addressing_; + } + std::string getPutObjectRequestBody() const { std::istreambuf_iterator<char> buf_it; return std::string(std::istreambuf_iterator<char>(*put_object_request.GetBody()), buf_it); @@ -291,4 +297,5 @@ class MockS3RequestSender : public minifi::aws::s3::S3RequestSender { bool is_listing_truncated_ = false; Aws::Auth::AWSCredentials credentials_; Aws::Client::ClientConfiguration client_config_; + bool use_virtual_addressing_ = true; }; diff --git a/extensions/aws/tests/PutS3ObjectTests.cpp b/extensions/aws/tests/PutS3ObjectTests.cpp index 884bfc7e7..66525c71c 100644 --- a/extensions/aws/tests/PutS3ObjectTests.cpp +++ b/extensions/aws/tests/PutS3ObjectTests.cpp @@ -136,6 +136,7 @@ TEST_CASE_METHOD(PutS3ObjectTestsFixture, "Check default client configuration", REQUIRE(mock_s3_request_sender_ptr->getClientConfig().proxyUserName.empty()); REQUIRE(mock_s3_request_sender_ptr->getClientConfig().proxyPassword.empty()); REQUIRE(mock_s3_request_sender_ptr->getPutObjectRequestBody() == INPUT_DATA); + REQUIRE(mock_s3_request_sender_ptr->getUseVirtualAddressing()); } TEST_CASE_METHOD(PutS3ObjectTestsFixture, "Check default client configuration with empty result", "[awsS3ClientConfig]") { @@ -171,6 +172,7 @@ TEST_CASE_METHOD(PutS3ObjectTestsFixture, "Set non-default client configuration" REQUIRE(mock_s3_request_sender_ptr->getClientConfig().connectTimeoutMs == 10000); REQUIRE(mock_s3_request_sender_ptr->getClientConfig().endpointOverride == "http://localhost:1234"); REQUIRE(mock_s3_request_sender_ptr->getPutObjectRequestBody() == INPUT_DATA); + REQUIRE(mock_s3_request_sender_ptr->getUseVirtualAddressing()); } TEST_CASE_METHOD(PutS3ObjectTestsFixture, "Test single user metadata", "[awsS3MetaData]") { @@ -218,4 +220,11 @@ TEST_CASE_METHOD(PutS3ObjectTestsFixture, "Test access control setting", "[awsS3 REQUIRE(mock_s3_request_sender_ptr->put_object_request.GetACL() == Aws::S3::Model::ObjectCannedACL::public_read_write); } +TEST_CASE_METHOD(PutS3ObjectTestsFixture, "Test path style access property", "[awsS3PathStyleAccess]") { + setRequiredProperties(); + plan->setProperty(s3_processor, "Use Path Style Access", "true"); + test_controller.runSession(plan, true); + REQUIRE(!mock_s3_request_sender_ptr->getUseVirtualAddressing()); +} + } // namespace
