Example #1
0
    def __init__(self, scope: Construct, id: str, envs: EnvSettings):
        super().__init__(scope, id)

        self.backend_repository = Repository(
            self,
            "BackendRepository",
            repository_name=self.get_backend_repository_name(envs),
            removal_policy=RemovalPolicy.DESTROY,
        )
        self.nginx_repository = Repository(
            self,
            "NginxRepository",
            repository_name=self.get_nginx_repository_name(envs),
            removal_policy=RemovalPolicy.DESTROY,
        )
        self.webapp_repository = Repository(
            self,
            "WebAppRepository",
            repository_name=self.get_webapp_repository_name(envs),
            removal_policy=RemovalPolicy.DESTROY,
        )
Example #2
0
    def create_backend_build_project(self, envs: EnvSettings,
                                     repo: Repository):
        project = PipelineProject(
            self,
            "BackendBuild",
            project_name=f"{envs.project_name}-build-backend",
            build_spec=self.backend_spec,
            environment=BuildEnvironment(
                environment_variables={
                    "REPOSITORY_URI":
                    BuildEnvironmentVariable(value=repo.repository_uri),
                    "PUSH_IMAGES":
                    BuildEnvironmentVariable(value="1"),
                },
                build_image=LinuxBuildImage.STANDARD_2_0,
                privileged=True,
            ),
            cache=Cache.local(LocalCacheMode.DOCKER_LAYER),
        )

        repo.grant_pull_push(project)

        return project
Example #3
0
    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        stack_util = StackUtil()

        Repository(self,
                   'Repository',
                   repository_name=stack_util.get_name('repo'),
                   lifecycle_rules=[LifecycleRule(
                       description='leave only one untagged',
                       rule_priority=1,
                       tag_status=TagStatus.UNTAGGED,
                       max_image_count=1
                   )])
Example #4
0
 def retrieve_webapp_ecr_repository(self, envs: EnvSettings):
     return Repository.from_repository_name(
         self, "ECRWebAppRepository",
         BaseECR.get_webapp_repository_name(envs))
Example #5
0
 def retrieve_nginx_ecr_repository(self, envs: EnvSettings):
     return Repository.from_repository_name(
         self, "ECRNginxRepository",
         BaseECR.get_nginx_repository_name(envs))
Example #6
0
 def retrieve_backend_ecr_repository(self, envs: EnvSettings):
     return Repository.from_repository_name(
         self, "ECRBackendRepository",
         BaseECR.get_backend_repository_name(envs))
Example #7
0
    def __init__(self, scope: cdk.Construct, construct_id: str,
                 ecr_repository: ecr.Repository,
                 ecs_service: ecs.FargateService,
                 **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        backend_repository = codecommit.Repository(
            self, 'BackendRepository',
            repository_name='MythicalMysfits-BackendRepository'
        )

        codebuild_project = codebuild.PipelineProject(
            self, 'BuildProject',
            project_name='MythicalMysfitsServiceCodeBuildProject',
            environment=codebuild.BuildEnvironment(
                build_image=codebuild.LinuxBuildImage.UBUNTU_14_04_PYTHON_3_5_2,
                compute_type=codebuild.ComputeType.SMALL,
                environment_variables={
                    'AWS_ACCOUNT_ID': codebuild.BuildEnvironmentVariable(
                        type=codebuild.BuildEnvironmentVariableType.PLAINTEXT,
                        value=self.account),
                    'AWS_DEFAULT_REGION': codebuild.BuildEnvironmentVariable(
                        type=codebuild.BuildEnvironmentVariableType.PLAINTEXT,
                        value=self.region),
                },
                privileged=True
            )
        )

        codebuild_policy_stm = _iam.PolicyStatement()
        codebuild_policy_stm.add_resources(backend_repository.repository_arn)
        codebuild_policy_stm.add_actions(
            "codecommit:ListBranches",
            "codecommit:ListRepositories",
            "codecommit:BatchGetRepositories",
            "codecommit:GitPull"
        )
        codebuild_project.add_to_role_policy(codebuild_policy_stm)

        ecr_repository.grant_pull_push(codebuild_project.grant_principal)

        source_output = codepipeline.Artifact()
        source_action = actions.CodeCommitSourceAction(
            action_name='CodeCommit-Source',
            branch='main',
            trigger=actions.CodeCommitTrigger.EVENTS,
            repository=backend_repository,
            output=source_output
        )

        build_output = codepipeline.Artifact()
        build_action = actions.CodeBuildAction(
            action_name='Build',
            input=source_output,
            outputs=[
                build_output
            ],
            project=codebuild_project
        )

        deploy_action = actions.EcsDeployAction(
            action_name='DeployAction',
            service=ecs_service,
            input=build_output
        )

        pipeline = codepipeline.Pipeline(
            self, 'Pipeline',
            pipeline_name='MythicalMysfitsPipeline',
        )
        pipeline.add_stage(stage_name='Source', actions=[source_action])
        pipeline.add_stage(stage_name='Build', actions=[build_action])
        # # the following pipeline.add_stage doesn't work
        # pipeline.add_stage(stage_name='Deploy', actions=[deploy_action])

        cdk.CfnOutput(self, 'BackendRepositoryCloneUrlHttp',
                      description='Backend Repository CloneUrl HTTP',
                      value=backend_repository.repository_clone_url_http)

        cdk.CfnOutput(self, 'BackendRepositoryCloneUrlSsh',
                      description='Backend Repository CloneUrl SSH',
                      value=backend_repository.repository_clone_url_ssh)
Example #8
0
def create_pipeline(
    scope: core.Construct,
    stack_name: str,
    ecr_repository: ecr.Repository,
    app_service: ecs.FargateService,
    config: StackConfig,
    worker_service: ecs.FargateService = None,
):

    project = codebuild.PipelineProject(
        scope,
        'build',
        project_name=stack_name,
        description=f'Build project for {stack_name}. Managed by AWS CDK.',
        environment=codebuild.BuildEnvironment(
            privileged=True,
            build_image=codebuild.LinuxBuildImage.AMAZON_LINUX_2_2),
        environment_variables={
            'REPOSITORY_URI':
            codebuild.BuildEnvironmentVariable(
                value=ecr_repository.repository_uri),
        },
        cache=codebuild.Cache.local(codebuild.LocalCacheMode.DOCKER_LAYER,
                                    codebuild.LocalCacheMode.CUSTOM,
                                    codebuild.LocalCacheMode.SOURCE),
        build_spec=codebuild.BuildSpec.from_object({
            'version': '0.2',
            'phases': {
                'pre_build': {
                    'commands': [
                        '$(aws ecr get-login --no-include-email --region $AWS_REGION)',
                        'IMAGE_LATEST=${REPOSITORY_URI}:latest',
                        'IMAGE_VERSION=${REPOSITORY_URI}:${CODEBUILD_RESOLVED_SOURCE_VERSION:0:7}'
                    ]
                },
                'build': {
                    'commands': [
                        f'docker login -u="{config.docker_user}" -p="{config.docker_password}"',
                        'docker build -f Dockerfile.prod -t ${IMAGE_LATEST} .',
                        'docker tag ${IMAGE_LATEST} ${IMAGE_VERSION}'
                    ]
                },
                'post_build': {
                    'commands': [
                        'docker push ${IMAGE_LATEST}',
                        'docker push ${IMAGE_VERSION}',
                        "printf '[{\"name\":\"container\",\"imageUri\":\"%s\"}]' ${IMAGE_VERSION} > imagedefinitions.json"
                    ]
                }
            },
            'artifacts': {
                'files': ['imagedefinitions.json']
            }
        }))
    ecr_repository.grant_pull_push(project)
    source_output = codepipeline.Artifact()
    source_action = actions.GitHubSourceAction(
        action_name='Source',
        owner=config.repo_owner,
        repo=config.repo_name,
        branch=config.repo_branch,
        oauth_token=core.SecretValue.plain_text(config.github_access_token),
        output=source_output,
    )

    build_output = codepipeline.Artifact()
    build_action = actions.CodeBuildAction(
        action_name='Build',
        project=project,
        input=source_output,
        outputs=[build_output],
        type=actions.CodeBuildActionType.BUILD,
    )

    artifact_bucket = s3.Bucket.from_bucket_name(scope, 'artifactBucket',
                                                 config.artifact_bucket)

    deploy_actions = [
        actions.EcsDeployAction(
            action_name='App',
            service=app_service,
            input=build_output,
        )
    ]
    if worker_service:
        deploy_actions.append(
            actions.EcsDeployAction(
                action_name='Worker',
                service=worker_service,
                input=build_output,
            ))

    pipeline = codepipeline.Pipeline(
        scope,
        'pipeline',
        pipeline_name=stack_name,
        restart_execution_on_update=True,
        artifact_bucket=artifact_bucket,
    )
    pipeline.add_stage(
        stage_name='Source',
        actions=[source_action],
    )
    pipeline.add_stage(stage_name='Build', actions=[build_action])
    if config.enable_deploy_approval:
        pipeline.add_stage(stage_name='Approval',
                           actions=[
                               actions.ManualApprovalAction(
                                   action_name='Approve', notify_emails=[])
                           ])
    pipeline.add_stage(
        stage_name='Deploy',
        actions=deploy_actions,
    )
Example #9
0
    def __init__(self, scope: cdk.Construct, construct_id: str,
                 **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # The code that defines your stack goes here
        table = dynamodb.Table(
            self,
            "TheTable",
            table_name="cdk-table",
            partition_key=dynamodb.Attribute(
                name="id", type=dynamodb.AttributeType.STRING),
            removal_policy=cdk.RemovalPolicy.DESTROY,
        )

        # compute_environment = batch.ComputeEnvironment(
        #     self,
        #     "MyComputeEnvironment",
        #     compute_environment_name="cdk-env",
        #     compute_resources=batch.ComputeResources(
        #         vpc=Vpc.from_lookup(self, "VPC", is_default=True),
        #     ),
        #     enabled=True,
        #     managed=True,
        # )

        job_role = Role(
            self,
            "BatchJobRole",
            assumed_by=ServicePrincipal("ecs-tasks.amazonaws.com"),
            description="Role for a container in a Batch job",
            role_name="CDK-BatchJobRole",
            managed_policies=[
                ManagedPolicy.from_aws_managed_policy_name(
                    managed_policy_name="AmazonDynamoDBFullAccess"),
            ],
        )

        repository = Repository(
            self,
            "MyRepository",
            removal_policy=cdk.RemovalPolicy.DESTROY,
            repository_name="cdk-my-repository",
            lifecycle_rules=[
                LifecycleRule(max_image_count=5, description="Max 5 images")
            ],
        )

        image: ContainerImage = ContainerImage.from_ecr_repository(
            repository=repository,
            tag="latest",
        )

        container = batch.JobDefinitionContainer(
            image=image,
            job_role=job_role,
            command=["python", "run.py", "--help"],
            environment={
                "READINGS_TABLE": table.table_name,
                "AWS_REGION": self.region,
            },
            vcpus=1,
            log_configuration=batch.LogConfiguration(
                log_driver=batch.LogDriver.AWSLOGS),
            memory_limit_mib=2048,
        )

        batch.JobDefinition(
            self,
            "JobDefinitionCreate",
            container=container,
            job_definition_name="create",
            retry_attempts=1,
        )
Example #10
0
    def __init__(
        self,
        scope: App,
        id: str,
        envs: EnvSettings,
        components: ComponentsStack,
        base_resources: BaseResources,
    ):
        super().__init__(scope, id)

        self.db_secret_arn = Fn.import_value(
            BaseResources.get_database_secret_arn_output_export_name(envs))

        self.job_processing_queues = components.data_processing_queues
        self.vpc = base_resources.vpc
        self.db = base_resources.db

        self.app_bucket = Bucket(self, "App", versioned=True)

        if self.app_bucket.bucket_arn:
            CfnOutput(
                self,
                id="AppBucketOutput",
                export_name=self.get_app_bucket_arn_output_export_name(envs),
                value=self.app_bucket.bucket_arn,
            )

        self.pages_bucket = Bucket(self, "Pages", public_read_access=True)

        self.domain_name = StringParameter.from_string_parameter_name(
            self,
            "DomainNameParameter",
            string_parameter_name="/schema-cms-app/DOMAIN_NAME").string_value

        self.certificate_arn = StringParameter.from_string_parameter_name(
            self,
            "CertificateArnParameter",
            string_parameter_name="/schema-cms-app/CERTIFICATE_ARN"
        ).string_value

        django_secret = Secret(self,
                               "DjangoSecretKey",
                               secret_name="SCHEMA_CMS_DJANGO_SECRET_KEY")
        lambda_auth_token_secret = Secret(
            self,
            "LambdaAuthToken",
            secret_name="SCHEMA_CMS_LAMBDA_AUTH_TOKEN")

        if lambda_auth_token_secret.secret_arn:
            CfnOutput(
                self,
                id="lambdaAuthTokenArnOutput",
                export_name=self.get_lambda_auth_token_arn_output_export_name(
                    envs),
                value=lambda_auth_token_secret.secret_arn,
            )

        self.django_secret_key = EcsSecret.from_secrets_manager(django_secret)
        self.lambda_auth_token = EcsSecret.from_secrets_manager(
            lambda_auth_token_secret)

        tag_from_context = self.node.try_get_context("app_image_tag")
        tag = tag_from_context if tag_from_context != "undefined" else None

        api_image = ContainerImage.from_ecr_repository(
            repository=Repository.from_repository_name(
                self,
                id="BackendRepository",
                repository_name=BaseECR.get_backend_repository_name(envs)),
            tag=tag,
        )
        nginx_image = ContainerImage.from_ecr_repository(
            repository=Repository.from_repository_name(
                self,
                id="NginxRepository",
                repository_name=BaseECR.get_nginx_repository_name(envs)),
            tag=tag,
        )

        self.api = ApplicationLoadBalancedFargateService(
            self,
            "ApiService",
            service_name=f"{envs.project_name}-api-service",
            cluster=Cluster.from_cluster_attributes(
                self,
                id="WorkersCluster",
                cluster_name="schema-ecs-cluster",
                vpc=self.vpc,
                security_groups=[],
            ),
            task_image_options=ApplicationLoadBalancedTaskImageOptions(
                image=nginx_image,
                container_name="nginx",
                container_port=80,
                enable_logging=True,
            ),
            desired_count=1,
            cpu=512,
            memory_limit_mib=1024,
            certificate=Certificate.from_certificate_arn(
                self, "Cert", certificate_arn=self.certificate_arn),
            domain_name=self.domain_name,
            domain_zone=PrivateHostedZone(
                self,
                "zone",
                vpc=self.vpc,
                zone_name=self.domain_name,
            ),
        )

        self.api.task_definition.add_container(
            "backend",
            image=api_image,
            command=[
                "sh", "-c",
                "/bin/chamber exec $CHAMBER_SERVICE_NAME -- ./scripts/run.sh"
            ],
            logging=AwsLogDriver(stream_prefix="backend-container"),
            environment={
                "POSTGRES_DB": envs.data_base_name,
                "AWS_STORAGE_BUCKET_NAME": self.app_bucket.bucket_name,
                "AWS_STORAGE_PAGES_BUCKET_NAME": self.pages_bucket.bucket_name,
                "SQS_WORKER_QUEUE_URL":
                self.job_processing_queues[0].queue_url,
                "SQS_WORKER_EXT_QUEUE_URL":
                self.job_processing_queues[1].queue_url,
                "SQS_WORKER_MAX_QUEUE_URL":
                self.job_processing_queues[2].queue_url,
                "CHAMBER_SERVICE_NAME": "schema-cms-app",
                "CHAMBER_KMS_KEY_ALIAS": envs.project_name,
            },
            secrets={
                "DB_CONNECTION":
                EcsSecret.from_secrets_manager(
                    Secret.from_secret_arn(self,
                                           id="DbSecret",
                                           secret_arn=self.db_secret_arn)),
                "DJANGO_SECRET_KEY":
                self.django_secret_key,
                "LAMBDA_AUTH_TOKEN":
                self.lambda_auth_token,
            },
            cpu=512,
            memory_limit_mib=1024,
        )

        self.django_secret_key.grant_read(
            self.api.service.task_definition.task_role)

        self.app_bucket.grant_read_write(
            self.api.service.task_definition.task_role)
        self.pages_bucket.grant_read_write(
            self.api.service.task_definition.task_role)

        for queue in self.job_processing_queues:
            queue.grant_send_messages(
                self.api.service.task_definition.task_role)

        self.api.service.connections.allow_to(self.db.connections,
                                              Port.tcp(5432))
        self.api.task_definition.add_to_task_role_policy(
            PolicyStatement(
                actions=["ses:SendRawEmail", "ses:SendBulkTemplatedEmail"],
                resources=["*"],
            ))

        self.api.task_definition.add_to_task_role_policy(
            PolicyStatement(
                actions=[
                    "kms:Get*", "kms:Describe*", "kms:List*", "kms:Decrypt"
                ],
                resources=[
                    Fn.import_value(
                        BaseKMS.get_kms_arn_output_export_name(envs))
                ],
            ))

        self.api.task_definition.add_to_task_role_policy(
            PolicyStatement(actions=["ssm:DescribeParameters"],
                            resources=["*"]))

        self.api.task_definition.add_to_task_role_policy(
            PolicyStatement(
                actions=["ssm:GetParameters*"],
                resources=[
                    f"arn:aws:ssm:{self.region}:{self.account}:parameter/schema-cms-app/*"
                ],
            ))
    def __init__(self, scope: core.Construct, construct_id: str,
                 **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        stack_util = StackUtil()
        repo = Repository.from_repository_attributes(
            scope=self,
            id='FunctionRepository',
            repository_name=stack_util.get_name('repo'),
            repository_arn=
            f'arn:aws:ecr:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:repository/{stack_util.get_name("repo")}'
        )

        fail_task = Fail(self, 'FailTask', comment='failed.')
        succeed_task = Succeed(self, 'SucceedTask', comment='succeeded.')

        get_forecast_function = get_get_forecast_resource(self, repo)
        send_message_function = get_send_message_resource(self, repo)

        get_forecast_task = LambdaInvoke(self,
                                         'GetForecastTask',
                                         lambda_function=get_forecast_function,
                                         input_path='$',
                                         result_path='$.get_forecast_task',
                                         output_path='$',
                                         payload_response_only=True)
        get_forecast_task.add_catch(fail_task,
                                    errors=[Errors.ALL],
                                    result_path='$.error_info')

        send_message_task = LambdaInvoke(self,
                                         'SendMessageTask',
                                         lambda_function=send_message_function,
                                         input_path='$.get_forecast_task.body',
                                         result_path='$.send_message_function',
                                         output_path='$',
                                         payload_response_only=True)
        send_message_task.add_catch(fail_task,
                                    errors=[Errors.ALL],
                                    result_path='$.error_info')

        state_machine = StateMachine(
            self,
            id='StateMachine',
            state_machine_name=stack_util.get_upper_name('STATE-MACHINE'),
            definition=get_forecast_task.next(send_message_task).next(
                succeed_task))

        today_rule = Rule(
            self,
            'StateMachineTodayRule',
            description='invoking state machine for today',
            rule_name=stack_util.get_upper_name('INVOKE-STATE-MACHINE-TODAY'),
            schedule=Schedule.cron(
                hour='23',
                minute='0',
            ))

        tomorrow_rule = Rule(self,
                             'StateMachineTomorrowRule',
                             description='invoking state machine for tomorrow',
                             rule_name=stack_util.get_upper_name(
                                 'INVOKE-STATE-MACHINE-TOMORROW'),
                             schedule=Schedule.cron(
                                 hour='9',
                                 minute='30',
                             ))

        today_target = SfnStateMachine(state_machine,
                                       input=RuleTargetInput.from_object({
                                           'city':
                                           '130010',
                                           'date_label':
                                           '今日'
                                       }))
        today_rule.add_target(today_target)

        tomorrow_target = SfnStateMachine(state_machine,
                                          input=RuleTargetInput.from_object({
                                              'city':
                                              '130010',
                                              'date_label':
                                              '明日'
                                          }))
        tomorrow_rule.add_target(tomorrow_target)