add pasword tool to the ami customizer service

This commit is contained in:
Enrique Araque 2025-11-17 17:08:19 +01:00
parent 2221c47413
commit 8009f42548
No known key found for this signature in database
GPG Key ID: 29A3281A91360096
17 changed files with 267 additions and 80 deletions

View File

@ -7,7 +7,7 @@ import paramiko
from configurer.ami.ami_post_configurer.create_service_directory import create_directory_structure, generate_yaml
from generic import exec_command, modify_file, remote_connection
from models import Inventory
from utils import CertificatesComponent, Logger, RemoteDirectories
from utils import CertificatesComponent, Logger, PasswordToolComponent, RemoteDirectories
logger = Logger("AmiPostConfigurer")
@ -15,21 +15,21 @@ logger = Logger("AmiPostConfigurer")
@dataclass
class AmiPostConfigurer:
inventory: Inventory
environment_name: str = "certs-env"
environment_name: str = "customizer-env"
enviroment_python_version: str = "3.11"
custom_env_dependencies: ClassVar[list[str]] = [
"pydantic",
"pyyaml",
"paramiko",
]
custom_dir_name: str = "wazuh-ami-certs-customize"
custom_dir_name: str = "wazuh-ami-customizer"
custom_dir_base_path: str = "/etc"
cloud_instances_path: Path = Path("/var/lib/cloud/instances")
journal_logs_path: Path = Path("/var/log/journal")
journald__config_file_path: Path = Path("/etc/systemd/journald.conf")
log_directory_path: Path = Path("/var/log")
wazuh_indexer_log_path: Path = Path("/var/log/wazuh-indexer")
wazuh_server_log_path: Path = Path("/var/log/wazuh-server")
wazuh_server_log_path: Path = Path("/var/ossec/logs")
wazuh_dashboard_log_path: Path = Path("/var/log/wazuh-dashboard")
@remote_connection
@ -105,6 +105,8 @@ class AmiPostConfigurer:
"remote_certs_path": RemoteDirectories.CERTS,
"certs_tool": CertificatesComponent.CERTS_TOOL,
"certs_config": CertificatesComponent.CONFIG,
"password_tool_path": RemoteDirectories.PASSWORD_TOOL,
"password_tool": PasswordToolComponent.PASSWORD_TOOL,
}
directory_template = generate_yaml(
context=context,
@ -181,7 +183,7 @@ class AmiPostConfigurer:
None
"""
self.stop_service("wazuh-server", client=client)
self.stop_service("wazuh-manager", client=client)
def remove_wazuh_indexes(self, client: paramiko.SSHClient) -> None:
"""

View File

@ -1,13 +1,22 @@
name: "wazuh-ami-certs-customize"
# The structure contains name, files, and directories:
# - name: name of the directory to be created
# - files: list of files to be created.
# - path: path where the file to be copied is located. (not the destination path, but the source. The destination path is constructed automatically)
# - local: indicates whether the file is on the local machine (true) or on the remote instance (false).
# - directories: list of subdirectories to be created within the current directory. Each subdirectory can contain its own files and subdirectories.
name: "wazuh-ami-customizer"
files:
- path: "{{ remote_certs_path }}/{{ certs_tool }}"
local: false
- path: "{{ remote_certs_path }}/{{ certs_config }}"
local: false
- path: "{{ password_tool_path }}/{{ password_tool }}"
local: false
directories:
- name: "custom_certificates"
- name: "src"
files:
- path: "configurer/ami/ami_post_configurer/custom_certificates.py"
- path: "configurer/ami/ami_post_configurer/wazuh-ami-customizer.py"
local: true
directories:
- name: "configurer"

View File

@ -7,10 +7,12 @@ from configurer.core.utils import ComponentCertsDirectory
from generic import exec_command
from utils import Component, Logger
LOGFILE = Path("/var/log/wazuh-ami-custom-certificates.log")
TEMP_DIR = Path("/etc/wazuh-ami-certs-customize")
LOGFILE = Path("/var/log/wazuh-ami-customizer.log")
TEMP_DIR = Path("/etc/wazuh-ami-customizer")
CERTS_TOOL_PATH = Path(f"{TEMP_DIR}/certs-tool.sh")
CERTS_TOOL_CONFIG_PATH = Path(f"{TEMP_DIR}/config.yml")
PASSWORD_TOOL_PATH = Path(f"{TEMP_DIR}/password-tool.sh")
PASWORDS_FILE_NAME = Path("/etc/wazuh-ami-customizer/passwords.txt")
SERVICE_PATH = "/etc/systemd/system"
SERVICE_NAME = f"{SERVICE_PATH}/wazuh-ami-customizer.service"
SERVICE_TIMER_NAME = f"{SERVICE_PATH}/wazuh-ami-customizer.timer"
@ -63,7 +65,7 @@ def stop_service(name: str) -> None:
logger.debug(f"{name} service stopped")
def verify_component_connection(component: Component, command: str, retries: int = 5, wait_time: int = 5) -> None:
def verify_component_connection(component: Component, command: str, retries: int = 5, wait_time: int = 10) -> None:
"""
Verifies the component connection by sending a request to the component's endpoint.
Args:
@ -194,13 +196,13 @@ def stop_components_services() -> None:
logger.debug("Stopping Wazuh components services...")
stop_service("wazuh-indexer")
stop_service("wazuh-server")
stop_service("wazuh-manager")
stop_service("wazuh-dashboard")
logger.debug("Wazuh components services stopped")
def verify_indexer_connection() -> None:
def verify_indexer_connection(password: str = "admin") -> None:
"""
Verifies the connection to the Wazuh indexer.
This function sends a request to the Wazuh indexer endpoint and checks the response.
@ -210,7 +212,7 @@ def verify_indexer_connection() -> None:
None
"""
command = 'curl -XGET https://localhost:9200/ -uadmin:admin -k --max-time 120 --silent -w "%{http_code}" --output /dev/null'
command = f"curl -XGET https://localhost:9200/ -uadmin:{password} -k --max-time 120 --silent -w \"%{{http_code}}\" --output /dev/null"
verify_component_connection(Component.WAZUH_INDEXER, command)
@ -259,8 +261,8 @@ def start_components_services() -> None:
run_indexer_security_init()
verify_indexer_connection()
enable_service("wazuh-server")
start_service("wazuh-server")
enable_service("wazuh-manager")
start_service("wazuh-manager")
enable_service("wazuh-dashboard")
start_service("wazuh-dashboard")
@ -269,6 +271,70 @@ def start_components_services() -> None:
logger.debug("Wazuh components services started")
def get_instance_id() -> str:
"""
Retrieves the instance ID of the current machine capitalized.
Returns:
str: The instance ID of the current machine.
"""
logger.debug("Retrieving instance ID")
command = "ec2-metadata | grep 'instance-id' | cut -d':' -f2"
output, error_output = exec_command(command=command)
if error_output:
logger.error(f"Error retrieving instance ID: {error_output}")
raise RuntimeError("Error retrieving instance ID")
return output.strip().capitalize()
def generate_password_file() -> None:
"""
Generates a password file using the password tool.
Args:
path (Path): The path where the password file will be created.
Returns:
None
"""
logger.debug("Generating password file")
command = f"bash {PASSWORD_TOOL_PATH} -gf {PASWORDS_FILE_NAME}"
_, error_output = exec_command(command=command)
if error_output:
logger.error(f"Error generating password file: {error_output}")
raise RuntimeError("Error generating password file")
logger.debug("Password file generated")
def change_passwords() -> None:
logger.name = "CustomPasswords"
logger.debug("Changing passwords started")
logger.debug("Getting instance ID")
instance_id = get_instance_id()
generate_password_file()
logger.debug("Changing passwords to instance ID")
command = f"""
sudo sed -i 's/password:.*/password: {instance_id}/g' {PASWORDS_FILE_NAME}
bash {PASSWORD_TOOL_PATH} -a -A -au wazuh -ap wazuh -f {PASWORDS_FILE_NAME}
"""
_, error_output = exec_command(command=command)
if error_output:
logger.error(f"Error changing passwords: {error_output}")
raise RuntimeError("Error changing passwords")
logger.debug("Passwords changed. Verifying indexer connection with new password")
verify_indexer_connection(password=instance_id)
logger.debug("Changing passwords finished successfully")
def clean_up() -> None:
"""
Cleans up temporary files and directories created during the process.
@ -301,11 +367,14 @@ if __name__ == "__main__":
remove_certificates()
create_certificates()
start_components_services()
stop_service("wazuh-dashboard")
change_passwords()
start_service("wazuh-dashboard")
start_ssh_service()
clean_up()
except Exception as e:
logger.error(f"An error occurred during the custom certificates configuration process: {e}")
logger.error(f"An error occurred during the customization process: {e}")
start_ssh_service()
raise RuntimeError("An error occurred during the custom certificates configuration process") from e
raise RuntimeError("An error occurred during the customization process") from e
logger.info("Custom certificates configuration process finished")
logger.info("Customization process finished")

View File

@ -13,8 +13,8 @@ Wants=wazuh-ami-customizer.timer
[Service]
Type=oneshot
WorkingDirectory=/etc/wazuh-ami-certs-customize/custom_certificates
ExecStart=/etc/wazuh-ami-certs-customize/certs-env/bin/python -m custom_certificates
WorkingDirectory=/etc/wazuh-ami-customizer/src
ExecStart=/etc/wazuh-ami-customizer/customizer-env/bin/python -m wazuh-ami-customizer
[Install]
WantedBy=multi-user.target

View File

@ -95,6 +95,7 @@ def main(
Provisioner(
inventory=input.inventory_content,
certs=input.certificates_content,
password_tool=input.password_tool_url,
components=components,
arch=input.arch,
package_type=input.package_type,

View File

@ -3,3 +3,4 @@ from .component_info import ComponentInfo
from .components_dependencies import ComponentsDependencies
from .input import Input
from .package_info import PackageInfo
from .password_tool_info import PasswordToolInfo

View File

@ -40,7 +40,7 @@ class CertsInfo(BaseModel):
"""
logger.debug(f"Getting URL for {name}...")
try:
url = AnyUrl(self.certs_url_content.get(name, None))
url = AnyUrl(self.certs_url_content.get(name, None)) # type: ignore
except pydantic_core._pydantic_core.ValidationError as err:
raise ValueError(f"URL for {name} has an invalid format: {err}") from err

View File

@ -10,7 +10,8 @@ from utils import Component
from .certs_info import CertsInfo
from .components_dependencies import ComponentsDependencies
from .package_info import PackageInfo
from .utils import format_certificates_urls_file, format_component_urls_file
from .password_tool_info import PasswordToolInfo
from .utils import format_certificates_urls_file, format_component_urls_file, format_password_tool_urls_file
class Input(BaseModel):
@ -67,6 +68,16 @@ class Input(BaseModel):
except FileNotFoundError as err:
raise FileNotFoundError(f"Certificates file not found at {self.packages_url_path}") from err
@property
def password_tool_url(self) -> PasswordToolInfo:
try:
password_tool_data = format_password_tool_urls_file(self.packages_url_path)
if password_tool_data is None:
raise ValueError("Password tool URL not found in the packages URL file.")
return PasswordToolInfo(password_tool_url=password_tool_data)
except FileNotFoundError as err:
raise FileNotFoundError(f"Password tool file not found at {self.packages_url_path}") from err
@property
def inventory_content(self, host_name: str | None = None) -> Inventory | None:
return Inventory(self.inventory_path, host_name) if self.inventory_path else None

View File

@ -0,0 +1,30 @@
from pydantic import AnyUrl, BaseModel, field_validator
from provisioner.utils import AllowedUrlHost
from utils import Logger
from .utils import check_correct_url
logger = Logger("Password-tool provision")
class PasswordToolInfo(BaseModel):
"""
PasswordToolInfo is a model that holds information about password tool URL.
Attributes:
password_tool_url (str): A string containing the URL for the password-tool.
"""
password_tool_url: AnyUrl
@field_validator("password_tool_url")
def validate_password_tool_url(cls, url: AnyUrl) -> AnyUrl:
logger.debug("Validating password tool URL...")
if not check_correct_url(
url,
[AllowedUrlHost.RELEASE, AllowedUrlHost.PRE_RELEASE, AllowedUrlHost.INTERNAL],
):
raise ValueError("URL for password-tool is not for Wazuh packages.")
return url

View File

@ -1,2 +1,2 @@
from .file_formatter import format_certificates_urls_file, format_component_urls_file
from .file_formatter import format_certificates_urls_file, format_component_urls_file, format_password_tool_urls_file
from .helpers import check_correct_url

View File

@ -1,12 +1,13 @@
from pathlib import Path
import yaml
from pydantic import AnyUrl
from provisioner.utils import (
Component_arch,
Package_type,
)
from utils import CertificatesComponent, Component
from utils import CertificatesComponent, Component, PasswordToolComponent
def file_to_dict(raw_urls_path: Path) -> dict:
@ -157,6 +158,31 @@ def format_certificates_urls_file(raw_urls_path: Path) -> dict:
return certificates_urls
def format_password_tool_urls_file(raw_urls_path: Path) -> AnyUrl | None:
"""
Formats a file containing raw URLs into a string of password tool URL.
This function reads a file containing raw URLs and retrieves the URL
for the password tool.
>>> raw_urls_path = Path("password_tool_urls.yaml")
>>> format_password_tool_urls_file(raw_urls_path)
'https://packages.wazuh.com/password-tool-example/password_tool'
Args:
raw_urls_path (Path): The path to the file containing the raw URLs.
Returns:
str: The URL for the password tool.
"""
raw_urls_content = file_to_dict(raw_urls_path)
for component_name, url in raw_urls_content.items():
if PasswordToolComponent.PASSWORD_TOOL.name.lower() in component_name.lower():
return AnyUrl(url)
return None
def format_component_urls_file(raw_urls_path: Path) -> dict:
"""
Formats the component URLs file by processing raw URLs and organizing them by component, architecture, and type.

View File

@ -5,9 +5,9 @@ from pydantic import AnyUrl
from generic import exec_command, remote_connection
from models import Inventory
from provisioner.models import CertsInfo, ComponentInfo
from provisioner.models import CertsInfo, ComponentInfo, PasswordToolInfo
from provisioner.utils import Component_arch, Package_manager, Package_type
from utils import CertificatesComponent, Component, Logger, RemoteDirectories
from utils import CertificatesComponent, Component, Logger, PasswordToolComponent, RemoteDirectories
logger = Logger("Provisioner")
@ -30,6 +30,7 @@ class Provisioner:
inventory: Inventory | None
certs: CertsInfo
password_tool: PasswordToolInfo
components: list[ComponentInfo]
arch: Component_arch = Component_arch.X86_64
package_type: Package_type = Package_type.RPM
@ -49,7 +50,8 @@ class Provisioner:
1. Logs the start of the provisioning process.
2. Provisions the certs_tool using `certs_tool_provision`.
3. Provision the config file using `certs_config_provision`.
4. Iterates over each component and performs the following:
4. Provisions the password tool using `password_tool_provision`.
5. Iterates over each component and performs the following:
a. Logs the start of provisioning for the component.
b. Provisions dependencies for the component using `dependencies_provision`.
c. Provisions packages for the component using `packages_provision`.
@ -63,6 +65,10 @@ class Provisioner:
self.certs_tool_provision(client)
self.certs_config_provision(client)
logger.debug_title("Provisioning password tool")
self.password_tool_provision(client)
logger.debug_title("Provisioning special dependencies")
self.special_dependencies_provision(client)
@ -77,20 +83,22 @@ class Provisioner:
Provisions the certs_tool on the specified client.
This method uses the provided SSH client to connect to a remote machine
and provision the certs_tool by calling the `certificates_provision`
and provision the certs_tool by calling the `tool_provision`
method with the appropriate URL.
Args:
client (paramiko.SSHClient): The SSH client used to connect to the remote machine.
"""
self.certificates_provision(self.certs.certs_tool_url, CertificatesComponent.CERTS_TOOL, client)
self.tool_provision(
self.certs.certs_tool_url, f"{RemoteDirectories.CERTS}", CertificatesComponent.CERTS_TOOL, client
)
def certs_config_provision(self, client: paramiko.SSHClient | None = None) -> None:
"""
Provisions the certs config file on the remote client.
This method uses the provided SSH client to connect to a remote machine
and provision the certs config file by calling the `certificates_provision`
and provision the certs config file by calling the `tool_provision`
method with the appropriate URL.
Args:
@ -99,7 +107,25 @@ class Provisioner:
Returns:
None
"""
self.certificates_provision(self.certs.config_url, CertificatesComponent.CONFIG, client)
self.tool_provision(self.certs.config_url, f"{RemoteDirectories.CERTS}", CertificatesComponent.CONFIG, client)
def password_tool_provision(self, client: paramiko.SSHClient | None = None) -> None:
"""
Provisions the password tool on the specified client.
This method uses the provided SSH client to connect to a remote machine
and provision the password tool by calling the `tool_provision`
method with the appropriate URL.
Args:
client (paramiko.SSHClient): The SSH client used to connect to the remote machine.
"""
self.tool_provision(
self.password_tool.password_tool_url,
f"{RemoteDirectories.PASSWORD_TOOL}",
PasswordToolComponent.PASSWORD_TOOL,
client,
)
def special_dependencies_provision(self, client: paramiko.SSHClient | None = None) -> None:
"""
@ -177,39 +203,33 @@ class Provisioner:
component.name.replace("_", " ").capitalize(),
)
def certificates_provision(
self, certs_file_url: AnyUrl, filename: str, client: paramiko.SSHClient | None = None
def tool_provision(
self, tool_url: AnyUrl, tool_dir: str, tool_filename: str, client: paramiko.SSHClient | None = None
) -> None:
"""
Downloads a certificate file (certs_tool or config) from a given URL and saves it to a remote directory on a server.
Provisions a tool (certs_tool, config file, or password tool) on the remote client.
Args:
certs_file_url (AnyUrl): The URL of the certificate file to be downloaded.
client (paramiko.SSHClient): An active SSH client connected to the remote server.
Raises:
Exception: If there is an error during the download process.
Logs:
Error message if the download fails.
Success message if the download is successful.
tool_url (AnyUrl): The URL of the tool to be provisioned.
tool_dir (str): The directory on the remote client where the tool will be stored.
tool_filename (str): The filename of the tool to be provisioned.
client (paramiko.SSHClient): The SSH client used to connect to the remote machine.
"""
logger.debug(f"Provisioning {filename}")
logger.debug(f"Provisioning {tool_filename}")
command_template = "mkdir -p {dir} && curl -s -o {path} '{certs_file_url}'"
command_template = "mkdir -p {directory} && curl -s -o {path} '{tool_file_url}'"
command = command_template.format(
dir=f"{RemoteDirectories.CERTS}",
path=f"{RemoteDirectories.CERTS}/{filename}",
certs_file_url=certs_file_url,
directory=tool_dir,
path=f"{tool_dir}/{tool_filename}",
tool_file_url=tool_url,
)
output, error_output = exec_command(command=command, client=client)
_, error_output = exec_command(command=command, client=client)
if error_output:
logger.error(f"Error downloading {filename}: {error_output}")
raise RuntimeError(f"Error downloading {filename}")
logger.error(f"Error downloading {tool_filename}: {error_output}")
raise RuntimeError(f"Error downloading {tool_filename}")
logger.info_success(f"{filename} downloaded successfully")
logger.info_success(f"{tool_filename} downloaded successfully")
def list_dependencies(self, elements: list[str], component_name: str) -> None:
"""

View File

@ -41,6 +41,7 @@ def mock_logger(autouse=True):
logger_paths = [
"provisioner.provisioner.logger",
"provisioner.models.certs_info.logger",
"provisioner.models.password_tool_info.logger",
"generic.remote_connection.logger",
"configurer.core.models.wazuh_components_config_manager.logger",
"configurer.core.models.certificates_manager.logger",

View File

@ -4,7 +4,7 @@ from unittest.mock import MagicMock, patch
import pytest
from configurer.ami.ami_post_configurer.ami_post_configurer import AmiPostConfigurer
from utils.enums import CertificatesComponent, RemoteDirectories
from utils.enums import CertificatesComponent, PasswordToolComponent, RemoteDirectories
@pytest.fixture()
@ -78,6 +78,8 @@ def test_create_custom_dir_success(mock_create_structure, mock_generate_yaml, mo
"remote_certs_path": RemoteDirectories.CERTS,
"certs_tool": CertificatesComponent.CERTS_TOOL,
"certs_config": CertificatesComponent.CONFIG,
"password_tool_path": RemoteDirectories.PASSWORD_TOOL,
"password_tool": PasswordToolComponent.PASSWORD_TOOL,
}
mock_generate_yaml.return_value = {"template": "test_value"}
@ -145,11 +147,11 @@ def test_stop_service_fails(mock_ami_post_configurer, mock_exec_command, mock_pa
def test_stop_wazuh_server(mock_ami_post_configurer, mock_exec_command, mock_paramiko, mock_logger):
mock_ami_post_configurer.stop_wazuh_server(mock_paramiko.return_value)
command = "sudo systemctl stop wazuh-server"
command = "sudo systemctl stop wazuh-manager"
mock_exec_command.assert_called_once_with(command=command, client=mock_paramiko.return_value)
mock_logger.debug.assert_called_once_with("Stopping wazuh-server service")
mock_logger.info_success.assert_called_once_with("wazuh-server service stopped successfully")
mock_logger.debug.assert_called_once_with("Stopping wazuh-manager service")
mock_logger.info_success.assert_called_once_with("wazuh-manager service stopped successfully")
def test_stop_wazuh_indexer(mock_ami_post_configurer, mock_exec_command, mock_paramiko, mock_logger):
@ -176,7 +178,9 @@ def test_stop_wazuh_indexer(mock_ami_post_configurer, mock_exec_command, mock_pa
def test_remove_wazuh_indexes(mock_ami_post_configurer, mock_exec_command, mock_paramiko, mock_logger):
mock_ami_post_configurer.remove_wazuh_indexes(mock_paramiko.return_value)
command = 'sudo curl -s -o /dev/null -w "%{http_code}" -X DELETE -u "admin:admin" -k "https://127.0.0.1:9200/wazuh-*"'
command = (
'sudo curl -s -o /dev/null -w "%{http_code}" -X DELETE -u "admin:admin" -k "https://127.0.0.1:9200/wazuh-*"'
)
mock_exec_command.assert_called_once_with(command=command, client=mock_paramiko.return_value)
@ -192,6 +196,7 @@ def test_remove_wazuh_indexes_fail(mock_ami_post_configurer, mock_exec_command,
mock_logger.error.assert_called_once_with("Error removing wazuh- indexes")
def test_run_security_init_script(mock_ami_post_configurer, mock_exec_command, mock_paramiko, mock_logger):
mock_ami_post_configurer.run_security_init_script(mock_paramiko.return_value)

View File

@ -6,6 +6,7 @@ from pydantic import AnyUrl
from provisioner.models.certs_info import CertsInfo
from provisioner.models.component_info import ComponentInfo
from provisioner.models.password_tool_info import PasswordToolInfo
from provisioner.provisioner import Provisioner
from provisioner.utils import Package_manager, Package_type
from utils.enums import Component
@ -32,10 +33,13 @@ def component_info_valid(valid_inventory):
"config": "http://packages-dev.wazuh.com/example/config.yml",
}
)
password_tool = PasswordToolInfo(password_tool_url=AnyUrl("http://packages-dev.wazuh.com/example/password-tool.sh"))
package_type = Package_type.RPM
return Provisioner(
inventory=valid_inventory,
certs=certs,
password_tool=password_tool,
components=[component_server],
package_type=package_type,
)
@ -56,9 +60,10 @@ def test_provision_success(mock_paramiko, mock_logger, component_info_valid, moc
mock_client_instance = MagicMock()
mock_paramiko.return_value = mock_client_instance
certs_expect_commands = [
"mkdir -p ~/wazuh-configure/certs && curl -s -o ~/wazuh-configure/certs/certs-tool.sh 'http://packages-dev.wazuh.com/example/certs-tool.sh'",
"mkdir -p ~/wazuh-configure/certs && curl -s -o ~/wazuh-configure/certs/config.yml 'http://packages-dev.wazuh.com/example/config.yml'",
tools_expect_commands = [
"mkdir -p ~/wazuh-configure/tools/certs && curl -s -o ~/wazuh-configure/tools/certs/certs-tool.sh 'http://packages-dev.wazuh.com/example/certs-tool.sh'",
"mkdir -p ~/wazuh-configure/tools/certs && curl -s -o ~/wazuh-configure/tools/certs/config.yml 'http://packages-dev.wazuh.com/example/config.yml'",
"mkdir -p ~/wazuh-configure/tools && curl -s -o ~/wazuh-configure/tools/password-tool.sh 'http://packages-dev.wazuh.com/example/password-tool.sh'"
]
dependencies_expect_commands = [
@ -85,22 +90,22 @@ def test_provision_success(mock_paramiko, mock_logger, component_info_valid, moc
key_filename=str(component_info_valid.inventory.ansible_ssh_private_key_file),
)
assert mock_exec_command.call_count == 7 # 3 for dependencies, 2 for certs, 1 download package, 1 install package
assert mock_exec_command.call_count == 8 # 3 for dependencies, 3 for tools (certs-tool and password-tool), 1 download package, 1 install package
# certs
assert certs_expect_commands[0] in mock_exec_command.call_args_list[0].kwargs["command"]
assert certs_expect_commands[1] in mock_exec_command.call_args_list[1].kwargs["command"]
# tools
assert tools_expect_commands[0] in mock_exec_command.call_args_list[0].kwargs["command"]
assert tools_expect_commands[1] in mock_exec_command.call_args_list[1].kwargs["command"]
assert tools_expect_commands[2] in mock_exec_command.call_args_list[2].kwargs["command"]
# dependencies
assert dependencies_expect_commands[0] in mock_exec_command.call_args_list[2].kwargs["command"]
assert dependencies_expect_commands[1] in mock_exec_command.call_args_list[2].kwargs["command"]
assert dependencies_expect_commands[2] in mock_exec_command.call_args_list[3].kwargs["command"]
assert dependencies_expect_commands[3] in mock_exec_command.call_args_list[4].kwargs["command"]
assert dependencies_expect_commands[0] in mock_exec_command.call_args_list[3].kwargs["command"]
assert dependencies_expect_commands[1] in mock_exec_command.call_args_list[3].kwargs["command"]
assert dependencies_expect_commands[2] in mock_exec_command.call_args_list[4].kwargs["command"]
assert dependencies_expect_commands[3] in mock_exec_command.call_args_list[5].kwargs["command"]
# package
assert package_expect_commands[0] in mock_exec_command.call_args_list[5].kwargs["command"]
assert package_expect_commands[1] in mock_exec_command.call_args_list[6].kwargs["command"]
assert package_expect_commands[0] in mock_exec_command.call_args_list[6].kwargs["command"]
assert package_expect_commands[1] in mock_exec_command.call_args_list[7].kwargs["command"]
mock_logger.debug_title.assert_any_call("Starting provisioning")
mock_logger.debug_title.assert_any_call("Provisioning certificates files")
mock_logger.debug_title.assert_any_call("Starting provisioning for wazuh manager")
@ -120,7 +125,7 @@ def test_certs_tool_provision_success(
getattr(component_info_valid, certs_method)(mock_client_instance)
mock_exec_command.assert_called_once_with(
command=f"mkdir -p ~/wazuh-configure/certs && curl -s -o ~/wazuh-configure/certs/{certs_component} 'http://packages-dev.wazuh.com/example/{certs_component}'",
command=f"mkdir -p ~/wazuh-configure/tools/certs && curl -s -o ~/wazuh-configure/tools/certs/{certs_component} 'http://packages-dev.wazuh.com/example/{certs_component}'",
client=mock_client_instance,
)
mock_logger.debug.assert_any_call(f"Provisioning {certs_component}")
@ -142,7 +147,7 @@ def test_certs_tool_provision_failure(
getattr(component_info_valid, certs_method)(mock_client_instance)
mock_exec_command.assert_called_once_with(
command=f"mkdir -p ~/wazuh-configure/certs && curl -s -o ~/wazuh-configure/certs/{certs_component} 'http://packages-dev.wazuh.com/example/{certs_component}'",
command=f"mkdir -p ~/wazuh-configure/tools/certs && curl -s -o ~/wazuh-configure/tools/certs/{certs_component} 'http://packages-dev.wazuh.com/example/{certs_component}'",
client=mock_client_instance,
)
mock_logger.debug.assert_any_call(f"Provisioning {certs_component}")
@ -345,9 +350,10 @@ def test_install_package(
if "installed successfully" in expected_log and "WARNING" not in error_output:
mock_logger.info_success.assert_called_once_with(f"{package_name} {expected_log}")
elif "is already installed" in expected_log:
mock_logger.debug.assert_has_calls(
[mock.call(f"Installing {package_name}"), mock.call(f"{package_name} {expected_log}")]
)
mock_logger.debug.assert_has_calls([
mock.call(f"Installing {package_name}"),
mock.call(f"{package_name} {expected_log}"),
])
elif "installed successfully" in expected_log and "WARNING" in error_output:
mock_logger.warning.assert_called_once_with(f"{error_output}")
mock_logger.info_success.assert_called_once_with(f"{package_name} {expected_log}")

View File

@ -1,2 +1,2 @@
from .enums import CertificatesComponent, Component, RemoteDirectories
from .enums import CertificatesComponent, Component, PasswordToolComponent, RemoteDirectories
from .logger import Logger

View File

@ -8,6 +8,10 @@ class Component(StrEnum):
ALL = auto()
class PasswordToolComponent(StrEnum):
PASSWORD_TOOL = "password-tool.sh"
class CertificatesComponent(StrEnum):
CERTS_TOOL = "certs-tool.sh"
CONFIG = "config.yml"
@ -15,5 +19,7 @@ class CertificatesComponent(StrEnum):
class RemoteDirectories(StrEnum):
WAZUH_ROOT_DIR = "~/wazuh-configure"
TOOLS_DIR = f"{WAZUH_ROOT_DIR}/tools"
PACKAGES = f"{WAZUH_ROOT_DIR}/packages"
CERTS = f"{WAZUH_ROOT_DIR}/certs"
CERTS = f"{TOOLS_DIR}/certs"
PASSWORD_TOOL = f"{TOOLS_DIR}"