Skip to content

Commit d4dab97

Browse files
lordgamezszaszm
authored andcommitted
MINIFICPP-2684 Move MiNiFi controller tests to modular docker tests
Closes apache#2078 Signed-off-by: Marton Szasz <[email protected]>
1 parent bc9a9ea commit d4dab97

File tree

14 files changed

+190
-335
lines changed

14 files changed

+190
-335
lines changed

behave_framework/src/minifi_test_framework/containers/container.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ def verify_file_contents(self, directory_path: str, expected_contents: list[str]
363363
if not self.container:
364364
return False
365365

366+
self.container.reload()
366367
if self.container.status == "running":
367368
return self._verify_file_contents_in_running_container(directory_path, expected_contents)
368369

behave_framework/src/minifi_test_framework/containers/minifi_container.py

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@
1616
#
1717

1818
import logging
19+
import os
20+
from pathlib import Path
1921
from OpenSSL import crypto
2022

2123
from minifi_test_framework.core.minifi_test_context import MinifiTestContext
2224
from minifi_test_framework.containers.file import File
25+
from minifi_test_framework.containers.host_file import HostFile
2326
from minifi_test_framework.minifi.minifi_flow_definition import MinifiFlowDefinition
2427
from minifi_test_framework.core.ssl_utils import make_cert_without_extended_usage, make_client_cert, make_server_cert
28+
from minifi_test_framework.core.helpers import wait_for_condition, retry_check
2529
from .container import Container
2630

2731

@@ -47,6 +51,10 @@ def __init__(self, container_name: str, test_context: MinifiTestContext):
4751
crypto.dump_certificate(type=crypto.FILETYPE_PEM, cert=minifi_server_cert) + crypto.dump_privatekey(type=crypto.FILETYPE_PEM, pkey=minifi_server_key)))
4852

4953
self.is_fhs = 'MINIFI_INSTALLATION_TYPE=FHS' in str(self.client.images.get(test_context.minifi_container_image).history())
54+
if self.is_fhs:
55+
self.minifi_controller_path = '/usr/bin/minifi-controller'
56+
else:
57+
self.minifi_controller_path = '/opt/minifi/minifi-current/bin/minifi-controller'
5058

5159
self._fill_default_properties()
5260
self._fill_default_log_properties()
@@ -66,7 +74,18 @@ def deploy(self) -> bool:
6674
self.files.append(File("/opt/minifi/minifi-current/conf/minifi-log.properties",
6775
self._get_log_properties_file_content()))
6876

69-
return super().deploy()
77+
resource_dir = Path(__file__).resolve().parent / "resources" / "minifi-controller"
78+
self.host_files.append(HostFile("/tmp/resources/minifi-controller/config.yml", os.path.join(resource_dir, "config.yml")))
79+
80+
if not super().deploy():
81+
return False
82+
83+
finished_str = "MiNiFi started"
84+
return wait_for_condition(
85+
condition=lambda: finished_str in self.get_logs(),
86+
timeout_seconds=15,
87+
bail_condition=lambda: self.exited,
88+
context=None)
7089

7190
def set_property(self, key: str, value: str):
7291
self.properties[key] = value
@@ -111,3 +130,74 @@ def get_memory_usage(self) -> int | None:
111130
memory_usage_in_bytes = int(output.strip()) * 1024
112131
logging.info(f"MiNiFi memory usage: {memory_usage_in_bytes} bytes")
113132
return memory_usage_in_bytes
133+
134+
def set_controller_socket_properties(self):
135+
self.properties["controller.socket.enable"] = "true"
136+
self.properties["controller.socket.host"] = "localhost"
137+
self.properties["controller.socket.port"] = "9998"
138+
self.properties["controller.socket.local.any.interface"] = "false"
139+
140+
def update_flow_config_through_controller(self):
141+
self.exec_run([self.minifi_controller_path, "--updateflow", "/tmp/resources/minifi-controller/config.yml"])
142+
143+
def updated_config_is_persisted(self) -> bool:
144+
exit_code, output = self.exec_run(["cat", "/opt/minifi/minifi-current/conf/config.yml" if not self.is_fhs else "/etc/nifi-minifi-cpp/config.yml"])
145+
if exit_code != 0:
146+
logging.error("Failed to read MiNiFi config file to check if updated config is persisted")
147+
return False
148+
return "2f2a3b47-f5ba-49f6-82b5-bc1c86b96f38" in output
149+
150+
def stop_component_through_controller(self, component: str):
151+
self.exec_run([self.minifi_controller_path, "--stop", component])
152+
153+
def start_component_through_controller(self, component: str):
154+
self.exec_run([self.minifi_controller_path, "--start", component])
155+
156+
@retry_check(10, 1)
157+
def is_component_running(self, component: str) -> bool:
158+
(code, output) = self.exec_run([self.minifi_controller_path, "--list", "components"])
159+
return code == 0 and component + ", running: true" in output
160+
161+
def get_connections(self):
162+
(_, output) = self.exec_run([self.minifi_controller_path, "--list", "connections"])
163+
connections = []
164+
for line in output.split('\n'):
165+
if not line.startswith('[') and not line.startswith('Connection Names'):
166+
connections.append(line)
167+
return connections
168+
169+
@retry_check(10, 1)
170+
def connection_found_through_controller(self, connection: str) -> bool:
171+
return connection in self.get_connections()
172+
173+
def get_full_connection_count(self) -> int:
174+
(_, output) = self.exec_run([self.minifi_controller_path, "--getfull"])
175+
for line in output.split('\n'):
176+
if "are full" in line:
177+
return int(line.split(' ')[0])
178+
return -1
179+
180+
def get_connection_size(self, connection: str):
181+
(_, output) = self.exec_run([self.minifi_controller_path, "--getsize", connection])
182+
for line in output.split('\n'):
183+
if "Size/Max of " + connection in line:
184+
size_and_max = line.split(connection)[1].split('/')
185+
return (int(size_and_max[0].strip()), int(size_and_max[1].strip()))
186+
return (-1, -1)
187+
188+
def get_manifest(self) -> str:
189+
(_, output) = self.exec_run([self.minifi_controller_path, "--manifest"])
190+
manifest = ""
191+
for line in output.split('\n'):
192+
if not line.startswith('['):
193+
manifest += line
194+
return manifest
195+
196+
def create_debug_bundle(self) -> bool:
197+
(code, _) = self.exec_run([self.minifi_controller_path, "--debug", "/tmp"])
198+
if code != 0:
199+
logging.error("Minifi controller debug command failed with code: %d", code)
200+
return False
201+
202+
(code, _) = self.exec_run(["test", "-f", "/tmp/debug.tar.gz"])
203+
return code == 0

docker/test/integration/resources/minifi-controller/config.yml renamed to behave_framework/src/minifi_test_framework/containers/resources/minifi-controller/config.yml

File renamed without changes.

docker/test/integration/cluster/ContainerStore.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,6 @@ def set_yaml_in_minifi(self):
273273
def set_json_in_minifi(self):
274274
self.minifi_options.config_format = "json"
275275

276-
def set_controller_socket_properties_in_minifi(self):
277-
self.minifi_options.enable_controller_socket = True
278-
279276
def enable_log_metrics_publisher_in_minifi(self):
280277
self.minifi_options.enable_log_metrics_publisher = True
281278

docker/test/integration/cluster/DockerCommunicator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def get_app_log_from_docker_container(self, container_name):
5454
logging.warning('Container segfaulted: %s', container.name)
5555
self.segfault = True
5656

57+
container.reload()
5758
return container.status, container.logs()
5859

5960
def __put_archive(self, container_name, path, data):

docker/test/integration/cluster/DockerTestCluster.py

Lines changed: 1 addition & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,16 @@
1515
import logging
1616
import time
1717
import re
18-
import tarfile
19-
import tempfile
20-
import os
21-
import gzip
22-
import shutil
2318

2419
from .LogSource import LogSource
2520
from .ContainerStore import ContainerStore
2621
from .DockerCommunicator import DockerCommunicator
27-
from .MinifiControllerExecutor import MinifiControllerExecutor
2822
from .checkers.AzureChecker import AzureChecker
2923
from .checkers.PostgresChecker import PostgresChecker
3024
from .checkers.PrometheusChecker import PrometheusChecker
3125
from .checkers.ModbusChecker import ModbusChecker
3226
from .checkers.MqttHelper import MqttHelper
33-
from utils import get_peak_memory_usage, get_minifi_pid, get_memory_usage, retry_check
27+
from utils import get_peak_memory_usage, get_minifi_pid, get_memory_usage
3428

3529

3630
class DockerTestCluster:
@@ -42,7 +36,6 @@ def __init__(self, context, feature_id):
4236
self.azure_checker = AzureChecker(self.container_communicator)
4337
self.postgres_checker = PostgresChecker(self.container_communicator)
4438
self.prometheus_checker = PrometheusChecker()
45-
self.minifi_controller_executor = MinifiControllerExecutor(self.container_communicator)
4639
self.modbus_checker = ModbusChecker(self.container_communicator)
4740
self.mqtt_helper = MqttHelper()
4841

@@ -124,9 +117,6 @@ def set_yaml_in_minifi(self):
124117
def set_json_in_minifi(self):
125118
self.container_store.set_json_in_minifi()
126119

127-
def set_controller_socket_properties_in_minifi(self):
128-
self.container_store.set_controller_socket_properties_in_minifi()
129-
130120
def enable_log_metrics_publisher_in_minifi(self):
131121
self.container_store.enable_log_metrics_publisher_in_minifi()
132122

@@ -283,78 +273,6 @@ def wait_for_memory_usage_to_drop_below(self, max_memory_usage: int, timeout_sec
283273
logging.warning(f"Memory usage ({current_memory_usage}) is more than the maximum asserted memory usage ({max_memory_usage})")
284274
return False
285275

286-
def update_flow_config_through_controller(self, container_name: str):
287-
self.minifi_controller_executor.update_flow(container_name)
288-
289-
@retry_check(10, 1)
290-
def check_minifi_controller_updated_config_is_persisted(self, container_name: str) -> bool:
291-
return self.minifi_controller_executor.updated_config_is_persisted(container_name)
292-
293-
def stop_component_through_controller(self, component: str, container_name: str):
294-
self.minifi_controller_executor.stop_component(component, container_name)
295-
296-
def start_component_through_controller(self, component: str, container_name: str):
297-
self.minifi_controller_executor.start_component(component, container_name)
298-
299-
@retry_check(10, 1)
300-
def check_component_not_running_through_controller(self, component: str, container_name: str) -> bool:
301-
return not self.minifi_controller_executor.is_component_running(component, container_name)
302-
303-
@retry_check(10, 1)
304-
def check_component_running_through_controller(self, component: str, container_name: str) -> bool:
305-
return self.minifi_controller_executor.is_component_running(component, container_name)
306-
307-
@retry_check(10, 1)
308-
def connection_found_through_controller(self, connection: str, container_name: str) -> bool:
309-
return connection in self.minifi_controller_executor.get_connections(container_name)
310-
311-
@retry_check(10, 1)
312-
def check_connections_full_through_controller(self, connection_count: int, container_name: str) -> bool:
313-
return self.minifi_controller_executor.get_full_connection_count(container_name) == connection_count
314-
315-
@retry_check(10, 1)
316-
def check_connection_size_through_controller(self, connection: str, size: int, max_size: int, container_name: str) -> bool:
317-
return self.minifi_controller_executor.get_connection_size(connection, container_name) == (size, max_size)
318-
319-
@retry_check(10, 1)
320-
def manifest_can_be_retrieved_through_minifi_controller(self, container_name: str) -> bool:
321-
manifest = self.minifi_controller_executor.get_manifest(container_name)
322-
return '"agentManifest": {' in manifest and '"componentManifest": {' in manifest and '"agentType": "cpp"' in manifest
323-
324-
@retry_check(10, 1)
325-
def debug_bundle_can_be_retrieved_through_minifi_controller(self, container_name: str) -> bool:
326-
with tempfile.TemporaryDirectory() as td:
327-
result = self.minifi_controller_executor.get_debug_bundle(container_name, td)
328-
if not result:
329-
logging.error("Failed to get debug bundle")
330-
return False
331-
332-
with tarfile.open(os.path.join(td, "debug.tar.gz")) as file:
333-
file.extractall(td)
334-
335-
if not os.path.exists(os.path.join(td, "config.yml")):
336-
logging.error("config.yml file was not found in debug bundle")
337-
return False
338-
339-
if not os.path.exists(os.path.join(td, "minifi.properties")):
340-
logging.error("minifi.properties file was not found in debug bundle")
341-
return False
342-
343-
if not os.path.exists(os.path.join(td, "minifi.log.gz")):
344-
logging.error("minifi.log.gz file was not found in debug bundle")
345-
return False
346-
347-
with gzip.open(os.path.join(td, "minifi.log.gz"), 'rb') as f_in:
348-
with open(os.path.join(td, "minifi.log"), 'wb') as f_out:
349-
shutil.copyfileobj(f_in, f_out)
350-
351-
with open(os.path.join(td, "minifi.log")) as f:
352-
if 'MiNiFi started' not in f.read():
353-
logging.error("'MiNiFi started' log entry was not found in minifi.log file")
354-
return False
355-
356-
return True
357-
358276
def set_value_on_plc_with_modbus(self, container_name, modbus_cmd):
359277
return self.modbus_checker.set_value_on_plc_with_modbus(container_name, modbus_cmd)
360278

docker/test/integration/cluster/DockerTestDirectoryBindings.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ def create_new_data_directories(self):
5656
test_dir = os.environ['TEST_DIRECTORY'] # Based on DockerVerify.sh
5757
shutil.copytree(test_dir + "/resources/python", self.data_directories[self.feature_id]["resources_dir"] + "/python")
5858
shutil.copytree(test_dir + "/resources/minifi", self.data_directories[self.feature_id]["minifi_config_dir"], dirs_exist_ok=True)
59-
shutil.copytree(test_dir + "/resources/minifi-controller", self.data_directories[self.feature_id]["resources_dir"] + "/minifi-controller")
6059

6160
def get_data_directories(self):
6261
return self.data_directories[self.feature_id]

docker/test/integration/cluster/MinifiControllerExecutor.py

Lines changed: 0 additions & 78 deletions
This file was deleted.

docker/test/integration/cluster/containers/MinifiContainer.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ def __init__(self):
4141
self.config_format = "json"
4242
self.use_flow_config_from_url = False
4343
self.set_ssl_context_properties = False
44-
self.enable_controller_socket = False
4544
self.enable_log_metrics_publisher = False
4645
self.enable_example_minifi_python_processors = False
4746
if "true" in os.environ['MINIFI_FIPS']:
@@ -66,7 +65,6 @@ def __init__(self):
6665
self.minifi_python_venv_parent = '/var/lib/nifi-minifi-cpp'
6766
self.minifi_python_examples = '/usr/share/doc/nifi-minifi-cpp/pythonprocessor-examples'
6867
self.models_path = '/var/lib/nifi-minifi-cpp/models'
69-
self.minifi_controller_path = '/usr/bin/minifi-controller'
7068
self.minifi_home = '/var/lib/nifi-minifi-cpp'
7169
else:
7270
self.run_minifi_cmd = '/opt/minifi/minifi-current/bin/minifi.sh run'
@@ -78,7 +76,6 @@ def __init__(self):
7876
self.minifi_python_examples = '/opt/minifi/minifi-current/minifi-python-examples'
7977
self.minifi_python_venv_parent = '/opt/minifi/minifi-current'
8078
self.models_path = '/opt/minifi/minifi-current/models'
81-
self.minifi_controller_path = '/opt/minifi/minifi-current/bin/minifi-controller'
8279
self.minifi_home = '/opt/minifi/minifi-current'
8380

8481

@@ -186,12 +183,6 @@ def _create_properties(self):
186183
if self.options.use_flow_config_from_url:
187184
f.write(f"nifi.c2.flow.url=http://minifi-c2-server-{self.feature_context.id}:10090/c2/config?class=minifi-test-class\n")
188185

189-
if self.options.enable_controller_socket:
190-
f.write("controller.socket.enable=true\n")
191-
f.write("controller.socket.host=localhost\n")
192-
f.write("controller.socket.port=9998\n")
193-
f.write("controller.socket.local.any.interface=false\n")
194-
195186
if self.options.use_nifi_python_processors_with_virtualenv or self.options.remove_python_requirements_txt or self.options.use_nifi_python_processors_without_dependencies:
196187
f.write("nifi.python.virtualenv.directory={minifi_python_venv_parent}/venv\n".format(minifi_python_venv_parent=MinifiContainer.MINIFI_LOCATIONS.minifi_python_venv_parent))
197188
elif self.options.use_nifi_python_processors_with_virtualenv_packages_installed:

0 commit comments

Comments
 (0)