def generate_sqs_root_template(settings): """ Function to create the root DynamdoDB template. :param ecs_composex.common.settings.ComposeXSettings settings: Execution settings. :return: """ mono_template = False output_per_resource = 2 if not keyisset(RES_KEY, settings.compose_content): return None queues = settings.compose_content[RES_KEY] if (len(list(queues.keys())) * output_per_resource) <= CFN_MAX_OUTPUTS: mono_template = True template = build_template("DynamoDB for ECS ComposeX") for queue_name in queues: queue_res_name = NONALPHANUM.sub("", queue_name) queue_def = queues[queue_name] queue = define_queue(queue_name, queue_def, queues, mono_template) if queue: values = [ (SQS_URL, "Url", Ref(queue)), (SQS_ARN_T, "Arn", GetAtt(queue, "Arn")), (SQS_NAME_T, "Name", Ref(queue)), ] outputs = ComposeXOutput(queue, values, duplicate_attr=(not mono_template)) if mono_template: template.add_resource(queue) template.add_output(outputs.outputs) elif not mono_template: parameters = {} if hasattr(queue, "RedrivePolicy"): parameters.update({ DLQ_ARN_T: GetAtt( NONALPHANUM.sub( "", queue_def["Properties"]["RedrivePolicy"] ["deadLetterTargetArn"], ), f"Outputs.{SQS_ARN_T}", ) }) queue_template = build_template( f"Template for SQS queue {queue.title}", [DLQ_ARN]) queue_template.add_resource(queue) queue_template.add_output(outputs.outputs) queue_stack = ComposeXStack( queue_res_name, stack_template=queue_template, stack_parameters=parameters, ) template.add_resource(queue_stack) return template
def __init__(self, name, definition, mesh, nodes): """ Method to initialize the router :param str name: :param dict definition: :param troposphere.appmesh.Mesh mesh: The mesh to add the router to. :param dict nodes: list of nodes defined in the mesh. """ self.title = NONALPHANUM.sub("", name) self.definition = definition self.validate_definition() self.mesh = mesh self.port = self.definition[LISTENER_KEY][PORT_KEY] self.protocol = self.definition[LISTENER_KEY][PROTOCOL_KEY] self.raw_routes = self.definition[ROUTES_KEY] self.routes = [] self.nodes = [] self.router = appmesh.VirtualRouter( f"VirtualRouter{self.title}", MeshName=appmesh_conditions.get_mesh_name(mesh), MeshOwner=appmesh_conditions.set_mesh_owner_id(), VirtualRouterName=Sub(f"{self.title}-vr-${{AWS::StackName}}"), Spec=appmesh.VirtualRouterSpec(Listeners=[ appmesh.VirtualRouterListener(PortMapping=appmesh.PortMapping( Port=self.port, Protocol=self.protocol)) ]), ) self.add_routes(nodes)
def create_kms_template(settings): """ :param ecs_composex.common.settings.ComposeXSettings settings: :return: """ mono_template = False template = build_template("Root template for KMS") if not keyisset(RES_KEY, settings.compose_content): return keys = settings.compose_content[RES_KEY] if len(list(keys.keys())) <= CFN_MAX_OUTPUTS: mono_template = True for key_name in keys: key_res_name = NONALPHANUM.sub("", key_name) key = generate_key(key_name, key_res_name, keys[key_name]) if key: values = [ (KMS_KEY_ARN_T, "Arn", GetAtt(key, "Arn")), (KMS_KEY_ID_T, "Name", Ref(key)), ] outputs = ComposeXOutput(key, values, True) if mono_template: template.add_resource(key) handle_key_settings(template, key, keys[key_name]) template.add_output(outputs.outputs) elif not mono_template: key_template = build_template(f"Template for DynamoDB key {key.title}") key_template.add_resource(key) key_template.add_output(outputs.outputs) key_stack = ComposeXStack(key_res_name, stack_template=key_template) template.add_resource(key_stack) return template
def set_services_mount_points(family): """ Method to set the mount points to the Container Definition of the defined service if the volume["volume"] is none, this is not a shared volume, which then works only when not using Fargate (i.e. EC2 host/ ECS Anywhere) """ for service in family.services: mount_points = [] if not hasattr(service.container_definition, "MountPoints"): setattr(service.container_definition, "MountPoints", mount_points) else: mount_points = getattr(service.container_definition, "MountPoints") for volume in service.volumes: if keyisset("volume", volume): mnt_point = MountPoint( ContainerPath=volume["target"], ReadOnly=volume["read_only"], SourceVolume=volume["volume"].volume_name, ) else: mnt_point = If( USE_FARGATE_CON_T, NoValue, MountPoint( ContainerPath=volume["target"], ReadOnly=volume["read_only"], SourceVolume=NONALPHANUM.sub("", volume["target"]), ), ) if not mount_point_exists(mount_points, mnt_point, family, service): mount_points.append(mnt_point)
def handle_families_targets_expansion_dict(self, service_name, service, settings) -> None: """ Method to list all families and services that are targets of the resource. Allows to implement family and service level association to resource :param str service_name: :param dict service: Service definition in compose file :param ecs_composex.common.settings.ComposeXSettings settings: Execution settings """ for svc in settings.services: if svc.name == service_name: the_service = svc break else: raise KeyError( f"Service {service_name} not found in ", [_svc.name for _svc in settings.services], ) for family_name in the_service.families: family_name = NONALPHANUM.sub("", family_name) if family_name not in [f[0].name for f in self.families_targets]: self.families_targets.append(( settings.families[family_name], False, [the_service], service["Access"] if keyisset("Access", service) else {}, service, ))
def handle_families_services(families, cluster_sg, settings): """ Function to handle creation of services within the same family. :return: """ services = {} for family_name in families: family_resource_name = NONALPHANUM.sub("", family_name) template = initialize_service_template(family_resource_name) family = families[family_name] family_service_configs = {} family_parameters = {} for service_name in family: service = settings.compose_content[ ecs_params.RES_KEY][service_name] if keyisset("deploy", service): service["deploy"].update(get_deploy_labels(service)) print(service["deploy"]) service_config = ServiceConfig( settings.compose_content, service_name, service, family_name=family_resource_name, ) family_service_configs[service_name] = { "config": service_config, "priority": 0, "definition": service, } task = Task(template, family_service_configs, family_parameters, settings) family_parameters.update(task.stack_parameters) service = Service( template=template, family_name=family_resource_name, task_definition=task, config=task.family_config, settings=settings, ) service.parameters.update({ CLUSTER_NAME_T: Ref(CLUSTER_NAME), ROOT_STACK_NAME_T: Ref(ROOT_STACK_NAME), ecs_params.CLUSTER_SG_ID_T: Ref(cluster_sg), dns_params.PRIVATE_DNS_ZONE_ID.title: Ref(dns_params.PRIVATE_DNS_ZONE_ID), dns_params.PRIVATE_DNS_ZONE_NAME.title: Ref(dns_params.PRIVATE_DNS_ZONE_NAME), dns_params.PUBLIC_DNS_ZONE_ID.title: Ref(dns_params.PUBLIC_DNS_ZONE_ID), dns_params.PUBLIC_DNS_ZONE_NAME.title: Ref(dns_params.PUBLIC_DNS_ZONE_NAME), }) service.parameters.update(family_parameters) LOG.debug(f"Service {family_resource_name} added.") services[family_resource_name] = service return services
def add_gateway_endpoint(service, rtbs, template): """ Function to add a service endpoint for gateways """ VPCEndpoint( NONALPHANUM.sub("", f"{service['service']}Endpoint"), template=template, ServiceName=Sub(f"com.amazonaws.${{AWS::Region}}.{service['service']}"), RouteTableIds=[Ref(rtb) for rtb in rtbs], VpcEndpointType="Gateway", VpcId=Ref(template.resources[VPC_T]), )
def set_services_targets(self, settings): """ Method to map services and families targets of the services defined. TargetStructure: (family, family_wide, services[], access) :param ecs_composex.common.settings.ComposeXSettings settings: :return: """ if not self.services: LOG.debug( f"{self.module.res_key}.{self.name} No Services defined.") return for service_def in self.services: family_combo_name = service_def["name"] service_name = family_combo_name.split(":")[-1] family_name = NONALPHANUM.sub("", family_combo_name.split(":")[0]) LOG.info( f"{self.module.res_key}.{self.name} - Adding target {family_name}:{service_name}" ) if family_name not in settings.families: raise ValueError( f"{self.module.res_key}.{self.name} - Service family {family_name} is invalid. Defined families", settings.families.keys(), ) for f_service in settings.families[family_name].ordered_services: if f_service.name == service_name: if f_service not in settings.services: raise ValueError( f"{self.module.res_key}.{self.name} Please, use only the services names." "You cannot use the family name defined by deploy labels" f"Found {f_service}", [s for s in settings.services], [f for f in settings.families], ) elif (f_service.name == service_name and f_service in settings.services and f_service not in self.families_targets): self.families_targets.append(( f_service.family, f_service, service_def, f"{service_def['name']}{service_def['port']}", )) break else: raise ValueError( f"{self.module.res_key}.{self.name} - Could not find {service_name} in family {family_name}" ) self.debug_families_targets()
def add_interface_endpoint(sg, service, subnets, template): """ Function to add a service endpoint for gateways """ VPCEndpoint( NONALPHANUM.sub("", f"{service['service']}Endpoint"), template=template, ServiceName=Sub(f"com.amazonaws.${{AWS::Region}}.{service['service']}"), SubnetIds=[Ref(subnet) for subnet in subnets], VpcEndpointType="Interface", VpcId=Ref(template.resources[VPC_T]), SecurityGroupIds=[Ref(sg)], PrivateDnsEnabled=True, )
def __init__( self, name, stack_template, stack_parameters=None, file_name=None, module_name=None, module=None, **kwargs, ): """ Class to keep track of the template object along with the stack object it represents. :param title: title of the resource in the root template :param stack_template: the template object to keep track of :param dict stack_parameters: Stack parameters to set :param kwargs: kwargs from composex along with the kwargs for the stack """ self.name = name self.parent_stack = None if module_name is None: self.module_name = path.basename( path.dirname(path.abspath(__file__))) else: self.module_name = module_name title = NONALPHANUM.sub("", self.name) self.file_name = file_name if file_name else title self.lookup_resources = [] if not isinstance(stack_template, Template): raise TypeError("stack_template is", type(stack_template), "expected", Template) self.stack_template = stack_template if stack_parameters is None: self.stack_parameters = {} elif not isinstance(stack_parameters, dict): raise TypeError("parameters is", type(stack_parameters), "expected", dict) stack_kwargs = {x: kwargs[x] for x in self.props.keys() if x in kwargs} stack_kwargs.update( {x: kwargs[x] for x in self.attributes if x in kwargs}) if stack_parameters: stack_kwargs.update({"Parameters": stack_parameters}) else: stack_kwargs.update({"Parameters": {}}) super().__init__(title, **stack_kwargs) if not hasattr(self, "DependsOn") or not keyisset("DependsOn", kwargs): self.DependsOn = []
def define_topic(topic_name, topic, content): """ Function that builds the SNS topic template from Dockerfile Properties """ properties = topic["Properties"] if keyisset("Properties", topic) else {} topic = Topic(NONALPHANUM.sub("", topic_name), Metadata=metadata) if keyisset(SUBSCRIPTIONS_KEY, properties): subscriptions = define_topic_subscriptions( properties[SUBSCRIPTIONS_KEY], content ) setattr(topic, "Subscription", subscriptions) for key in properties.keys(): if type(properties[key]) != list: setattr(topic, key, properties[key]) return topic
def create_ext_sources_ingress_rule(self, destination_title, allowed_source, security_group, **props) -> None: """ Creates the Security Ingress rule for a CIDR based rule :param str destination_title: :param dict allowed_source: :param security_group: :param dict props: """ for port in self.ports: target_port = set_else_none("published", port, alt_value=set_else_none( "target", port, None)) if target_port is None: raise ValueError( "Wrong port definition value for security group ingress", port) if (keyisset("Ports", allowed_source) and target_port not in allowed_source["Ports"]): continue if keyisset("Name", allowed_source): name = NONALPHANUM.sub("", allowed_source["Name"]) title = f"From{name.title()}To{target_port}{port['protocol']}" description = Sub( f"From {name.title()} " f"To {target_port}{port['protocol']} for {destination_title}" ) else: title = (f"From{flatten_ip(allowed_source[self.ipv4_key])}" f"To{target_port}{port['protocol']}") description = Sub(f"Public {target_port}{port['protocol']}" f" for {destination_title}") self.ext_ingress_rules.append( SecurityGroupIngress( title, Description=description if not keyisset("Description", allowed_source) else allowed_source["Description"], GroupId=security_group, IpProtocol=port["protocol"], FromPort=target_port, ToPort=target_port, **props, ))
def set_attributes_from_mapping(self, attribute_parameter): """ Method to define the attribute outputs for lookup resources, which use FindInMap or Ref :param attribute_parameter: The parameter mapped to the resource attribute :type attribute_parameter: ecs_composex.common.cfn_params.Parameter :return: The FindInMap setting for mapped resource """ if attribute_parameter.return_value: return FindInMap( self.module.mapping_key, self.logical_name, NONALPHANUM.sub("", attribute_parameter.return_value), ) else: return FindInMap(self.module.mapping_key, self.logical_name, attribute_parameter.title)
def render_new_queues(settings, new_queues, queues, xstack, template): """ Function to create the root DynamdoDB template. :param ecs_composex.common.settings.ComposeXSettings settings: Execution settings. """ mono_template = False output_per_resource = 3 if (len(new_queues) * output_per_resource) <= CFN_MAX_OUTPUTS: mono_template = True for queue in new_queues: queue.stack = xstack define_queue(queue, queues, mono_template) if queue.cfn_resource: queue.init_outputs() queue.generate_outputs() if mono_template: template.add_resource(queue.cfn_resource) template.add_output(queue.outputs) elif not mono_template: parameters = {} if hasattr(queue, "RedrivePolicy"): parameters.update({ DLQ_ARN_T: GetAtt( NONALPHANUM.sub( "", queues[queue.name].definition["Properties"] ["RedrivePolicy"]["deadLetterTargetArn"], ), f"Outputs.{SQS_ARN_T}", ) }) queue_template = build_template( f"Template for SQS queue {queue.cfn_resource.title}", [DLQ_ARN], ) queue_template.add_resource(queue.cfn_resource) queue_template.add_output(queue.outputs) queue_stack = ComposeXStack( queue.logical_name, stack_template=queue_template, stack_parameters=parameters, ) template.add_resource(queue_stack)
def generate_cfn_mappings_from_lookup_properties(self): """ Sets the .mappings attribute based on the lookup_attributes for CFN purposes """ for parameter, value in self.lookup_properties.items(): if not isinstance(parameter, Parameter): raise TypeError( f"{self.module.res_key}.{self.name} - lookup attribute {parameter} is", parameter, type(parameter), "Expected", Parameter, ) if parameter.return_value: self.mappings[NONALPHANUM.sub("", parameter.return_value)] = value else: self.mappings[parameter.title] = value
def create_root_stack(settings: ComposeXSettings) -> ComposeXStack: """ Initializes the root stack template and ComposeXStack :param ecs_composex.common.settings.ComposeXSettings settings: The settings for the execution """ template = init_template("Root template generated via ECS ComposeX") template.add_mapping("ComposeXDefaults", {"ECS": { "PlatformVersion": "1.4.0" }}) root_stack_title = NONALPHANUM.sub("", settings.name.title()) root_stack = ComposeXStack( root_stack_title, stack_template=template, file_name=settings.name, ) return root_stack
def handle_family_scaling_expansion(self, service, settings): """ Method to search for the families of given service and add it if not already present :param dict service: :param ecs_composex.common.settings.ComposeXSettings settings: :return: """ name_key = get_setting_key("name", service) scaling_key = get_setting_key("scaling", service) the_service = [ s for s in settings.services if s.name == service[name_key] ][0] for family_name in the_service.families: family_name = NONALPHANUM.sub("", family_name) if family_name not in [f[0].name for f in self.families_scaling]: self.families_scaling.append( (settings.families[family_name], service[scaling_key]))
def __init__(self, name, definition, settings): """ Method to init Secret for ECS ComposeX :param str name: :param dict definition: :param ecs_composex.common.settings.ComposeXSettings settings: """ self.services = [] if not any(key in definition[self.x_key].keys() for key in self.allowed_keys): raise KeyError( "You must define at least one of", self.allowed_keys, "Got", definition.keys(), ) elif not all(key in self.valid_keys for key in definition[self.x_key].keys()): raise KeyError( "Only valid keys are", self.valid_keys, "Got", definition[self.x_key].keys(), ) self.name = name self.logical_name = NONALPHANUM.sub("", self.name) self.definition = deepcopy(definition) self.links = [EXEC_ROLE_T] self.arn = None self.iam_arn = None self.aws_name = None self.kms_key = None self.kms_key_arn = None self.ecs_secret = [] self.mapping = {} if not keyisset("Lookup", self.definition[self.x_key]): self.define_names_from_import() else: self.define_names_from_lookup(settings.session) self.define_links() if self.mapping: settings.secrets_mappings.update({self.logical_name: self.mapping}) self.add_json_keys()
def __init__(self, name, definition, routers, nodes, mesh, settings): """ Method to initialize the Mesh service. :param name: name of the virtual service :param routers: the routers of the mesh :param nodes: the nodes of the mesh :param mesh: the mesh object. """ self.title = NONALPHANUM.sub("", name) self.definition = definition service_node = (nodes[self.definition[NODE_KEY]] if keyisset( NODE_KEY, self.definition) else None) service_router = (routers[self.definition[ROUTER_KEY]] if keyisset( ROUTER_KEY, self.definition) else None) if not service_router and not service_node: raise AttributeError( f"The service {name} has neither nodes or routers defined. Define at least one" ) depends = [] self.node = service_node if service_node else None self.router = service_router if service_router else None self.service = appmesh.VirtualService( f"{NONALPHANUM.sub('', name).title()}VirtualService", DependsOn=depends, MeshName=appmesh_conditions.get_mesh_name(mesh), MeshOwner=appmesh_conditions.set_mesh_owner_id(), VirtualServiceName=Sub( f"{name}.${{ZoneName}}", ZoneName=settings.private_zone.name_value, ), Spec=appmesh.VirtualServiceSpec( Provider=appmesh.VirtualServiceProvider( VirtualNode=appmesh.VirtualNodeServiceProvider( VirtualNodeName=service_node.get_node_param ) if service_node else Ref(AWS_NO_VALUE), VirtualRouter=appmesh.VirtualRouterServiceProvider( VirtualRouterName=GetAtt(service_router. router, "VirtualRouterName") ) if service_router else Ref(AWS_NO_VALUE), )), )
def handle_families_scaling_expansion_dict(self, service_name, service, settings): """ Method to list all families and services that are targets of the resource. Allows to implement family and service level association to resource :param str service_name: :param dict service: Service definition in compose file :param ecs_composex.common.settings.ComposeXSettings settings: Execution settings """ the_service = [s for s in settings.services if s.name == service_name][0] for family_name in the_service.families: family_name = NONALPHANUM.sub("", family_name) if family_name not in [f[0].name for f in self.families_scaling]: self.families_scaling.append(( settings.families[family_name], service["Scaling"], ))
def set_volumes(family): """ Method to create the volumes definition to the Task Definition :return: """ family_task_volumes = define_shared_volumes(family) host_volumes = define_host_volumes(family) if not hasattr(family.task_definition, "Volumes"): family_definition_volumes = [] setattr(family.task_definition, "Volumes", family_definition_volumes) else: family_definition_volumes = getattr(family.task_definition, "Volumes") for volume in family_task_volumes: if volume.type == "volume" and volume.driver == "local": volume.cfn_volume = Volume( Host=NoValue, Name=volume.volume_name, DockerVolumeConfiguration=If( USE_FARGATE_CON_T, NoValue, DockerVolumeConfiguration( Scope="task" if not volume.is_shared else "shared", Autoprovision=NoValue if not volume.is_shared else True, ), ), ) if volume.cfn_volume: family_definition_volumes.append(volume.cfn_volume) for volume_config in host_volumes: cfn_volume = If( USE_FARGATE_CON_T, NoValue, Volume( Host=Host(SourcePath=volume_config["source"]), DockerVolumeConfiguration=NoValue, Name=NONALPHANUM.sub("", volume_config["target"]), ), ) family_definition_volumes.append(cfn_volume) set_services_mount_points(family)
def apply_iam_based_resources( resource_def, services_families, services_stack, res_root_stack, envvars, perms, nested=False, ): """ Function to assign resource to services stack :param dict resource_def: :param dict services_families: :param ecs_composex.common.stacks.ComposeXStack services_stack: :param ecs_composex.common.stacks.ComposeXStack res_root_stack: :raises KeyError: if the service name is not a listed service in docker-compose. """ if not keyisset("Services", resource_def): return for service in resource_def["Services"]: service_family = get_service_family_name(services_families, service["name"]) if (not service_family or service_family not in services_stack.stack_template.resources): raise ValueError( f"Service {service_family} not in the services stack", services_stack.stack_template.resources, ) family_wide = True if service["name"] in services_families else False service_stack = services_stack.stack_template.resources[service_family] add_iam_policy_to_service_task_role( service_stack.stack_template, perms, envvars, service["access"], NONALPHANUM.sub("", service["name"]), family_wide, ) LOG.debug(f"{res_root_stack.title} - {nested}") if res_root_stack.title not in services_stack.DependsOn and not nested: services_stack.add_dependencies(res_root_stack.title)
def add_certificates(acm_tpl, certs): """ Function to add all the ACM certs together :param acm_tpl: :param certs: :return: """ for cert_name in certs: resource_name = NONALPHANUM.sub("", cert_name) cert_def = certs[cert_name] cert_props = cert_def["Properties"] cert_params = build_cert_params(cert_props) cert_params.update(pass_root_stack_name()) cert_template = initialize_acm_stack_template(resource_name) acm_tpl.add_resource( ComposeXStack( resource_name, stack_template=cert_template, Parameters=cert_params, ))
def create_dynamodb_template(settings): """ Function to create the root DynamdoDB template. :param ecs_composex.common.settings.ComposeXSettings settings: :return: """ mono_template = False if not keyisset(RES_KEY, settings.compose_content): return None tables = settings.compose_content[RES_KEY] if len(list(tables.keys())) <= CFN_MAX_OUTPUTS: mono_template = True template = build_template("DynamoDB for ECS ComposeX") for table_name in tables: table_res_name = NONALPHANUM.sub("", table_name) table = generate_table(table_name, table_res_name, tables[table_name]) if table: values = [ (TABLE_ARN_T, "Arn", GetAtt(table, "Arn")), (TABLE_NAME_T, "Name", Ref(table)), ] outputs = ComposeXOutput(table, values, True) if mono_template: template.add_resource(table) template.add_output(outputs.outputs) elif not mono_template: table_template = build_template( f"Template for DynamoDB table {table.title}" ) table_template.add_resource(table) table_template.add_output(outputs.outputs) table_stack = ComposeXStack( table_res_name, stack_template=table_template ) template.add_resource(table_stack) return template
def set_queue(queue_name, properties, redrive_policy=None): """ Function to define and set the SQS Queue :param str queue_name: name of the queue :param dict properties: queue properties :param dict redrive_policy: redrive policy in case it has been defined :return: queue :rtype: troposphere.sqs.Queue """ res_name = NONALPHANUM.sub("", queue_name) if redrive_policy is not None: properties.update(redrive_policy) if keyisset("QueueName", properties): queue_name = properties["QueueName"] properties.pop("QueueName") properties["QueueName"] = Sub(f"${{{ROOT_STACK_NAME_T}}}-{queue_name}") if keyisset("FifoQueue", properties): properties["QueueName"] = Sub( f"${{{ROOT_STACK_NAME_T}}}-{queue_name}.fifo") queue = Queue(res_name, **properties) return queue
def handle_families_targets_expansion(self, service, settings): """ Method to list all families and services that are targets of the resource. Allows to implement family and service level association to resource :param dict service: Service definition in compose file :param ecs_composex.common.settings.ComposeXSettings settings: Execution settings """ name_key = get_setting_key("name", service) access_key = get_setting_key("access", service) the_service = [ s for s in settings.services if s.name == service[name_key] ][0] for family_name in the_service.families: family_name = NONALPHANUM.sub("", family_name) if family_name not in [f[0].name for f in self.families_targets]: self.families_targets.append(( settings.families[family_name], False, [the_service], service[access_key], service, ))
def set_families(self): """ Method to define the list of families :return: """ assigned_services = [] for service in self.services: for family_name in service.families: formatted_name = sub(r"[^a-zA-Z0-9]+", "", family_name) if NONALPHANUM.findall(formatted_name): raise ValueError( "Family names must be ^[a-zA-Z0-9]+$ | alphanumerical" ) if formatted_name not in self.families.keys(): self.add_new_family(family_name, service, assigned_services) elif formatted_name in self.families.keys() and service.name not in [ _service.name for _service in self.families[formatted_name].ordered_services ]: self.add_service_to_family( formatted_name, service, assigned_services ) LOG.debug([self.families[family] for family in self.families])
def create_dashboards(settings: ComposeXSettings, x_stack: ComposeXStack, module: XResourceModule) -> None: """ Loop to iterate over dashboards definitions :param ecs_composex.common.settings.ComposeXSettings settings: :param ecs_composex.common.stacks.ComposeXStack x_stack: :param ModManager module: """ if not keyisset(module.res_key, settings.compose_content): LOG.error(f"No {module.res_key} defined") dashboards = settings.compose_content[module.res_key] for name, dashboard in dashboards.items(): widgets = [] if keyisset("Services", dashboard): service_params = retrieve_services(settings, dashboard["Services"], x_stack) y_index = 0 for param in service_params: service_ecs_widgets = ServiceEcsWidget(param[0], param[1], CLUSTER_NAME, y_index=y_index) widgets += service_ecs_widgets.widgets y_index += service_ecs_widgets.height + 1 dashboard_body_header = {"start": "-PT12H", "widgets": widgets} dashboard_body = Sub(json.dumps(dashboard_body_header)) cfn_dashboard = CWDashboard( NONALPHANUM.sub("", name), DashboardBody=dashboard_body, DashboardName=Sub( f"${{StackName}}--{name}", StackName=define_stack_name(x_stack.template), ), ) x_stack.stack_template.add_resource(cfn_dashboard)
def logical_name(self) -> str: return NONALPHANUM.sub("", self.name)
# SPDX-License-Identifier: MPL-2.0 # Copyright 2020-2022 John Mille <*****@*****.**> """ Parameters specific to AWS ACM """ from os import path from ecs_composex.common import NONALPHANUM from ecs_composex.common.cfn_params import Parameter from ecs_composex.common.ecs_composex import X_KEY MOD_KEY = f"{path.basename(path.dirname(path.abspath(__file__)))}" RES_KEY = f"{X_KEY}{MOD_KEY}" MAPPINGS_KEY = NONALPHANUM.sub("", MOD_KEY) VALIDATION_DOMAIN_NAME_T = "ValidationDomainName" VALIDATION_DOMAIN_NAME = Parameter( VALIDATION_DOMAIN_NAME_T, Type="String", Default="none", AllowedPattern=r"(^none$|^(\*\.)?(((?!-)[A-Za-z0-9-]{0,62}[A-Za-z0-9])\.)+((?!-)[A-Za-z0-9-]{1,62}[A-Za-z0-9])$)", ) VALIDATION_DOMAIN_ZONE_ID_T = "ValidationZoneId" VALIDATION_DOMAIN_ZONE_ID = Parameter( VALIDATION_DOMAIN_ZONE_ID_T, Type="String", AllowedPattern=r"(none|^Z[A-Z0-9]+$)",