AmmarFahmy
adding all files
105b369
from typing import Optional, Dict, Any, List, TYPE_CHECKING
from pydantic import Field, field_validator
from pydantic_core.core_schema import FieldValidationInfo
from phi.app.base import AppBase # noqa: F401
from phi.app.context import ContainerContext
from phi.aws.app.context import AwsBuildContext
from phi.utils.log import logger
if TYPE_CHECKING:
from phi.aws.resource.base import AwsResource
from phi.aws.resource.ec2.security_group import SecurityGroup
from phi.aws.resource.ecs.cluster import EcsCluster
from phi.aws.resource.ecs.container import EcsContainer
from phi.aws.resource.ecs.service import EcsService
from phi.aws.resource.ecs.task_definition import EcsTaskDefinition
from phi.aws.resource.elb.listener import Listener
from phi.aws.resource.elb.load_balancer import LoadBalancer
from phi.aws.resource.elb.target_group import TargetGroup
class AwsApp(AppBase):
# -*- Workspace Configuration
# Path to the workspace directory inside the container
workspace_dir_container_path: str = "/usr/local/app"
# -*- Networking Configuration
# List of subnets for the app: Type: Union[str, Subnet]
# Added to the load balancer, target group, and ECS service
subnets: Optional[List[Any]] = None
# -*- ECS Configuration
ecs_cluster: Optional[Any] = None
# Create a cluster if ecs_cluster is None
create_ecs_cluster: bool = True
# Name of the ECS cluster
ecs_cluster_name: Optional[str] = None
ecs_launch_type: str = "FARGATE"
ecs_task_cpu: str = "1024"
ecs_task_memory: str = "2048"
ecs_service_count: int = 1
ecs_enable_service_connect: bool = False
ecs_service_connect_protocol: Optional[str] = None
ecs_service_connect_namespace: str = "default"
assign_public_ip: Optional[bool] = None
ecs_bedrock_access: bool = True
ecs_exec_access: bool = True
ecs_secret_access: bool = True
ecs_s3_access: bool = True
# -*- Security Group Configuration
# List of security groups for the ECS Service. Type: SecurityGroup
security_groups: Optional[List[Any]] = None
# If create_security_groups=True,
# Create security groups for the app and load balancer
create_security_groups: bool = True
# inbound_security_groups to add to the app security group
inbound_security_groups: Optional[List[Any]] = None
# inbound_security_group_ids to add to the app security group
inbound_security_group_ids: Optional[List[str]] = None
# -*- LoadBalancer Configuration
load_balancer: Optional[Any] = None
# Create a load balancer if load_balancer is None
create_load_balancer: bool = False
# Enable HTTPS on the load balancer
load_balancer_enable_https: bool = False
# ACM certificate for HTTPS
# load_balancer_certificate or load_balancer_certificate_arn
# is required if enable_https is True
load_balancer_certificate: Optional[Any] = None
# ARN of the certificate for HTTPS, required if enable_https is True
load_balancer_certificate_arn: Optional[str] = None
# Security groups for the load balancer: List[SecurityGroup]
# The App creates a security group for the load balancer if:
# load_balancer_security_groups is None
# and create_load_balancer is True
# and create_security_groups is True
load_balancer_security_groups: Optional[List[Any]] = None
# -*- Listener Configuration
listeners: Optional[List[Any]] = None
# Create a listener if listener is None
create_listeners: Optional[bool] = Field(None, validate_default=True)
# -*- TargetGroup Configuration
target_group: Optional[Any] = None
# Create a target group if target_group is None
create_target_group: Optional[bool] = Field(None, validate_default=True)
# HTTP or HTTPS. Recommended to use HTTP because HTTPS is handled by the load balancer
target_group_protocol: str = "HTTP"
# Port number for the target group
# If target_group_port is None, then use container_port
target_group_port: Optional[int] = None
target_group_type: str = "ip"
health_check_protocol: Optional[str] = None
health_check_port: Optional[str] = None
health_check_enabled: Optional[bool] = None
health_check_path: Optional[str] = None
health_check_interval_seconds: Optional[int] = None
health_check_timeout_seconds: Optional[int] = None
healthy_threshold_count: Optional[int] = None
unhealthy_threshold_count: Optional[int] = None
# -*- Add NGINX reverse proxy
enable_nginx: bool = False
nginx_image: Optional[Any] = None
nginx_image_name: str = "nginx"
nginx_image_tag: str = "1.25.2-alpine"
nginx_container_port: int = 80
@field_validator("create_listeners", mode="before")
def update_create_listeners(cls, create_listeners, info: FieldValidationInfo):
if create_listeners:
return create_listeners
# If create_listener is False, then create a listener if create_load_balancer is True
return info.data.get("create_load_balancer", None)
@field_validator("create_target_group", mode="before")
def update_create_target_group(cls, create_target_group, info: FieldValidationInfo):
if create_target_group:
return create_target_group
# If create_target_group is False, then create a target group if create_load_balancer is True
return info.data.get("create_load_balancer", None)
def get_container_context(self) -> Optional[ContainerContext]:
logger.debug("Building ContainerContext")
if self.container_context is not None:
return self.container_context
workspace_name = self.workspace_name
if workspace_name is None:
raise Exception("Could not determine workspace_name")
workspace_root_in_container = self.workspace_dir_container_path
if workspace_root_in_container is None:
raise Exception("Could not determine workspace_root in container")
workspace_parent_paths = workspace_root_in_container.split("/")[0:-1]
workspace_parent_in_container = "/".join(workspace_parent_paths)
self.container_context = ContainerContext(
workspace_name=workspace_name,
workspace_root=workspace_root_in_container,
workspace_parent=workspace_parent_in_container,
)
if self.workspace_settings is not None and self.workspace_settings.scripts_dir is not None:
self.container_context.scripts_dir = f"{workspace_root_in_container}/{self.workspace_settings.scripts_dir}"
if self.workspace_settings is not None and self.workspace_settings.storage_dir is not None:
self.container_context.storage_dir = f"{workspace_root_in_container}/{self.workspace_settings.storage_dir}"
if self.workspace_settings is not None and self.workspace_settings.workflows_dir is not None:
self.container_context.workflows_dir = (
f"{workspace_root_in_container}/{self.workspace_settings.workflows_dir}"
)
if self.workspace_settings is not None and self.workspace_settings.workspace_dir is not None:
self.container_context.workspace_dir = (
f"{workspace_root_in_container}/{self.workspace_settings.workspace_dir}"
)
if self.workspace_settings is not None and self.workspace_settings.ws_schema is not None:
self.container_context.workspace_schema = self.workspace_settings.ws_schema
if self.requirements_file is not None:
self.container_context.requirements_file = f"{workspace_root_in_container}/{self.requirements_file}"
return self.container_context
def get_container_env(self, container_context: ContainerContext, build_context: AwsBuildContext) -> Dict[str, str]:
from phi.constants import (
PHI_RUNTIME_ENV_VAR,
PYTHONPATH_ENV_VAR,
REQUIREMENTS_FILE_PATH_ENV_VAR,
SCRIPTS_DIR_ENV_VAR,
STORAGE_DIR_ENV_VAR,
WORKFLOWS_DIR_ENV_VAR,
WORKSPACE_DIR_ENV_VAR,
WORKSPACE_HASH_ENV_VAR,
WORKSPACE_ID_ENV_VAR,
WORKSPACE_ROOT_ENV_VAR,
)
# Container Environment
container_env: Dict[str, str] = self.container_env or {}
container_env.update(
{
"INSTALL_REQUIREMENTS": str(self.install_requirements),
"PRINT_ENV_ON_LOAD": str(self.print_env_on_load),
PHI_RUNTIME_ENV_VAR: "ecs",
REQUIREMENTS_FILE_PATH_ENV_VAR: container_context.requirements_file or "",
SCRIPTS_DIR_ENV_VAR: container_context.scripts_dir or "",
STORAGE_DIR_ENV_VAR: container_context.storage_dir or "",
WORKFLOWS_DIR_ENV_VAR: container_context.workflows_dir or "",
WORKSPACE_DIR_ENV_VAR: container_context.workspace_dir or "",
WORKSPACE_ROOT_ENV_VAR: container_context.workspace_root or "",
}
)
try:
if container_context.workspace_schema is not None:
if container_context.workspace_schema.id_workspace is not None:
container_env[WORKSPACE_ID_ENV_VAR] = str(container_context.workspace_schema.id_workspace) or ""
if container_context.workspace_schema.ws_hash is not None:
container_env[WORKSPACE_HASH_ENV_VAR] = container_context.workspace_schema.ws_hash
except Exception:
pass
if self.set_python_path:
python_path = self.python_path
if python_path is None:
python_path = container_context.workspace_root
if self.add_python_paths is not None:
python_path = "{}:{}".format(python_path, ":".join(self.add_python_paths))
if python_path is not None:
container_env[PYTHONPATH_ENV_VAR] = python_path
# Set aws region and profile
self.set_aws_env_vars(env_dict=container_env, aws_region=build_context.aws_region)
# Update the container env using env_file
env_data_from_file = self.get_env_file_data()
if env_data_from_file is not None:
container_env.update({k: str(v) for k, v in env_data_from_file.items() if v is not None})
# Update the container env using secrets_file
secret_data_from_file = self.get_secret_file_data()
if secret_data_from_file is not None:
container_env.update({k: str(v) for k, v in secret_data_from_file.items() if v is not None})
# Update the container env with user provided env_vars
# this overwrites any existing variables with the same key
if self.env_vars is not None and isinstance(self.env_vars, dict):
container_env.update({k: v for k, v in self.env_vars.items() if v is not None})
# logger.debug("Container Environment: {}".format(container_env))
return container_env
def get_load_balancer_security_groups(self) -> Optional[List["SecurityGroup"]]:
from phi.aws.resource.ec2.security_group import SecurityGroup, InboundRule
load_balancer_security_groups: Optional[List[SecurityGroup]] = self.load_balancer_security_groups
if load_balancer_security_groups is None:
# Create security group for the load balancer
if self.create_load_balancer and self.create_security_groups:
load_balancer_security_groups = []
lb_sg = SecurityGroup(
name=f"{self.get_app_name()}-lb-security-group",
description=f"Security group for {self.get_app_name()} load balancer",
inbound_rules=[
InboundRule(
description="Allow HTTP traffic from the internet",
port=80,
cidr_ip="0.0.0.0/0",
),
],
)
if self.load_balancer_enable_https:
if lb_sg.inbound_rules is None:
lb_sg.inbound_rules = []
lb_sg.inbound_rules.append(
InboundRule(
description="Allow HTTPS traffic from the internet",
port=443,
cidr_ip="0.0.0.0/0",
)
)
load_balancer_security_groups.append(lb_sg)
return load_balancer_security_groups
def security_group_definition(self) -> "SecurityGroup":
from phi.aws.resource.ec2.security_group import SecurityGroup, InboundRule
from phi.aws.resource.reference import AwsReference
# Create security group for the app
app_sg = SecurityGroup(
name=f"{self.get_app_name()}-security-group",
description=f"Security group for {self.get_app_name()}",
)
# Add inbound rules for the app security group
# Allow traffic from the load balancer security groups
load_balancer_security_groups = self.get_load_balancer_security_groups()
if load_balancer_security_groups is not None:
if app_sg.inbound_rules is None:
app_sg.inbound_rules = []
if app_sg.depends_on is None:
app_sg.depends_on = []
for lb_sg in load_balancer_security_groups:
app_sg.inbound_rules.append(
InboundRule(
description=f"Allow traffic from {lb_sg.name} to the {self.get_app_name()}",
port=self.container_port,
source_security_group_id=AwsReference(lb_sg.get_security_group_id),
)
)
app_sg.depends_on.append(lb_sg)
# Allow traffic from inbound_security_groups
if self.inbound_security_groups is not None:
if app_sg.inbound_rules is None:
app_sg.inbound_rules = []
if app_sg.depends_on is None:
app_sg.depends_on = []
for inbound_sg in self.inbound_security_groups:
app_sg.inbound_rules.append(
InboundRule(
description=f"Allow traffic from {inbound_sg.name} to the {self.get_app_name()}",
port=self.container_port,
source_security_group_id=AwsReference(inbound_sg.get_security_group_id),
)
)
# Allow traffic from inbound_security_group_ids
if self.inbound_security_group_ids is not None:
if app_sg.inbound_rules is None:
app_sg.inbound_rules = []
if app_sg.depends_on is None:
app_sg.depends_on = []
for inbound_sg_id in self.inbound_security_group_ids:
app_sg.inbound_rules.append(
InboundRule(
description=f"Allow traffic from {inbound_sg_id} to the {self.get_app_name()}",
port=self.container_port,
source_security_group_id=inbound_sg_id,
)
)
return app_sg
def get_security_groups(self) -> Optional[List["SecurityGroup"]]:
from phi.aws.resource.ec2.security_group import SecurityGroup
security_groups: Optional[List[SecurityGroup]] = self.security_groups
if security_groups is None:
# Create security group for the service
if self.create_security_groups:
security_groups = []
app_security_group = self.security_group_definition()
if app_security_group is not None:
security_groups.append(app_security_group)
return security_groups
def get_all_security_groups(self) -> Optional[List["SecurityGroup"]]:
from phi.aws.resource.ec2.security_group import SecurityGroup
security_groups: List[SecurityGroup] = []
load_balancer_security_groups = self.get_load_balancer_security_groups()
if load_balancer_security_groups is not None:
for lb_sg in load_balancer_security_groups:
if isinstance(lb_sg, SecurityGroup):
security_groups.append(lb_sg)
service_security_groups = self.get_security_groups()
if service_security_groups is not None:
for sg in service_security_groups:
if isinstance(sg, SecurityGroup):
security_groups.append(sg)
return security_groups if len(security_groups) > 0 else None
def ecs_cluster_definition(self) -> "EcsCluster":
from phi.aws.resource.ecs.cluster import EcsCluster
ecs_cluster = EcsCluster(
name=f"{self.get_app_name()}-cluster",
ecs_cluster_name=self.ecs_cluster_name or self.get_app_name(),
capacity_providers=[self.ecs_launch_type],
)
if self.ecs_enable_service_connect:
ecs_cluster.service_connect_namespace = self.ecs_service_connect_namespace
return ecs_cluster
def get_ecs_cluster(self) -> "EcsCluster":
from phi.aws.resource.ecs.cluster import EcsCluster
if self.ecs_cluster is None:
if self.create_ecs_cluster:
return self.ecs_cluster_definition()
raise Exception("Please provide ECSCluster or set create_ecs_cluster to True")
elif isinstance(self.ecs_cluster, EcsCluster):
return self.ecs_cluster
else:
raise Exception(f"Invalid ECSCluster: {self.ecs_cluster} - Must be of type EcsCluster")
def load_balancer_definition(self) -> "LoadBalancer":
from phi.aws.resource.elb.load_balancer import LoadBalancer
return LoadBalancer(
name=f"{self.get_app_name()}-lb",
subnets=self.subnets,
security_groups=self.get_load_balancer_security_groups(),
protocol="HTTPS" if self.load_balancer_enable_https else "HTTP",
)
def get_load_balancer(self) -> Optional["LoadBalancer"]:
from phi.aws.resource.elb.load_balancer import LoadBalancer
if self.load_balancer is None:
if self.create_load_balancer:
return self.load_balancer_definition()
return None
elif isinstance(self.load_balancer, LoadBalancer):
return self.load_balancer
else:
raise Exception(f"Invalid LoadBalancer: {self.load_balancer} - Must be of type LoadBalancer")
def target_group_definition(self) -> "TargetGroup":
from phi.aws.resource.elb.target_group import TargetGroup
return TargetGroup(
name=f"{self.get_app_name()}-tg",
port=self.target_group_port or self.container_port,
protocol=self.target_group_protocol,
subnets=self.subnets,
target_type=self.target_group_type,
health_check_protocol=self.health_check_protocol,
health_check_port=self.health_check_port,
health_check_enabled=self.health_check_enabled,
health_check_path=self.health_check_path,
health_check_interval_seconds=self.health_check_interval_seconds,
health_check_timeout_seconds=self.health_check_timeout_seconds,
healthy_threshold_count=self.healthy_threshold_count,
unhealthy_threshold_count=self.unhealthy_threshold_count,
)
def get_target_group(self) -> Optional["TargetGroup"]:
from phi.aws.resource.elb.target_group import TargetGroup
if self.target_group is None:
if self.create_target_group:
return self.target_group_definition()
return None
elif isinstance(self.target_group, TargetGroup):
return self.target_group
else:
raise Exception(f"Invalid TargetGroup: {self.target_group} - Must be of type TargetGroup")
def listeners_definition(
self, load_balancer: Optional["LoadBalancer"], target_group: Optional["TargetGroup"]
) -> List["Listener"]:
from phi.aws.resource.elb.listener import Listener
listener = Listener(
name=f"{self.get_app_name()}-listener",
load_balancer=load_balancer,
target_group=target_group,
)
if self.load_balancer_certificate_arn is not None:
listener.certificates = [{"CertificateArn": self.load_balancer_certificate_arn}]
if self.load_balancer_certificate is not None:
listener.acm_certificates = [self.load_balancer_certificate]
listeners: List[Listener] = [listener]
if self.load_balancer_enable_https:
# Add a listener to redirect HTTP to HTTPS
listeners.append(
Listener(
name=f"{self.get_app_name()}-redirect-listener",
port=80,
protocol="HTTP",
load_balancer=load_balancer,
default_actions=[
{
"Type": "redirect",
"RedirectConfig": {
"Protocol": "HTTPS",
"Port": "443",
"StatusCode": "HTTP_301",
"Host": "#{host}",
"Path": "/#{path}",
"Query": "#{query}",
},
}
],
)
)
return listeners
def get_listeners(
self, load_balancer: Optional["LoadBalancer"], target_group: Optional["TargetGroup"]
) -> Optional[List["Listener"]]:
from phi.aws.resource.elb.listener import Listener
if self.listeners is None:
if self.create_listeners:
return self.listeners_definition(load_balancer, target_group)
return None
elif isinstance(self.listeners, list):
for listener in self.listeners:
if not isinstance(listener, Listener):
raise Exception(f"Invalid Listener: {listener} - Must be of type Listener")
return self.listeners
else:
raise Exception(f"Invalid Listener: {self.listeners} - Must be of type List[Listener]")
def get_container_command(self) -> Optional[List[str]]:
if isinstance(self.command, str):
return self.command.strip().split(" ")
return self.command
def get_ecs_container_port_mappings(self) -> List[Dict[str, Any]]:
port_mapping: Dict[str, Any] = {"containerPort": self.container_port}
# To enable service connect, we need to set the port name to the app name
if self.ecs_enable_service_connect:
port_mapping["name"] = self.get_app_name()
if self.ecs_service_connect_protocol is not None:
port_mapping["appProtocol"] = self.ecs_service_connect_protocol
return [port_mapping]
def get_ecs_container(self, container_context: ContainerContext, build_context: AwsBuildContext) -> "EcsContainer":
from phi.aws.resource.ecs.container import EcsContainer
# -*- Get Container Environment
container_env: Dict[str, str] = self.get_container_env(
container_context=container_context, build_context=build_context
)
# -*- Get Container Command
container_cmd: Optional[List[str]] = self.get_container_command()
if container_cmd:
logger.debug("Command: {}".format(" ".join(container_cmd)))
aws_region = build_context.aws_region or (
self.workspace_settings.aws_region if self.workspace_settings else None
)
return EcsContainer(
name=self.get_app_name(),
image=self.get_image_str(),
port_mappings=self.get_ecs_container_port_mappings(),
command=container_cmd,
essential=True,
environment=[{"name": k, "value": v} for k, v in container_env.items()],
log_configuration={
"logDriver": "awslogs",
"options": {
"awslogs-group": self.get_app_name(),
"awslogs-region": aws_region,
"awslogs-create-group": "true",
"awslogs-stream-prefix": self.get_app_name(),
},
},
linux_parameters={"initProcessEnabled": True},
env_from_secrets=self.aws_secrets,
)
def get_ecs_task_definition(self, ecs_container: "EcsContainer") -> "EcsTaskDefinition":
from phi.aws.resource.ecs.task_definition import EcsTaskDefinition
return EcsTaskDefinition(
name=f"{self.get_app_name()}-td",
family=self.get_app_name(),
network_mode="awsvpc",
cpu=self.ecs_task_cpu,
memory=self.ecs_task_memory,
containers=[ecs_container],
requires_compatibilities=[self.ecs_launch_type],
add_bedrock_access_to_task=self.ecs_bedrock_access,
add_exec_access_to_task=self.ecs_exec_access,
add_secret_access_to_ecs=self.ecs_secret_access,
add_secret_access_to_task=self.ecs_secret_access,
add_s3_access_to_task=self.ecs_s3_access,
)
def get_ecs_service(
self,
ecs_container: "EcsContainer",
ecs_task_definition: "EcsTaskDefinition",
ecs_cluster: "EcsCluster",
target_group: Optional["TargetGroup"],
) -> Optional["EcsService"]:
from phi.aws.resource.ecs.service import EcsService
service_security_groups = self.get_security_groups()
ecs_service = EcsService(
name=f"{self.get_app_name()}-service",
desired_count=self.ecs_service_count,
launch_type=self.ecs_launch_type,
cluster=ecs_cluster,
task_definition=ecs_task_definition,
target_group=target_group,
target_container_name=ecs_container.name,
target_container_port=self.container_port,
subnets=self.subnets,
security_groups=service_security_groups,
assign_public_ip=self.assign_public_ip,
# Force delete the service.
force_delete=True,
# Force a new deployment of the service on update.
force_new_deployment=True,
enable_execute_command=self.ecs_exec_access,
)
if self.ecs_enable_service_connect:
# namespace is used from the cluster
ecs_service.service_connect_configuration = {
"enabled": True,
"services": [
{
"portName": self.get_app_name(),
"clientAliases": [
{
"port": self.container_port,
"dnsName": self.get_app_name(),
}
],
},
],
}
return ecs_service
def build_resources(self, build_context: AwsBuildContext) -> List["AwsResource"]:
from phi.aws.resource.base import AwsResource
from phi.aws.resource.ec2.security_group import SecurityGroup
from phi.aws.resource.ecs.cluster import EcsCluster
from phi.aws.resource.elb.load_balancer import LoadBalancer
from phi.aws.resource.elb.target_group import TargetGroup
from phi.aws.resource.elb.listener import Listener
from phi.aws.resource.ecs.container import EcsContainer
from phi.aws.resource.ecs.task_definition import EcsTaskDefinition
from phi.aws.resource.ecs.service import EcsService
from phi.aws.resource.ecs.volume import EcsVolume
from phi.docker.resource.image import DockerImage
from phi.utils.defaults import get_default_volume_name
logger.debug(f"------------ Building {self.get_app_name()} ------------")
# -*- Get Container Context
container_context: Optional[ContainerContext] = self.get_container_context()
if container_context is None:
raise Exception("Could not build ContainerContext")
logger.debug(f"ContainerContext: {container_context.model_dump_json(indent=2)}")
# -*- Get Security Groups
security_groups: Optional[List[SecurityGroup]] = self.get_all_security_groups()
# -*- Get ECS cluster
ecs_cluster: EcsCluster = self.get_ecs_cluster()
# -*- Get Load Balancer
load_balancer: Optional[LoadBalancer] = self.get_load_balancer()
# -*- Get Target Group
target_group: Optional[TargetGroup] = self.get_target_group()
# Point the target group to the nginx container port if:
# - nginx is enabled
# - user provided target_group is None
# - user provided target_group_port is None
if self.enable_nginx and self.target_group is None and self.target_group_port is None:
if target_group is not None:
target_group.port = self.nginx_container_port
# -*- Get Listener
listeners: Optional[List[Listener]] = self.get_listeners(load_balancer=load_balancer, target_group=target_group)
# -*- Get ECSContainer
ecs_container: EcsContainer = self.get_ecs_container(
container_context=container_context, build_context=build_context
)
# -*- Add nginx container if nginx is enabled
nginx_container: Optional[EcsContainer] = None
nginx_shared_volume: Optional[EcsVolume] = None
if self.enable_nginx and ecs_container is not None:
nginx_container_name = f"{self.get_app_name()}-nginx"
nginx_shared_volume = EcsVolume(name=get_default_volume_name(self.get_app_name()))
nginx_image_str = f"{self.nginx_image_name}:{self.nginx_image_tag}"
if self.nginx_image and isinstance(self.nginx_image, DockerImage):
nginx_image_str = self.nginx_image.get_image_str()
nginx_container = EcsContainer(
name=nginx_container_name,
image=nginx_image_str,
essential=True,
port_mappings=[{"containerPort": self.nginx_container_port}],
environment=ecs_container.environment,
log_configuration={
"logDriver": "awslogs",
"options": {
"awslogs-group": self.get_app_name(),
"awslogs-region": build_context.aws_region
or (self.workspace_settings.aws_region if self.workspace_settings else None),
"awslogs-create-group": "true",
"awslogs-stream-prefix": nginx_container_name,
},
},
mount_points=[
{
"sourceVolume": nginx_shared_volume.name,
"containerPath": container_context.workspace_root,
}
],
linux_parameters=ecs_container.linux_parameters,
env_from_secrets=ecs_container.env_from_secrets,
save_output=ecs_container.save_output,
output_dir=ecs_container.output_dir,
skip_create=ecs_container.skip_create,
skip_delete=ecs_container.skip_delete,
wait_for_create=ecs_container.wait_for_create,
wait_for_delete=ecs_container.wait_for_delete,
)
# Add shared volume to ecs_container
ecs_container.mount_points = nginx_container.mount_points
# -*- Get ECS Task Definition
ecs_task_definition: EcsTaskDefinition = self.get_ecs_task_definition(ecs_container=ecs_container)
# -*- Add nginx container to ecs_task_definition if nginx is enabled
if self.enable_nginx:
if ecs_task_definition is not None:
if nginx_container is not None:
if ecs_task_definition.containers:
ecs_task_definition.containers.append(nginx_container)
else:
logger.error("While adding Nginx container, found TaskDefinition.containers to be None")
else:
logger.error("While adding Nginx container, found nginx_container to be None")
if nginx_shared_volume:
ecs_task_definition.volumes = [nginx_shared_volume]
# -*- Get ECS Service
ecs_service: Optional[EcsService] = self.get_ecs_service(
ecs_cluster=ecs_cluster,
ecs_task_definition=ecs_task_definition,
target_group=target_group,
ecs_container=ecs_container,
)
# -*- Add nginx container as target_container if nginx is enabled
if self.enable_nginx:
if ecs_service is not None:
if nginx_container is not None:
ecs_service.target_container_name = nginx_container.name
ecs_service.target_container_port = self.nginx_container_port
else:
logger.error("While adding Nginx container as target_container, found nginx_container to be None")
# -*- List of AwsResources created by this App
app_resources: List[AwsResource] = []
if security_groups:
app_resources.extend(security_groups)
if load_balancer:
app_resources.append(load_balancer)
if target_group:
app_resources.append(target_group)
if listeners:
app_resources.extend(listeners)
if ecs_cluster:
app_resources.append(ecs_cluster)
if ecs_task_definition:
app_resources.append(ecs_task_definition)
if ecs_service:
app_resources.append(ecs_service)
logger.debug(f"------------ {self.get_app_name()} Built ------------")
return app_resources