Source code for ecs_composex.ecs.ecs_template

#  -*- coding: utf-8 -*-
# SPDX-License-Identifier: MPL-2.0
# Copyright 2020-2021 John Mille <john@compose-x.io>

"""
Core ECS Template building
"""

from troposphere import GetAtt, Ref, Sub
from troposphere.iam import PolicyType
from troposphere.logs import LogGroup

from ecs_composex.common import build_template
from ecs_composex.common.cfn_params import ROOT_STACK_NAME, ROOT_STACK_NAME_T
from ecs_composex.dns import dns_conditions, dns_params
from ecs_composex.dns.dns_conditions import (
    CREATE_PUBLIC_NAMESPACE_CON,
    CREATE_PUBLIC_NAMESPACE_CON_T,
)
from ecs_composex.ecs import ecs_conditions, ecs_params
from ecs_composex.ecs.ecs_params import CLUSTER_NAME, CLUSTER_NAME_T
from ecs_composex.ecs.ecs_service import Service
from ecs_composex.ecs.ecs_service_config import ServiceConfig
from ecs_composex.secrets.secrets_params import RES_KEY as SECRETS_KEY
from ecs_composex.vpc import vpc_params


[docs]def initialize_service_template(service_name): """Function to initialize the base template for ECS Services with all parameters and conditions necessary for CFN to work properly :param service_name: Name of the ecs_service as defined in ComposeX File :type service_name: str :return: service_template :rtype: troposphere.Template """ service_tpl = build_template( f"Template for {service_name}", [ dns_params.PUBLIC_DNS_ZONE_NAME, dns_params.PRIVATE_DNS_ZONE_NAME, dns_params.PUBLIC_DNS_ZONE_ID, dns_params.PRIVATE_DNS_ZONE_ID, dns_params.PRIVATE_NAMESPACE_ID, ecs_params.CLUSTER_NAME, ecs_params.LAUNCH_TYPE, ecs_params.ECS_CONTROLLER, ecs_params.SERVICE_COUNT, ecs_params.CLUSTER_SG_ID, ecs_params.SERVICE_HOSTNAME, ecs_params.FARGATE_CPU_RAM_CONFIG, ecs_params.SERVICE_NAME, ecs_params.ELB_GRACE_PERIOD, ecs_params.FARGATE_VERSION, ecs_params.LOG_GROUP_RETENTION, vpc_params.VPC_ID, vpc_params.APP_SUBNETS, vpc_params.PUBLIC_SUBNETS, ], ) service_tpl.add_condition( ecs_conditions.SERVICE_COUNT_ZERO_CON_T, ecs_conditions.SERVICE_COUNT_ZERO_CON, ) service_tpl.add_condition( ecs_conditions.SERVICE_COUNT_ZERO_AND_FARGATE_CON_T, ecs_conditions.SERVICE_COUNT_ZERO_AND_FARGATE_CON, ) service_tpl.add_condition( ecs_conditions.USE_HOSTNAME_CON_T, ecs_conditions.USE_HOSTNAME_CON ) service_tpl.add_condition( ecs_conditions.NOT_USE_HOSTNAME_CON_T, ecs_conditions.NOT_USE_HOSTNAME_CON, ) service_tpl.add_condition( ecs_conditions.NOT_USE_CLUSTER_SG_CON_T, ecs_conditions.NOT_USE_CLUSTER_SG_CON, ) service_tpl.add_condition( ecs_conditions.USE_CLUSTER_SG_CON_T, ecs_conditions.USE_CLUSTER_SG_CON ) service_tpl.add_condition( ecs_conditions.USE_FARGATE_PROVIDERS_CON_T, ecs_conditions.USE_FARGATE_PROVIDERS_CON, ) service_tpl.add_condition( ecs_conditions.USE_FARGATE_LT_CON_T, ecs_conditions.USE_FARGATE_LT_CON ) service_tpl.add_condition( ecs_conditions.USE_FARGATE_CON_T, ecs_conditions.USE_FARGATE_CON, ) service_tpl.add_condition( ecs_conditions.NOT_FARGATE_CON_T, ecs_conditions.NOT_FARGATE_CON ) service_tpl.add_condition(ecs_conditions.USE_EC2_CON_T, ecs_conditions.USE_EC2_CON) service_tpl.add_condition( ecs_conditions.USE_SERVICE_MODE_CON_T, ecs_conditions.USE_SERVICE_MODE_CON ) service_tpl.add_condition( ecs_conditions.USE_CLUSTER_MODE_CON_T, ecs_conditions.USE_CLUSTER_MODE_CON ) service_tpl.add_condition( ecs_conditions.USE_LAUNCH_TYPE_CON_T, ecs_conditions.USE_LAUNCH_TYPE_CON ) service_tpl.add_condition( CREATE_PUBLIC_NAMESPACE_CON_T, CREATE_PUBLIC_NAMESPACE_CON ) service_tpl.add_condition( dns_conditions.PRIVATE_ZONE_ID_CON_T, dns_conditions.PRIVATE_ZONE_ID_CON ) service_tpl.add_condition( dns_conditions.PRIVATE_NAMESPACE_CON_T, dns_conditions.PRIVATE_NAMESPACE_CON, ) return service_tpl
[docs]def create_log_group(family): """ Function to create a new Log Group for the services :return: """ svc_log = family.template.add_resource( LogGroup( ecs_params.LOG_GROUP_T, RetentionInDays=Ref(ecs_params.LOG_GROUP_RETENTION), LogGroupName=Sub( f"${{{ROOT_STACK_NAME.title}}}/" f"svc/ecs/${{{ecs_params.CLUSTER_NAME_T}}}/{family.logical_name}", ), ), ) policy = PolicyType( f"{family.logical_name}LogGroupAccess", PolicyName=Sub(f"CloudWatchAccessForFamily{family.logical_name}"), PolicyDocument={ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowCloudWatchLoggingToSpecificLogGroup", "Effect": "Allow", "Action": ["logs:CreateLogStream", "logs:PutLogEvents"], "Resource": [GetAtt(svc_log, "Arn")], } ], }, Roles=[Ref(family.exec_role.name["ImportParameter"])], ) if ( family.template and f"{family.logical_name}LogGroupAccess" not in family.template.resources ): family.template.add_resource(policy)
[docs]def get_service_family_name(services_families, service_name): """ Function to return the root family name, representing the service stack name. :param services_families: :param service_name: :return: service stack name :rtype: str """ for family_name in services_families: if service_name in services_families[family_name]: return family_name if service_name in services_families.keys(): return service_name return None
[docs]def initialize_family_services(settings, family): """ Function to handle creation of services within the same family. :param ecs_composex.common.settings.ComposeXSettings settings: :return: """ if settings.secrets_mappings: family.template.add_mapping(SECRETS_KEY, settings.secrets_mappings) if SECRETS_KEY not in family.exec_role.stack.stack_template.resources: family.exec_role.stack.stack_template.add_mapping( SECRETS_KEY, settings.secrets_mappings ) family.init_task_definition() family.set_secrets_access() family.refresh() family.assign_policies() family.service_config = ServiceConfig(family, settings) family.ecs_service = Service(family, settings) family.service_config.network.set_aws_sources( settings, family.logical_name, GetAtt(family.ecs_service.sg, "GroupId"), ) family.service_config.network.set_ext_sources_ingress( family.logical_name, GetAtt(family.ecs_service.sg, "GroupId") ) family.service_config.network.associate_aws_igress_rules(family.template) family.service_config.network.associate_ext_igress_rules(family.template) family.service_config.network.add_self_ingress(family) family.merge_capacity_providers() family.validate_capacity_providers(settings.ecs_cluster) family.stack.Parameters.update( { ecs_params.SERVICE_NAME_T: family.logical_name, CLUSTER_NAME_T: Ref(CLUSTER_NAME), ROOT_STACK_NAME_T: Ref(ROOT_STACK_NAME), } ) family.upload_services_env_files(settings) family.set_repository_credentials(settings) family.set_volumes() create_log_group(family) family.handle_logging() family.handle_alarms() family.handle_prometheus() family.validate_compute_configuration_for_task(settings)