예제 #1
0
    def __init__(self, scope: Construct, id: str, *, deployment: Deployment,
                 policy: Policy, cluster: ICluster, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Application", self.application_name)
        Tags.of(self).add("Deployment", deployment.value)

        policy.add_stack(self)

        if deployment == Deployment.PRODUCTION:
            desired_count = 2
            priority = 50
        else:
            desired_count = 1
            priority = 150

        ECSHTTPSContainer(
            self,
            self.application_name,
            subdomain_name=self.subdomain_name,
            deployment=deployment,
            policy=policy,
            application_name=self.application_name,
            image_name="ghcr.io/openttd/binaries-redirect",
            port=80,
            memory_limit_mib=16,
            desired_count=desired_count,
            cluster=cluster,
            priority=priority,
            allow_via_http=True,
        )
예제 #2
0
    def __init__(self, scope: Construct, id: str, *, deployment: Deployment,
                 policy: Policy, cluster: ICluster, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Application", self.application_name)
        Tags.of(self).add("Deployment", deployment.value)

        policy.add_stack(self)

        if deployment == Deployment.PRODUCTION:
            desired_count = 1  # Currently this pod is stateful, and as such cannot be run more than once
            priority = 46
        else:
            desired_count = 1
            priority = 146

        api_fqdn = dns.subdomain_to_fqdn("api.bananas")
        api_url = f"https://{api_fqdn}"
        frontend_fqdn = dns.subdomain_to_fqdn(self.subdomain_name)
        frontend_url = f"https://{frontend_fqdn}"

        sentry_dsn = parameter_store.add_secure_string(
            f"/BananasFrontendWeb/{deployment.value}/SentryDSN").parameter

        ECSHTTPSContainer(
            self,
            self.application_name,
            subdomain_name=self.subdomain_name,
            deployment=deployment,
            policy=policy,
            application_name=self.application_name,
            image_name="ghcr.io/openttd/bananas-frontend-web",
            port=80,
            memory_limit_mib=64,
            desired_count=desired_count,
            cluster=cluster,
            priority=priority,
            command=[
                "--api-url",
                api_url,
                "--frontend-url",
                frontend_url,
                "run",
                "-p",
                "80",
                "-h",
                "0.0.0.0",
            ],
            environment={
                "WEBCLIENT_SENTRY_ENVIRONMENT": deployment.value.lower(),
            },
            secrets={
                "WEBCLIENT_SENTRY_DSN": Secret.from_ssm_parameter(sentry_dsn),
            },
        )
예제 #3
0
    def __init__(self, scope: Construct, id: str, *, parameter_name: str,
                 image_name: str, policy: Policy) -> None:
        super().__init__(scope, id)

        parameter = parameter_store.add_string(parameter_name, default=":1")
        # Make sure external processes can change this Parameter, to redeploy
        # a new version of the container.
        policy.add_parameter(parameter.parameter)

        tag = Token.as_string(
            StringParameter.value_for_string_parameter(self, parameter.name))
        self._image_ref = StringConcat().join(image_name, tag)
예제 #4
0
    def __init__(self, scope: Construct, id: str, *, deployment: Deployment,
                 policy: Policy, cluster: ICluster, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Application", self.application_name)
        Tags.of(self).add("Deployment", deployment.value)

        policy.add_stack(self)

        if deployment == Deployment.PRODUCTION:
            desired_count = 2
            priority = 62
        else:
            desired_count = 1
            priority = 162

        api_fqdn = dns.subdomain_to_fqdn("api.master")
        api_url = f"https://{api_fqdn}"

        sentry_dsn = parameter_store.add_secure_string(
            f"/MasterServerWeb/{deployment.value}/SentryDSN").parameter

        ECSHTTPSContainer(
            self,
            self.application_name,
            subdomain_name=self.subdomain_name,
            deployment=deployment,
            policy=policy,
            application_name=self.application_name,
            image_name="ghcr.io/openttd/master-server-web",
            port=80,
            memory_limit_mib=96,
            desired_count=desired_count,
            cluster=cluster,
            priority=priority,
            command=[
                "--api-url",
                api_url,
                "run",
                "-p",
                "80",
                "-h",
                "0.0.0.0",
            ],
            environment={
                "WEBCLIENT_SENTRY_ENVIRONMENT": deployment.value.lower(),
            },
            secrets={
                "WEBCLIENT_SENTRY_DSN": Secret.from_ssm_parameter(sentry_dsn),
            },
        )
예제 #5
0
    def __init__(
        self,
        scope: Construct,
        id: str,
        *,
        subdomain_name: str,
        deployment: Deployment,
        policy: Policy,
        application_name: str,
        image_name: str,
        port: int,
        memory_limit_mib: int,
        desired_count: int,
        cluster: ICluster,
        priority: int,
        path_pattern: Optional[str] = None,
        health_check_grace_period: Optional[Duration] = None,
        allow_via_http: Optional[bool] = False,
        command: Optional[List[str]] = None,
        environment: Mapping[str, str] = {},
        secrets: Mapping[str, Secret] = {},
        volumes: Mapping[str, Volume] = {},
    ) -> None:
        super().__init__(scope, id)

        full_application_name = f"{deployment.value}-{application_name}"

        log_group = tasks.add_logging(full_application_name)
        self.task_role = tasks.add_role(full_application_name)
        policy.add_role(self.task_role)

        logging = LogDrivers.aws_logs(
            stream_prefix=full_application_name,
            log_group=log_group,
        )

        image = ImageFromParameterStore(
            self,
            "ImageName",
            parameter_name=f"/Version/{deployment.value}/{application_name}",
            image_name=image_name,
            policy=policy,
        )

        task_definition = Ec2TaskDefinition(
            self,
            "TaskDef",
            network_mode=NetworkMode.BRIDGE,
            execution_role=self.task_role,
            task_role=self.task_role,
            volumes=list(volumes.values()),
        )

        self.container = task_definition.add_container(
            "Container",
            image=ContainerImage.from_registry(image.image_ref),
            memory_limit_mib=memory_limit_mib,
            logging=logging,
            environment=environment,
            secrets=secrets,
            command=command,
        )
        self.container.add_mount_points(*[
            MountPoint(
                container_path=path,
                read_only=False,
                source_volume=volume.name,
            ) for path, volume in volumes.items()
        ])

        self.add_port(port=port, )

        self.service = Ec2Service(
            self,
            "Service",
            cluster=cluster,
            task_definition=task_definition,
            desired_count=desired_count,
            health_check_grace_period=health_check_grace_period,
        )
        policy.add_service(self.service)
        policy.add_cluster(cluster)

        self.service.add_placement_strategies(
            PlacementStrategy.spread_across(
                BuiltInAttributes.AVAILABILITY_ZONE), )

        self.add_target(
            subdomain_name=subdomain_name,
            port=port,
            priority=priority,
            path_pattern=path_pattern,
            allow_via_http=allow_via_http,
        )

        # Remove the security group from this stack, and add it to the ALB stack
        self.service.node.try_remove_child("SecurityGroup1")
        for security_group in cluster.connections.security_groups:
            self.service.connections.add_security_group(security_group)
예제 #6
0
    def __init__(self, scope: Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Stack", "Common-Policy")
        self._policy = Policy(self, "Policy")
예제 #7
0
    def __init__(
        self,
        scope: Construct,
        id: str,
        *,
        deployment: Deployment,
        policy: Policy,
        cluster: ICluster,
        bucket: Bucket,
        **kwargs,
    ) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Application", self.application_name)
        Tags.of(self).add("Deployment", deployment.value)

        policy.add_stack(self)

        if deployment == Deployment.PRODUCTION:
            desired_count = 2
            priority = 44
            memory = 256
            github_url = "https://github.com/OpenTTD/BaNaNaS"
            content_port = 3978
            bootstrap_command = ["--bootstrap-unique-id", "4f474658"]
        else:
            desired_count = 1
            priority = 144
            memory = 128
            github_url = "https://github.com/OpenTTD/BaNaNaS-staging"
            content_port = 4978
            bootstrap_command = []

        cdn_fqdn = dns.subdomain_to_fqdn("bananas.cdn")
        cdn_url = f"http://{cdn_fqdn}"

        sentry_dsn = parameter_store.add_secure_string(f"/BananasServer/{deployment.value}/SentryDSN").parameter
        reload_secret = parameter_store.add_secure_string(f"/BananasServer/{deployment.value}/ReloadSecret").parameter

        command = [
            "--storage",
            "s3",
            "--storage-s3-bucket",
            bucket.bucket_name,
            "--index",
            "github",
            "--index-github-url",
            github_url,
            "--cdn-url",
            cdn_url,
            "--bind",
            "0.0.0.0",
            "--content-port",
            str(content_port),
            "--proxy-protocol",
        ]
        command.extend(bootstrap_command)

        self.container = ECSHTTPSContainer(
            self,
            self.application_name,
            subdomain_name=self.subdomain_name,
            path_pattern=self.path_pattern,
            allow_via_http=True,
            deployment=deployment,
            policy=policy,
            application_name=self.application_name,
            image_name="ghcr.io/openttd/bananas-server",
            port=80,
            memory_limit_mib=memory,
            desired_count=desired_count,
            cluster=cluster,
            priority=priority,
            command=command,
            environment={
                "BANANAS_SERVER_SENTRY_ENVIRONMENT": deployment.value.lower(),
            },
            secrets={
                "BANANAS_SERVER_SENTRY_DSN": Secret.from_ssm_parameter(sentry_dsn),
                "BANANAS_SERVER_RELOAD_SECRET": Secret.from_ssm_parameter(reload_secret),
            },
        )

        self.container.add_port(content_port)
        nlb.add_nlb(self, self.container.service, Port.tcp(content_port), self.nlb_subdomain_name, "BaNaNaS Server")

        self.container.task_role.add_to_policy(
            PolicyStatement(
                actions=[
                    "s3:GetObject",
                    "s3:ListBucket",
                ],
                resources=[
                    bucket.bucket_arn,
                    StringConcat().join(bucket.bucket_arn, "/*"),
                ],
            )
        )
예제 #8
0
    def __init__(
        self,
        scope: Construct,
        id: str,
        *,
        deployment: Deployment,
        policy: Policy,
        cluster: ICluster,
        bucket: Bucket,
        **kwargs,
    ) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Application", self.application_name)
        Tags.of(self).add("Deployment", deployment.value)

        policy.add_stack(self)

        if deployment == Deployment.PRODUCTION:
            desired_count = 1  # Currently this pod is stateful, and as such cannot be run more than once
            tus_priority = 40
            priority = 42
            memory = 256
            github_url = "[email protected]:OpenTTD/BaNaNaS.git"
            client_file = "clients-production.yaml"
        else:
            desired_count = 1
            tus_priority = 140
            priority = 142
            memory = 96
            github_url = "[email protected]:OpenTTD/BaNaNaS-staging.git"
            client_file = "clients-staging.yaml"

        sentry_dsn = parameter_store.add_secure_string(f"/BananasApi/{deployment.value}/SentryDSN").parameter
        user_github_client_id = parameter_store.add_secure_string(f"/BananasApi/{deployment.value}/UserGithubClientId").parameter
        user_github_client_secret = parameter_store.add_secure_string(f"/BananasApi/{deployment.value}/UserGithubClientSecret").parameter
        index_github_private_key = parameter_store.add_secure_string(f"/BananasApi/{deployment.value}/IndexGithubPrivateKey").parameter
        reload_secret = parameter_store.add_secure_string(f"/BananasApi/{deployment.value}/ReloadSecret").parameter

        self.container = ECSHTTPSContainer(
            self,
            self.application_name,
            subdomain_name=self.subdomain_name,
            deployment=deployment,
            policy=policy,
            application_name=self.application_name,
            image_name="ghcr.io/openttd/bananas-api",
            port=80,
            memory_limit_mib=memory,
            desired_count=desired_count,
            cluster=cluster,
            priority=priority,
            command=[
                "--storage",
                "s3",
                "--storage-s3-bucket",
                bucket.bucket_name,
                "--index",
                "github",
                "--index-github-url",
                github_url,
                "--client-file",
                client_file,
                "--user",
                "github",
                "--bind",
                "0.0.0.0",
                "--behind-proxy",
            ],
            environment={
                "BANANAS_API_SENTRY_ENVIRONMENT": deployment.value.lower(),
            },
            secrets={
                "BANANAS_API_SENTRY_DSN": Secret.from_ssm_parameter(sentry_dsn),
                "BANANAS_API_USER_GITHUB_CLIENT_ID": Secret.from_ssm_parameter(user_github_client_id),
                "BANANAS_API_USER_GITHUB_CLIENT_SECRET": Secret.from_ssm_parameter(user_github_client_secret),
                "BANANAS_API_INDEX_GITHUB_PRIVATE_KEY": Secret.from_ssm_parameter(index_github_private_key),
                "BANANAS_API_RELOAD_SECRET": Secret.from_ssm_parameter(reload_secret),
            },
        )
        self.container.add_port(1080)
        self.container.add_target(
            subdomain_name=self.subdomain_name,
            port=1080,
            priority=tus_priority,
            path_pattern="/new-package/tus/*",
        )

        self.container.task_role.add_to_policy(
            PolicyStatement(
                actions=[
                    "s3:PutObject",
                    "s3:PutObjectAcl",
                ],
                resources=[
                    StringConcat().join(bucket.bucket_arn, "/*"),
                ],
            )
        )
예제 #9
0
파일: wiki.py 프로젝트: frosch123/aws-infra
    def __init__(
        self,
        scope: Construct,
        id: str,
        *,
        deployment: Deployment,
        policy: Policy,
        cluster: ICluster,
        vpc: IVpc,
        **kwargs,
    ) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Application", self.application_name)
        Tags.of(self).add("Deployment", deployment.value)

        policy.add_stack(self)

        efs_cache = FileSystem(
            self,
            "WikiCacheEFS",
            vpc=vpc,
        )
        efs_cache.connections.allow_default_port_from(cluster)

        if deployment == Deployment.PRODUCTION:
            desired_count = 1  # Currently this pod is stateful, and as such cannot be run more than once
            priority = 80
            memory = 384
            github_url = "[email protected]:OpenTTD/wiki-data.git"
            github_history_url = "https://github.com/OpenTTD/wiki-data"
            frontend_url = "https://wiki.openttd.org"
        else:
            desired_count = 1
            priority = 180
            memory = 128
            github_url = "[email protected]:OpenTTD/wiki-data-staging.git"
            github_history_url = "https://github.com/OpenTTD/wiki-data-staging"
            frontend_url = "https://wiki.staging.openttd.org"

        sentry_dsn = parameter_store.add_secure_string(f"/Wiki/{deployment.value}/SentryDSN").parameter
        user_github_client_id = parameter_store.add_secure_string(f"/Wiki/{deployment.value}/UserGithubClientId").parameter
        user_github_client_secret = parameter_store.add_secure_string(f"/Wiki/{deployment.value}/UserGithubClientSecret").parameter
        storage_github_private_key = parameter_store.add_secure_string(f"/Wiki/{deployment.value}/StorageGithubPrivateKey").parameter
        reload_secret = parameter_store.add_secure_string(f"/Wiki/{deployment.value}/ReloadSecret").parameter

        self.container = ECSHTTPSContainer(
            self,
            self.application_name,
            subdomain_name=self.subdomain_name,
            deployment=deployment,
            policy=policy,
            application_name=self.application_name,
            image_name="ghcr.io/truebrain/truewiki",
            port=80,
            memory_limit_mib=memory,
            desired_count=desired_count,
            cluster=cluster,
            priority=priority,
            command=[
                "--storage",
                "github",
                "--storage-github-url",
                github_url,
                "--storage-github-history-url",
                github_history_url,
                "--storage-folder",
                "/data",
                "--user",
                "github",
                "--frontend-url",
                frontend_url,
                "--cache-metadata-file",
                "/cache/metadata.json",
                "--cache-page-folder",
                "/cache-pages",
                "--bind",
                "0.0.0.0",
            ],
            environment={
                "TRUEWIKI_SENTRY_ENVIRONMENT": deployment.value.lower(),
            },
            secrets={
                "TRUEWIKI_SENTRY_DSN": Secret.from_ssm_parameter(sentry_dsn),
                "TRUEWIKI_USER_GITHUB_CLIENT_ID": Secret.from_ssm_parameter(user_github_client_id),
                "TRUEWIKI_USER_GITHUB_CLIENT_SECRET": Secret.from_ssm_parameter(user_github_client_secret),
                "TRUEWIKI_STORAGE_GITHUB_PRIVATE_KEY": Secret.from_ssm_parameter(storage_github_private_key),
                "TRUEWIKI_RELOAD_SECRET": Secret.from_ssm_parameter(reload_secret),
            },
            volumes={
                "/cache": Volume(
                    name="cache",
                    efs_volume_configuration=EfsVolumeConfiguration(
                        file_system_id=efs_cache.file_system_id,
                    ),
                ),
            },
        )
예제 #10
0
    def __init__(
        self,
        scope: Construct,
        id: str,
        *,
        deployment: Deployment,
        policy: Policy,
        cluster: ICluster,
        vpc: IVpc,
        **kwargs,
    ) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Application", self.application_name)
        Tags.of(self).add("Deployment", deployment.value)

        policy.add_stack(self)

        efs = FileSystem(
            self,
            "EintsEFS",
            vpc=vpc,
        )
        efs.connections.allow_default_port_from(cluster)

        if deployment == Deployment.PRODUCTION:
            desired_count = 1  # Currently this pod is stateful, and as such cannot be run more than once
            priority = 70
            memory = 512
        else:
            desired_count = 1
            priority = 170
            memory = 128

        github_org_api_token = parameter_store.add_secure_string(
            f"/Eints/{deployment.value}/GithubOrgApiToken").parameter
        github_oauth2_client_id = parameter_store.add_secure_string(
            f"/Eints/{deployment.value}/GithubOauth2ClientId").parameter
        github_oauth2_client_secret = parameter_store.add_secure_string(
            f"/Eints/{deployment.value}/GithubOauth2ClientSecret").parameter
        translators_password = parameter_store.add_secure_string(
            f"/Eints/{deployment.value}/TranslatorsPassword").parameter
        sentry_dsn = parameter_store.add_secure_string(
            f"/Eints/{deployment.value}/SentryDSN").parameter

        ECSHTTPSContainer(
            self,
            self.application_name,
            subdomain_name=self.subdomain_name,
            deployment=deployment,
            policy=policy,
            application_name=self.application_name,
            image_name="ghcr.io/openttd/eints-openttd-github",
            port=80,
            memory_limit_mib=memory,
            desired_count=desired_count,
            cluster=cluster,
            priority=priority,
            command=[
                "--server-host",
                "0.0.0.0",
                "--server-port",
                "80",
                "--server-mode",
                "production",
                "--authentication",
                "github",
                "--stable-languages",
                "stable_languages",
                "--unstable-languages",
                "unstable_languages",
                "--project-cache",
                "1",
                "--project-types",
                "openttd",
                "--storage-format",
                "split-languages",
                "--data-format",
                "json",
                "--language-file-size",
                "10000000",
                "--num-backup-files",
                "1",
                "--max-num-changes",
                "5",
                "--min-num-changes",
                "2",
                "--change-stable-age",
                "600",
                "--github-organization",
                "OpenTTD",
            ],
            environment={
                "EINTS_SENTRY_ENVIRONMENT": deployment.value.lower(),
            },
            secrets={
                "EINTS_GITHUB_ORG_API_TOKEN":
                Secret.from_ssm_parameter(github_org_api_token),
                "EINTS_GITHUB_OAUTH2_CLIENT_ID":
                Secret.from_ssm_parameter(github_oauth2_client_id),
                "EINTS_GITHUB_OAUTH2_CLIENT_SECRET":
                Secret.from_ssm_parameter(github_oauth2_client_secret),
                "EINTS_TRANSLATORS_PASSWORD":
                Secret.from_ssm_parameter(translators_password),
                "EINTS_SENTRY_DSN":
                Secret.from_ssm_parameter(sentry_dsn),
            },
            volumes={
                "/data":
                Volume(
                    name="data",
                    efs_volume_configuration=EfsVolumeConfiguration(
                        file_system_id=efs.file_system_id, ),
                )
            },
        )
예제 #11
0
    def __init__(
        self,
        scope: Construct,
        id: str,
        *,
        deployment: Deployment,
        policy: Policy,
        cluster: ICluster,
        vpc: IVpc,
        **kwargs,
    ) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Application", self.application_name)
        Tags.of(self).add("Deployment", deployment.value)

        policy.add_stack(self)

        efs_seen = FileSystem(
            self,
            "DorpsGekSeenEFS",
            vpc=vpc,
        )
        efs_seen.connections.allow_default_port_from(cluster)
        efs_logs = FileSystem(
            self,
            "DorpsGekLogsEFS",
            vpc=vpc,
        )
        efs_logs.connections.allow_default_port_from(cluster)

        if deployment == Deployment.PRODUCTION:
            desired_count = 1
            priority = 30
            addressed_by = "@"
            irc_username = "******"
            channels = [
                "--channel",
                "dorpsgek",
                "--channel",
                "openttd,public",
                "--channel",
                "openttd.dev,public",
                "--channel",
                "openttd.notice",
                "--channel",
                "openttd.tgp",
                "--channel",
                "opendune,public",
            ]
        else:
            desired_count = 1
            priority = 130
            addressed_by = "%"
            irc_username = "******"
            channels = [
                "--channel",
                "dorpsgek",
                "--channel",
                "dorpsgek-test,public",
            ]

        sentry_dsn = parameter_store.add_secure_string(
            f"/Dorpsgek/{deployment.value}/SentryDSN").parameter
        github_app_id = parameter_store.add_secure_string(
            f"/Dorpsgek/{deployment.value}/GithubAppId").parameter
        github_app_private_key = parameter_store.add_secure_string(
            f"/Dorpsgek/{deployment.value}/GithubAppPrivateKey").parameter
        github_app_secret = parameter_store.add_secure_string(
            f"/Dorpsgek/{deployment.value}/GithubAppSecret").parameter
        nickserv_password = parameter_store.add_secure_string(
            f"/Dorpsgek/{deployment.value}/NickservPassword").parameter

        ECSHTTPSContainer(
            self,
            self.application_name,
            subdomain_name=self.subdomain_name,
            deployment=deployment,
            policy=policy,
            application_name=self.application_name,
            image_name="ghcr.io/openttd/dorpsgek",
            port=80,
            memory_limit_mib=96,
            desired_count=desired_count,
            cluster=cluster,
            priority=priority,
            command=[
                "--irc-username",
                irc_username,
                "--nickserv-username",
                irc_username,
                "--addressed-by",
                addressed_by,
            ] + channels,
            environment={
                "DORPSGEK_SENTRY_ENVIRONMENT": deployment.value.lower(),
            },
            secrets={
                "DORPSGEK_SENTRY_DSN":
                Secret.from_ssm_parameter(sentry_dsn),
                "DORPSGEK_GITHUB_APP_ID":
                Secret.from_ssm_parameter(github_app_id),
                "DORPSGEK_GITHUB_APP_PRIVATE_KEY":
                Secret.from_ssm_parameter(github_app_private_key),
                "DORPSGEK_GITHUB_APP_SECRET":
                Secret.from_ssm_parameter(github_app_secret),
                "DORPSGEK_NICKSERV_PASSWORD":
                Secret.from_ssm_parameter(nickserv_password),
            },
            volumes={
                "/code/data":
                Volume(
                    name="data",
                    efs_volume_configuration=EfsVolumeConfiguration(
                        file_system_id=efs_seen.file_system_id, ),
                ),
                "/code/logs/ChannelLogger":
                Volume(
                    name="logs",
                    efs_volume_configuration=EfsVolumeConfiguration(
                        file_system_id=efs_logs.file_system_id, ),
                ),
            },
        )
예제 #12
0
    def __init__(self, scope: Construct, id: str, *, deployment: Deployment,
                 policy: Policy, cluster: ICluster, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        Tags.of(self).add("Application", self.application_name)
        Tags.of(self).add("Deployment", deployment.value)

        policy.add_stack(self)

        if deployment == Deployment.PRODUCTION:
            desired_count = 2
            priority = 60
            dynamodb_prefix = "P-"
        else:
            desired_count = 1
            priority = 160
            dynamodb_prefix = "S-"

        sentry_dsn = parameter_store.add_secure_string(
            f"/MasterServerApi/{deployment.value}/SentryDSN").parameter

        self.container = ECSHTTPSContainer(
            self,
            self.application_name,
            subdomain_name=self.subdomain_name,
            deployment=deployment,
            policy=policy,
            application_name=self.application_name,
            image_name="ghcr.io/openttd/master-server",
            port=80,
            memory_limit_mib=96,
            desired_count=desired_count,
            cluster=cluster,
            priority=priority,
            command=[
                "--app",
                "web_api",
                "--bind",
                "0.0.0.0",
                "--db",
                "dynamodb",
                "--dynamodb-region",
                "eu-central-1",
                "--dynamodb-prefix",
                dynamodb_prefix,
            ],
            environment={
                "MASTER_SERVER_SENTRY_ENVIRONMENT": deployment.value.lower(),
            },
            secrets={
                "MASTER_SERVER_SENTRY_DSN":
                Secret.from_ssm_parameter(sentry_dsn),
            },
        )

        table_and_index = []
        for table in ("S-MSU-ip-port", "S-MSU-server", "P-MSU-ip-port",
                      "P-MSU-server"):
            table_and_index.extend([
                f"arn:aws:dynamodb:{self.region}:{self.account}:table/{table}",
                f"arn:aws:dynamodb:{self.region}:{self.account}:table/{table}/index/online_view",
                f"arn:aws:dynamodb:{self.region}:{self.account}:table/{table}/index/time_last_seen_view",
            ])

        self.container.task_role.add_to_policy(
            PolicyStatement(
                actions=[
                    "dynamodb:CreateTable",
                    "dynamodb:UpdateTimeToLive",
                    "dynamodb:PutItem",
                    "dynamodb:DescribeTable",
                    "dynamodb:ListTables",
                    "dynamodb:GetItem",
                    "dynamodb:Query",
                    "dynamodb:UpdateItem",
                ],
                resources=table_and_index,
            ))