Skip to content

Commit

Permalink
MINIFICPP-2378 Add support for parameters in controller services
Browse files Browse the repository at this point in the history
  • Loading branch information
lordgamez committed Oct 30, 2024
1 parent 35985ad commit ceb83b8
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 2 deletions.
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

0 comments on commit ceb83b8

Please sign in to comment.