Пример #1
0
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
Пример #2
0
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)
Пример #3
0
    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)
Пример #4
0
    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,
                ))
Пример #5
0
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
Пример #6
0
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
Пример #7
0
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]),
    )
Пример #8
0
    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()
Пример #9
0
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,
    )
Пример #10
0
    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 = []
Пример #11
0
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
Пример #12
0
    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,
                ))
Пример #13
0
    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)
Пример #14
0
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)
Пример #15
0
 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
Пример #16
0
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
Пример #17
0
    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]))
Пример #18
0
    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()
Пример #19
0
    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),
                )),
        )
Пример #20
0
    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"],
                ))
Пример #21
0
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)
Пример #22
0
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)
Пример #23
0
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,
            ))
Пример #24
0
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
Пример #25
0
    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,
                ))
Пример #26
0
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
Пример #27
0
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)
Пример #28
0
    def __init__(self, content, service_name, definition, family_name=None):
        """
        Function to initialize the ecs_service configuration
        :param content:
        """
        service_configs = keyset_else_novalue(
            self.master_key, definition, else_value={}
        )
        self.network = None
        self.iam = None

        self.lb_type = None
        self.healthcheck = None
        self.ext_sources = None
        self.aws_sources = None
        self.ingress_from_self = False
        self.is_public: False
        self.use_cloudmap = True
        self.use_appmesh = False
        self.boundary = None
        self.policies = []
        self.managed_policies = []
        self.container_start_condition = "START"
        self.service_name = service_name if service_name else "global"
        self.logs_retention_period = ecs_params.LOG_GROUP_RETENTION.Default
        if keyisset("x-appmesh", content):
            self.use_appmesh = True

        if keyisset(self.master_key, content):
            self.set_from_top_configs(content)
        if service_name and isinstance(service_configs, dict):
            self.define_service_config(content, service_name, service_configs)

        if not set(self.required_keys).issubset(set(definition)):
            raise AttributeError(
                "Required attributes for a ecs_service are", self.required_keys
            )
        self.family_dependents = []
        self.essential = False
        self.volumes = []
        self.links = (keyset_else_novalue("external_links", definition, else_value=[]),)
        self.service = None
        self.use_xray = False
        self.replicas = int(ecs_params.SERVICE_COUNT.Default)
        self.cpu_alloc = Ref(AWS_NO_VALUE)
        self.cpu_resa = Ref(AWS_NO_VALUE)
        self.mem_alloc = Ref(AWS_NO_VALUE)
        self.mem_resa = Ref(AWS_NO_VALUE)
        self.service_name = service_name
        self.resource_name = NONALPHANUM.sub("", service_name)
        self.command = (
            definition["command"].strip() if keyisset("command", definition) else None
        )
        self.entrypoint = keyset_else_novalue("entrypoint", definition, else_value=None)
        self.ports = (
            set_service_ports(definition["ports"])
            if keyisset("ports", definition)
            else []
        )
        self.ingress_mappings = define_ingress_mappings(self.ports)
        self.environment = keyset_else_novalue("environment", definition, else_value=[])
        self.hostname = keyset_else_novalue("hostname", definition, else_value=None)
        self.family_name = family_name
        self.set_service_deploy(definition)
        self.lb_service_name = service_name
        self.set_xray(definition)
        self.healthcheck = set_healthcheck(definition)
        self.depends_on = keyset_else_novalue("depends_on", definition, else_value=[])
Пример #29
0
 def logical_name(self) -> str:
     return NONALPHANUM.sub("", self.name)
Пример #30
0
# 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]+$)",