MINIFICPP-2718 Windows based docker tests#2106
MINIFICPP-2718 Windows based docker tests#2106martinzink wants to merge 3 commits intoapache:MINIFICPP-2711from
Conversation
Closes #2106 Signed-off-by: Martin Zink <martinzink@apache.org>
Closes #2106 Signed-off-by: Martin Zink <martinzink@apache.org>
32a11ab to
ea3f9de
Compare
Closes #2106 Signed-off-by: Martin Zink <martinzink@apache.org>
There was a problem hiding this comment.
Pull request overview
This PR updates the MiNiFi C++ Behave-based test framework to support running a subset of Docker-based tests on Windows hosts, while also refactoring the container abstraction and SSL certificate utilities to be more portable.
Changes:
- Introduces Windows container support (Windows container base class, Windows MiNiFi container, Windows Dockerfile) and gates scenarios via a
@SUPPORTS_WINDOWStag. - Refactors the Behave container layer to distinguish Linux vs. Windows containers and centralizes controller logic via a
MinifiControllerhelper. - Replaces M2Crypto/PyOpenSSL usage in the Behave framework with
cryptographyand updates dependent test containers accordingly.
Reviewed changes
Copilot reviewed 37 out of 38 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| run_flake8.sh | Updates flake8 exclude list to ignore additional virtualenv directories. |
| extensions/standard-processors/tests/features/steps/tcp_client_container.py | Switches test container base class to LinuxContainer. |
| extensions/standard-processors/tests/features/steps/syslog_container.py | Switches test container base class to LinuxContainer. |
| extensions/standard-processors/tests/features/steps/minifi_controller_steps.py | Routes controller-related steps through a .controller helper object. |
| extensions/standard-processors/tests/features/steps/diag_slave_container.py | Switches test container base class to LinuxContainer. |
| extensions/standard-processors/tests/features/replace_text.feature | Marks feature as @SUPPORTS_WINDOWS. |
| extensions/standard-processors/tests/features/core_functionality.feature | Marks feature as @SUPPORTS_WINDOWS and adjusts some step text/timeouts. |
| extensions/sql/tests/features/steps/postgress_server_container.py | Switches test container base class to LinuxContainer. |
| extensions/splunk/tests/features/steps/splunk_container.py | Removes PyOpenSSL usage and uses ssl_utils.dump_cert/dump_key; switches to LinuxContainer. |
| extensions/opc/tests/features/steps/opc_ua_server_container.py | Switches test container base class to LinuxContainer. |
| extensions/kafka/tests/features/steps/kafka_server_container.py | Removes PyOpenSSL usage and uses dump_cert/dump_key with DER output; switches to LinuxContainer. |
| extensions/grafana-loki/tests/features/steps/reverse_proxy_container.py | Switches test container base class to LinuxContainer. |
| extensions/grafana-loki/tests/features/steps/grafana_loki_container.py | Removes PyOpenSSL usage and uses dump_cert/dump_key; switches to LinuxContainer. |
| extensions/gcp/tests/features/steps/fake_gcs_server_container.py | Switches test container base class to LinuxContainer. |
| extensions/elasticsearch/tests/features/steps/opensearch_container.py | Removes PyOpenSSL usage and uses dump_cert/dump_key. |
| extensions/elasticsearch/tests/features/steps/elasticsearch_container.py | Removes PyOpenSSL usage and uses dump_cert/dump_key. |
| extensions/elasticsearch/tests/features/steps/elastic_base_container.py | Switches test container base class to LinuxContainer. |
| extensions/couchbase/tests/features/steps/couchbase_server_container.py | Removes PyOpenSSL usage and updates retry_check(...) decorator invocation style. |
| extensions/azure/tests/features/steps/azure_server_container.py | Switches test container base class to LinuxContainer. |
| extensions/aws/tests/features/steps/s3_server_container.py | Switches test container base class to LinuxContainer. |
| extensions/aws/tests/features/steps/kinesis_server_container.py | Switches test container base class to LinuxContainer. |
| docker/installed/win.Dockerfile | Adds a Windows Server Core Dockerfile to run MiNiFi installed via MSI. |
| behave_framework/src/minifi_test_framework/core/ssl_utils.py | Reimplements cert generation/dumping using cryptography. |
| behave_framework/src/minifi_test_framework/core/minifi_test_context.py | Selects Linux/FHS/Windows MiNiFi container implementations at runtime; introduces protocol typing. |
| behave_framework/src/minifi_test_framework/core/hooks.py | Skips non-@SUPPORTS_WINDOWS scenarios on Windows; makes teardown tolerant when setup is skipped. |
| behave_framework/src/minifi_test_framework/containers/nifi_container.py | Switches NiFi container base class to LinuxContainer. |
| behave_framework/src/minifi_test_framework/containers/minifi_win_container.py | Adds a Windows MiNiFi container implementation. |
| behave_framework/src/minifi_test_framework/containers/minifi_protocol.py | Adds a typing Protocol for MiNiFi container capabilities. |
| behave_framework/src/minifi_test_framework/containers/minifi_linux_container.py | Adds a Linux MiNiFi container implementation with controller support and cert provisioning. |
| behave_framework/src/minifi_test_framework/containers/minifi_fhs_container.py | Adds an FHS-layout MiNiFi container implementation with controller support and cert provisioning. |
| behave_framework/src/minifi_test_framework/containers/minifi_controller.py | Adds a helper encapsulating minifi-controller CLI interactions. |
| behave_framework/src/minifi_test_framework/containers/minifi_container.py | Updates cert dumping to use dump_cert/dump_key (legacy container remains in tree). |
| behave_framework/src/minifi_test_framework/containers/http_proxy_container.py | Switches test container base class to LinuxContainer. |
| behave_framework/src/minifi_test_framework/containers/container_windows.py | Adds a Windows container base class for test framework containers. |
| behave_framework/src/minifi_test_framework/containers/container_protocol.py | Adds a typing Protocol for container operations used by steps. |
| behave_framework/src/minifi_test_framework/containers/container_linux.py | Renames base container class to LinuxContainer and aligns it with the protocol. |
| behave_framework/pyproject.toml | Bumps framework version and replaces M2Crypto/PyOpenSSL deps with cryptography. |
| .gitignore | Ignores additional venv directories (venv, behave_venv). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| class MinifiTestContext(Context): | ||
| containers: dict[str, Container] | ||
| containers: dict[str, ContainerProtocol] | ||
| scenario_id: str | ||
| network: Network | ||
| minifi_container_image: str | ||
| resource_dir: str | None | ||
| root_ca_key: crypto.PKey | ||
| root_ca_cert: crypto.X509 | ||
| root_ca_key: Any | ||
| root_ca_cert: Any |
There was a problem hiding this comment.
root_ca_key / root_ca_cert are typed as Any. Since ssl_utils now uses cryptography, these can be typed more precisely (e.g., cryptography.x509.Certificate and an RSAPrivateKey type) to keep static checking useful.
|
|
||
| # 4. Create and Start | ||
| try: | ||
| print(f"Creating and starting container '{self.container_name}'...") |
There was a problem hiding this comment.
print(...) is used for container startup logging. Using the existing logging calls (as in LinuxContainer.deploy) would keep test output consistent and easier to control in CI.
| print(f"Creating and starting container '{self.container_name}'...") | |
| logging.info(f"Creating and starting container '{self.container_name}'...") |
|
|
||
| for file in self.files: | ||
| self._copy_content_to_container(file.content, file.path) | ||
|
|
||
| except Exception as e: | ||
| logging.error(f"Error starting container: {e}") | ||
| self.clean_up() | ||
| raise | ||
| return True | ||
|
|
||
| def _copy_content_to_container(self, content: str, target_path: str): | ||
| if not self.container: | ||
| return | ||
|
|
||
| win_path = self._normalize_path(target_path) | ||
| dir_name = os.path.dirname(win_path) | ||
| file_name = os.path.basename(win_path) | ||
|
|
||
| self._run_powershell(f"New-Item -ItemType Directory -Force -Path '{dir_name}'") | ||
|
|
||
| tar_stream = io.BytesIO() | ||
| with tarfile.open(fileobj=tar_stream, mode='w') as tar: | ||
| encoded_data = content.encode('utf-8') | ||
| tarinfo = tarfile.TarInfo(name=file_name) | ||
| tarinfo.size = len(encoded_data) | ||
| tar.addfile(tarinfo, io.BytesIO(encoded_data)) | ||
|
|
There was a problem hiding this comment.
_copy_content_to_container assumes content is a str and unconditionally calls .encode('utf-8'), but File.content is defined as str | bytes. If a Windows container needs to copy binary content (e.g., JKS files/certs), this will fail. Consider accepting bytes | str and only encoding when the input is text.
| import datetime | ||
| from cryptography import x509 | ||
| from cryptography.x509.oid import NameOID | ||
| from cryptography.hazmat.primitives import hashes | ||
| from cryptography.hazmat.primitives.asymmetric import rsa | ||
| from cryptography.hazmat.primitives import serialization |
There was a problem hiding this comment.
This file no longer includes the ASF license header that is present across the rest of the repository. Please restore the standard Apache 2.0 header at the top of the file to maintain licensing compliance.
| def make_client_cert(common_name, ca_cert, ca_key): | ||
| return _make_cert(common_name=common_name, ca_cert=ca_cert, ca_key=ca_key, extended_key_usage=b"clientAuth") | ||
| return _make_cert(common_name, ca_cert, ca_key, [x509.OID_CLIENT_AUTH]) | ||
|
|
||
|
|
||
| def make_server_cert(common_name, ca_cert, ca_key): | ||
| return _make_cert(common_name=common_name, ca_cert=ca_cert, ca_key=ca_key, extended_key_usage=b"serverAuth") | ||
| return _make_cert(common_name, ca_cert, ca_key, [x509.OID_SERVER_AUTH]) | ||
|
|
There was a problem hiding this comment.
x509.OID_CLIENT_AUTH / x509.OID_SERVER_AUTH are not valid identifiers in cryptography.x509 (extended key usage OIDs are exposed via cryptography.x509.oid.ExtendedKeyUsageOID). As written, these calls will raise at runtime when creating certs. Switch to the correct ExtendedKeyUsageOID constants (or pass ObjectIdentifier instances) so certificate generation works.
| directory=${1:-.} | ||
| flake8 --exclude .venv,venv,thirdparty,build,cmake-build-*,github_env --builtins log,REL_SUCCESS,REL_FAILURE,REL_ORIGINAL,raw_input --ignore E501,W503,F811 "${directory}" | ||
| flake8 --exclude .venv,venv,venv2,behave-venv,thirdparty,build,cmake-build-*,github_env --builtins log,REL_SUCCESS,REL_FAILURE,REL_ORIGINAL,raw_input --ignore E501,W503,F811 "${directory}" |
There was a problem hiding this comment.
The repo’s Behave test virtualenv is created in ./behave_venv (see docker/RunBehaveTests.sh), but flake8 excludes behave-venv (dash). This means flake8 will still traverse the Behave venv by default. Consider excluding behave_venv here (and keep/remove behave-venv depending on what is actually used).
|
|
||
| SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] | ||
|
|
||
| RUN Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) |
There was a problem hiding this comment.
Downloading and executing the Chocolatey install script with iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) introduces a supply-chain remote code execution risk: if community.chocolatey.org or the connection is compromised, arbitrary code can run during the Docker build with high privileges. To harden this, rely on a trusted, versioned installation source (e.g., a base image or offline package) and/or verify the installer’s integrity via a pinned checksum or signature instead of executing it directly from the remote URL.
Thank you for submitting a contribution to Apache NiFi - MiNiFi C++.
In order to streamline the review of the contribution we ask you
to ensure the following steps have been taken:
For all changes:
Is there a JIRA ticket associated with this PR? Is it referenced
in the commit message?
Does your PR title start with MINIFICPP-XXXX where XXXX is the JIRA number you are trying to resolve? Pay particular attention to the hyphen "-" character.
Has your PR been rebased against the latest commit within the target branch (typically main)?
Is your initial contribution a single, squashed commit?
For code changes:
For documentation related changes:
Note:
Please ensure that once the PR is submitted, you check GitHub Actions CI results for build issues and submit an update to your PR as soon as possible.