Source code for ecs_composex.ssm_parameter.ssm_parameter_helpers

#  SPDX-License-Identifier: MPL-2.0
#  Copyright 2020-2022 John Mille <john@compose-x.io>

from __future__ import annotations

from typing import TYPE_CHECKING

import ecs_composex.common.troposphere_tools

if TYPE_CHECKING:
    from ecs_composex.common.stacks import ComposeXStack
    from ecs_composex.ssm_parameter.ssm_parameter_stack import SsmParameter

import json
from os import path

import yaml
from compose_x_common.compose_x_common import keyisset
from troposphere import Base64
from troposphere.ssm import Parameter as CfnSsmParameter
from yaml import Loader

from ecs_composex.common.logging import LOG
from ecs_composex.common.troposphere_tools import add_outputs
from ecs_composex.resources_import import import_record_properties
from ecs_composex.ssm_parameter.ssm_parameter_params import (
    SSM_PARAM_ARN,
    SSM_PARAM_NAME,
)


[docs]def get_parameter_config(parameter: SsmParameter, account_id: str, resource_id: str): """ :param parameter: :param account_id: :param resource_id: :return: """ return {SSM_PARAM_NAME.title: resource_id, SSM_PARAM_ARN.title: parameter.arn}
[docs]def handle_yaml_validation(resource: SsmParameter, value: str, file_path: str) -> str: """ Function to evaluate the JSON content :param SsmParamter resource: :param str value: Value read from file :param str file_path: :return: """ try: payload = yaml.load(value, Loader=Loader) if keyisset("RenderToJson", resource.parameters): return json.dumps(payload, separators=(",", ":")) return value except yaml.YAMLError: if keyisset("IgnoreInvalidYaml", resource.parameters): LOG.warn( f"{resource.name} - The content of {file_path} " "did not pass YAML validation. Skipping due to IgnoreInvalidYaml" ) return value else: LOG.error( f"{resource.name} - The content of {file_path} " "did not pass YAML validation." ) raise
[docs]def handle_json_validation(resource: SsmParameter, value: str, file_path: str) -> str: """ Function to evaluate the JSON content :param SsmParamter resource: :param str value: Value read from file :param str file_path: :return: """ try: payload = json.loads(value) if keyisset("MinimizeJson", resource.parameters): return json.dumps(payload, separators=(",", ":")) return value except json.decoder.JSONDecodeError: if keyisset("IgnoreInvalidJson", resource.parameters): LOG.warn( f"{resource.name} - The content of {file_path} " "did not pass JSON validation. Skipping due to IgnoreInvalidJson" ) return value else: LOG.error( f"{resource.name} - The content of {file_path} " "did not pass JSON validation." ) raise
[docs]def import_value_from_file(resource: SsmParameter) -> str | Base64: """ Function to import file into the SSM Parameter value :param SsmParameter resource: :return: The value """ file_path = path.abspath(resource.parameters["FromFile"]) with open(file_path) as file_fd: value = file_fd.read() if keyisset("ValidateJson", resource.parameters): return handle_json_validation(resource, value, file_path) elif keyisset("ValidateYaml", resource.parameters): return handle_yaml_validation(resource, value, file_path) return value
[docs]def render_new_parameters( new_resources: list[SsmParameter], root_stack: ComposeXStack ) -> None: """ :param list[SsmParameter] new_resources: :param ecs_composex.common.stacks.ComposeXStack root_stack: """ for new_res in new_resources: value = None if ( keyisset("Type", new_res.definition) and new_res.definition["Type"] == "SecureString" ): raise ValueError(f"{new_res.name} AWS CFN does not support SecureString.") if new_res.parameters and keyisset("FromFile", new_res.parameters): value = import_value_from_file(new_res) if keyisset("Value", new_res.properties): if value: LOG.warn( "Both Value and FromFile properties were set. Using Value from Properties" ) value = new_res.properties["Value"] if not value: raise ValueError(f"{new_res.name} - Failed to determine the value") if keyisset("EncodeToBase64", new_res.parameters): value = Base64(value) new_res.properties.update({"Value": value}) param_props = import_record_properties( new_res.properties, CfnSsmParameter, ignore_missing_required=False ) new_res.cfn_resource = CfnSsmParameter(new_res.logical_name, **param_props) root_stack.stack_template.add_resource(new_res.cfn_resource) new_res.init_outputs() new_res.generate_outputs() add_outputs(root_stack.stack_template, new_res.outputs)