diff --git a/osism/commands/loadbalancer.py b/osism/commands/loadbalancer.py index e5fe0e41..168e4b81 100644 --- a/osism/commands/loadbalancer.py +++ b/osism/commands/loadbalancer.py @@ -39,23 +39,9 @@ def _load_octavia_database_password(): return None try: - from osism.tasks.conductor.utils import get_vault + from osism.tasks.conductor.utils import load_yaml_file - vault = get_vault() - - with open(secrets_path, "rb") as f: - file_data = f.read() - - if vault.is_encrypted(file_data): - decrypted_data = vault.decrypt(file_data).decode() - logger.debug(f"Successfully decrypted secrets file: {secrets_path}") - else: - decrypted_data = file_data.decode() - logger.debug( - f"Secrets file is not encrypted (development mode): {secrets_path}" - ) - - secrets = yaml.safe_load(decrypted_data) + secrets = load_yaml_file(secrets_path) if not secrets or not isinstance(secrets, dict): logger.error("Empty or invalid secrets file") diff --git a/osism/commands/status.py b/osism/commands/status.py index be022a46..7e967d40 100644 --- a/osism/commands/status.py +++ b/osism/commands/status.py @@ -104,8 +104,6 @@ def _load_kolla_configuration(self): def _load_database_password(self): """Load and decrypt the database password from secrets.yml""" - from osism.tasks.conductor.utils import get_vault - secrets_path = "/opt/configuration/environments/kolla/secrets.yml" if not os.path.exists(secrets_path): @@ -113,21 +111,9 @@ def _load_database_password(self): return None try: - vault = get_vault() - - with open(secrets_path, "rb") as f: - file_data = f.read() - - if vault.is_encrypted(file_data): - decrypted_data = vault.decrypt(file_data).decode() - logger.debug(f"Successfully decrypted secrets file: {secrets_path}") - else: - decrypted_data = file_data.decode() - logger.debug( - f"Secrets file is not encrypted (development mode): {secrets_path}" - ) + from osism.tasks.conductor.utils import load_yaml_file - secrets = yaml.safe_load(decrypted_data) + secrets = load_yaml_file(secrets_path) if not secrets or not isinstance(secrets, dict): logger.error("Empty or invalid secrets file") diff --git a/osism/tasks/conductor/utils.py b/osism/tasks/conductor/utils.py index dc8f74e4..25cee2f1 100644 --- a/osism/tasks/conductor/utils.py +++ b/osism/tasks/conductor/utils.py @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +import os + from ansible import constants as ansible_constants from ansible.parsing.vault import VaultLib, VaultSecret from loguru import logger @@ -7,6 +9,7 @@ from osism import utils import sushy import urllib3 +import yaml def deep_compare(a, b, updates): @@ -88,6 +91,32 @@ def get_vault(): return vault +def load_yaml_file(path): + """Load a YAML file and only request the vault secret when needed.""" + if not os.path.exists(path): + logger.error(f"YAML file not found: {path}") + return None + + try: + with open(path, "rb") as f: + file_data = f.read() + + if VaultLib().is_encrypted(file_data): + decrypted_data = get_vault().decrypt(file_data).decode() + logger.debug(f"Successfully decrypted vault-encrypted YAML file: {path}") + else: + decrypted_data = file_data.decode() + logger.debug(f"YAML file is not encrypted: {path}") + + return yaml.safe_load(decrypted_data) + except yaml.YAMLError as exc: + logger.error(f"Failed to parse YAML file {path}: {exc}") + return None + except Exception as exc: + logger.error(f"Failed to load YAML file {path}: {exc}") + return None + + def get_redfish_connection( hostname, username=None, password=None, ignore_ssl_errors=True, timeout=None ): diff --git a/osism/tasks/openstack.py b/osism/tasks/openstack.py index 86809140..36a75f3f 100644 --- a/osism/tasks/openstack.py +++ b/osism/tasks/openstack.py @@ -10,7 +10,7 @@ from osism import settings, utils from osism.tasks import Config, run_command -from osism.tasks.conductor.utils import get_vault +from osism.tasks.conductor.utils import load_yaml_file app = Celery("openstack") app.config_from_object(Config) @@ -432,51 +432,9 @@ def get_cloud_password(cloud): logger.warning(f"Secrets file not found: {secrets_path}") return None - # Get vault instance for decryption - vault = get_vault() - - # Load the secrets file - with open(secrets_path, "rb") as f: - file_data = f.read() - - decrypted_secrets = None - - # Try to decrypt the file if it's vault encrypted - try: - if vault.is_encrypted(file_data): - # File is encrypted, decrypt it - decrypted_data = vault.decrypt(file_data).decode() - logger.debug(f"Successfully decrypted secrets file: {secrets_path}") - else: - # File is not encrypted, use as-is - decrypted_data = file_data.decode() - logger.debug( - f"Secrets file is not encrypted (development mode): {secrets_path}" - ) - - # Parse the YAML content safely - try: - decrypted_secrets = yaml.safe_load(decrypted_data) - except yaml.YAMLError as yaml_exc: - logger.error( - f"Failed to parse YAML content from secrets file: {yaml_exc}" - ) - return None - - except Exception as decrypt_exc: - # If decryption fails, try reading as plain YAML (development fallback) - logger.warning( - f"Failed to decrypt secrets file, attempting to read as plain YAML: {decrypt_exc}" - ) - try: - with open(secrets_path, "r") as f: - decrypted_secrets = yaml.safe_load(f) - logger.debug( - f"Successfully loaded unencrypted secrets file (development mode): {secrets_path}" - ) - except Exception as plain_exc: - logger.error(f"Failed to read secrets file as plain YAML: {plain_exc}") - return None + decrypted_secrets = load_yaml_file(secrets_path) + if decrypted_secrets is None: + return None if not decrypted_secrets or not isinstance(decrypted_secrets, dict): logger.warning( diff --git a/osism/utils/rabbitmq.py b/osism/utils/rabbitmq.py index 0cbfe3a4..1a343b95 100644 --- a/osism/utils/rabbitmq.py +++ b/osism/utils/rabbitmq.py @@ -6,7 +6,6 @@ import subprocess from loguru import logger -import yaml from osism.utils.inventory import get_hosts_from_inventory, get_inventory_path @@ -150,23 +149,9 @@ def load_rabbitmq_password(): return None try: - from osism.tasks.conductor.utils import get_vault + from osism.tasks.conductor.utils import load_yaml_file - vault = get_vault() - - with open(secrets_path, "rb") as f: - file_data = f.read() - - if vault.is_encrypted(file_data): - decrypted_data = vault.decrypt(file_data).decode() - logger.debug(f"Successfully decrypted secrets file: {secrets_path}") - else: - decrypted_data = file_data.decode() - logger.debug( - f"Secrets file is not encrypted (development mode): {secrets_path}" - ) - - secrets = yaml.safe_load(decrypted_data) + secrets = load_yaml_file(secrets_path) if not secrets or not isinstance(secrets, dict): logger.error("Empty or invalid secrets file")