Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

MINIFICPP-2378 Add support for parameters in controller services #1868

Open
wants to merge 1 commit into
base: MINIFICPP-2377
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions extensions/standard-processors/tests/unit/FlowJsonTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1028,4 +1028,124 @@ TEST_CASE("NiFi flow json can use alternative targetUris field") {
REQUIRE(port->getProperty("Port UUID") == "00000000-0000-0000-0000-000000000005");
}


TEST_CASE("Test parameters in controller services") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_parameter_value = minifi::utils::crypto::property_encryption::encrypt("secret1!!1!", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value = minifi::utils::crypto::property_encryption::encrypt("#{my_value_1}", *context.sensitive_values_encryptor);
core::flow::AdaptiveConfiguration json_config(context);

static const std::string CONFIG_JSON =
fmt::format(R"(
{{
"parameterContexts": [
{{
"identifier": "721e10b7-8e00-3188-9a27-476cca376978",
"name": "my-context",
"description": "my parameter context",
"parameters": [
{{
"name": "my_value_1",
"description": "",
"sensitive": true,
"value": "{}"
}},
{{
"name": "my_value_2",
"description": "",
"sensitive": false,
"value": "/opt/secrets/private-key.pem"
}}
]
}}
],
"rootGroup": {{
"name": "MiNiFi Flow",
"processors": [],
"controllerServices": [{{
"identifier": "a00f8722-2419-44ee-929c-ad68644ad557",
"name": "SSLContextService",
"type": "org.apache.nifi.minifi.controllers.SSLContextService",
"properties": {{
"Passphrase": "{}",
"Private Key": "#{{my_value_2}}",
"Use System Cert Store": "true"
}}
}}],
"parameterContextName": "my-context"
}}
}})", encrypted_parameter_value, encrypted_sensitive_property_value);

std::unique_ptr<core::ProcessGroup> flow = json_config.getRootFromPayload(CONFIG_JSON);
REQUIRE(flow);
auto* controller = flow->findControllerService("SSLContextService");
REQUIRE(controller);
auto impl = controller->getControllerServiceImplementation();
CHECK(impl->getProperty("Passphrase").value() == "secret1!!1!");
CHECK(impl->getProperty("Private Key").value() == "/opt/secrets/private-key.pem");
}

TEST_CASE("Parameters can be used in controller services in nested process groups") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_parameter_value = minifi::utils::crypto::property_encryption::encrypt("secret1!!1!", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value = minifi::utils::crypto::property_encryption::encrypt("#{my_value_1}", *context.sensitive_values_encryptor);
core::flow::AdaptiveConfiguration json_config(context);

static const std::string CONFIG_JSON =
fmt::format(R"(
{{
"parameterContexts": [
{{
"identifier": "721e10b7-8e00-3188-9a27-476cca376978",
"name": "my-context",
"description": "my parameter context",
"parameters": [
{{
"name": "my_value_1",
"description": "",
"sensitive": true,
"value": "{}"
}},
{{
"name": "my_value_2",
"description": "",
"sensitive": false,
"value": "/opt/secrets/private-key.pem"
}}
]
}}
],
"rootGroup": {{
"name": "MiNiFi Flow",
"processors": [],
"processGroups": [{{
"name": "MiNiFi SubFlow",
"processors": [],
"controllerServices": [{{
"identifier": "a00f8722-2419-44ee-929c-ad68644ad557",
"name": "SSLContextService",
"type": "org.apache.nifi.minifi.controllers.SSLContextService",
"properties": {{
"Passphrase": "{}",
"Private Key": "#{{my_value_2}}",
"Use System Cert Store": "true"
}}
}}],
"parameterContextName": "my-context"
}}]
}}
}})", encrypted_parameter_value, encrypted_sensitive_property_value);

std::unique_ptr<core::ProcessGroup> flow = json_config.getRootFromPayload(CONFIG_JSON);
REQUIRE(flow);
auto* controller = flow->findControllerService("SSLContextService", core::ProcessGroup::Traverse::IncludeChildren);
REQUIRE(controller);
auto impl = controller->getControllerServiceImplementation();
REQUIRE(impl);
CHECK(impl->getProperty("Passphrase").value() == "secret1!!1!");
CHECK(impl->getProperty("Private Key").value() == "/opt/secrets/private-key.pem");
}

} // namespace org::apache::nifi::minifi::test
106 changes: 106 additions & 0 deletions extensions/standard-processors/tests/unit/YamlConfigurationTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1769,4 +1769,110 @@ Parameter Context Name: my-context
CHECK(values[1] == "value2");
}

TEST_CASE("Test parameters in controller services", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_parameter_value_1 = minifi::utils::crypto::property_encryption::encrypt("secret1!!1!", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value_1 = minifi::utils::crypto::property_encryption::encrypt("#{my_value_1}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);

static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: my_value_1
description: ''
sensitive: true
value: {}
- name: my_value_2
description: ''
sensitive: false
value: /opt/secrets/private-key.pem
Processors: []
Controller Services:
- id: a00f8722-2419-44ee-929c-ad68644ad557
name: SSLContextService
type: org.apache.nifi.minifi.controllers.SSLContextService
Properties:
CA Certificate:
Client Certificate:
Passphrase: {}
Private Key: "#{{my_value_2}}"
Use System Cert Store: 'true'
Parameter Context Name: my-context
)", encrypted_parameter_value_1, encrypted_sensitive_property_value_1);

std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* controller = flow->findControllerService("SSLContextService");
REQUIRE(controller);
auto impl = controller->getControllerServiceImplementation();
CHECK(impl->getProperty("Passphrase").value() == "secret1!!1!");
CHECK(impl->getProperty("Private Key").value() == "/opt/secrets/private-key.pem");
}

TEST_CASE("Parameters can be used in controller services in nested process groups", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_parameter_value_1 = minifi::utils::crypto::property_encryption::encrypt("secret1!!1!", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value_1 = minifi::utils::crypto::property_encryption::encrypt("#{my_value_1}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);

static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile
Parameter Contexts:
- id: 123e10b7-8e00-3188-9a27-476cca376456
name: sub-context
description: my sub context
Parameters:
- name: my_value_1
description: ''
sensitive: true
value: {}
- name: my_value_2
description: ''
sensitive: false
value: /opt/secrets/private-key.pem
Processors: []
Controller Services: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Process Groups:
- id: 2a3aaf32-8574-4fa7-b720-84001f8dde43
name: Sub process group
Processors: []
Controller Services:
- id: a00f8722-2419-44ee-929c-ad68644ad557
name: SSLContextService
type: org.apache.nifi.minifi.controllers.SSLContextService
Properties:
CA Certificate:
Client Certificate:
Passphrase: {}
Private Key: "#{{my_value_2}}"
Use System Cert Store: 'true'
Parameter Context Name: sub-context
)", encrypted_parameter_value_1, encrypted_sensitive_property_value_1);

std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* controller = flow->findControllerService("SSLContextService", core::ProcessGroup::Traverse::IncludeChildren);
REQUIRE(controller);
auto impl = controller->getControllerServiceImplementation();
REQUIRE(impl);
CHECK(impl->getProperty("Passphrase").value() == "secret1!!1!");
CHECK(impl->getProperty("Private Key").value() == "/opt/secrets/private-key.pem");
}

} // namespace org::apache::nifi::minifi::test
4 changes: 2 additions & 2 deletions libminifi/src/core/flow/StructuredConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,9 +540,9 @@ void StructuredConfiguration::parseControllerServices(const Node& controller_ser
controller_service_node->initialize();
if (Node propertiesNode = service_node[schema_.controller_service_properties]) {
// we should propagate properties to the node and to the implementation
parsePropertiesNode(propertiesNode, *controller_service_node, name, nullptr);
parsePropertiesNode(propertiesNode, *controller_service_node, name, parent_group->getParameterContext());
if (auto controllerServiceImpl = controller_service_node->getControllerServiceImplementation(); controllerServiceImpl) {
parsePropertiesNode(propertiesNode, *controllerServiceImpl, name, nullptr);
parsePropertiesNode(propertiesNode, *controllerServiceImpl, name, parent_group->getParameterContext());
}
}

Expand Down