Source code for ecs_composex.ecs.service_compute
# SPDX-License-Identifier: MPL-2.0
# Copyright 2020-2022 John Mille <john@compose-x.io>
"""
Module to manage the ``compute`` settings of the ECS Service
* Launch Type
* Capacity Providers
Unrelated to the Task compute settings (RAM/CPU)
"""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ecs_composex.ecs.ecs_family import ComposeFamily
from troposphere import If, NoValue, Ref
from ecs_composex.common.logging import LOG
from ecs_composex.ecs.ecs_conditions import (
DISABLE_CAPACITY_PROVIDERS_CON_T,
USE_LAUNCH_TYPE_CON_T,
)
from ecs_composex.ecs.ecs_params import LAUNCH_TYPE
from .helpers import merge_capacity_providers
[docs]class ServiceCompute:
"""
Class to manage the ECS Service settings for launch type and capacity providers
"""
def __init__(self, family):
self.family: ComposeFamily = family
self._launch_type = None
self._ecs_capacity_providers = []
self._cfn_launch_type = None
self._cfn_capacity_providers = None
self.set_update_launch_type()
self.set_update_capacity_providers()
@property
def cfn_launch_type(self):
return If(USE_LAUNCH_TYPE_CON_T, Ref(LAUNCH_TYPE), NoValue)
@property
def launch_type(self):
return self._launch_type
@launch_type.setter
def launch_type(self, launch_type):
self._launch_type = launch_type
if self.family.stack:
self.family.stack.Parameters.update({LAUNCH_TYPE.title: self._launch_type})
@property
def ecs_capacity_providers(self):
return self._ecs_capacity_providers
@ecs_capacity_providers.setter
def ecs_capacity_providers(self, providers):
if not isinstance(providers, list):
raise TypeError(
"ECS Capacity Providers must be a list. Got", providers, type(providers)
)
self._ecs_capacity_providers = providers
if self.family.ecs_service and self.family.ecs_service.ecs_service:
self.apply_capacity_providers_to_service(providers)
[docs] def apply_capacity_providers_to_service(self, providers: list):
setattr(
self.family.ecs_service.ecs_service,
"CapacityProviderStrategy",
If(
DISABLE_CAPACITY_PROVIDERS_CON_T,
NoValue,
providers,
),
)
[docs] def set_update_capacity_providers(self) -> None:
"""
If the Launch Type is not EXTERNAL, will merge the capacity providers defined by the services.x-ecs
of the family services.
"""
if self.launch_type and self.launch_type != "EXTERNAL":
merge_capacity_providers(self)
[docs] def set_update_launch_type(self) -> None:
"""
Defines all the possible launch types defined on the services of the task into `launch_types`
If this is the first time we run the function, and we don't have either self.launch_type nor `launch_types`
we default to Fargate
Considering that `EXTERNAL` > `EC2` > `FARGATE` in priority, we stop at that launch_type as soon as any service
has it set in its properties.
If launch_type wasn't set, we stop at the highest priority type
If launch_type was already set, we evaluate it a new service might have a different launch_type, higher priority
If we are already all set, debug log it.
Otherwise, if somehow we didn't get into any of these conditions, pick default => Fargate
"""
launch_types = [
_svc.launch_type
for _svc in self.family.ordered_services
if _svc.launch_type
]
if not self.launch_type and not launch_types:
LOG.info(
"services.{} - No Launch Type defined. Using default: {}".format(
self.family.name, LAUNCH_TYPE.Default
)
)
self.launch_type = LAUNCH_TYPE.Default
return
launch_types_priority_ordered = ["EXTERNAL", "EC2", "FARGATE"]
for _launch_type in launch_types_priority_ordered:
type_in_family_launch_types: bool = _launch_type in launch_types
type_is_defined_launch_type: bool = self.launch_type == _launch_type
if not self.launch_type and type_in_family_launch_types:
LOG.info(
f"{self.family.name} - Init LaunchType {_launch_type}, requested by at least one service."
)
self.launch_type = _launch_type
break
elif (
self.launch_type
and type_in_family_launch_types
and not type_is_defined_launch_type
):
LOG.info(
f"{self.family.name} - A service in family requires {_launch_type} instead of {self.launch_type}."
" Overriding."
)
self.launch_type = _launch_type
break
elif (
self.launch_type
and type_in_family_launch_types
and type_is_defined_launch_type
):
LOG.debug(f"{self.family.name} is already set to {_launch_type}")
break
else:
LOG.debug(
"{} - Using default Launch Type - {}".format(
self.family.name, LAUNCH_TYPE.Default
)
)
self.launch_type = LAUNCH_TYPE.Default