Пример #1
0
    def deploy(self,
               stack_name: str,
               *,
               template_path: str = None,
               action_name: str = None,
               stage_it: bool = True,
               **deploy_config):
        """Deploy stage for AWS CodePipeline

        Args:
            stack_name (str): CDK/CFN stack name to deploy
            template_path (str, optional): the generated CFN template path. Defaults to: 'stack_name'.template.json
            action_name (str, optional): AWS Pipeline action name. Defaults to: deploy-'stack_name'
            stage_it (bool, optional): Automagically stage this in pipeline. Defaults to True.
        """
        if not template_path:
            template_path = self.artifacts['builds'][0].at_path(
                "{}.template.json".format(stack_name))
        if not action_name:
            action_name = "deploy-{}".format(stack_name)

        deploy = cpa.CloudFormationCreateUpdateStackAction(
            admin_permissions=True,
            extra_inputs=self.artifacts['builds'],
            template_path=template_path,
            action_name=action_name,
            stack_name=stack_name,
            **deploy_config)
        # Save deploy action
        self.actions['deploy'][action_name] = deploy
        # Stage it (execute deploy) in pipeline
        if stage_it:
            self.pipe.add_stage(stage_name=action_name,
                                actions=[self.actions['deploy'][action_name]])
Пример #2
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        pipeline = codepipeline.Pipeline(
            self, "CodePipeline",
            pipeline_name="CDKPipelineTest"
        )
        token = core.SecretValue.secrets_manager("arn:aws:secretsmanager:ap-northeast-1:821383200340:secret:GitHubKey-LPPj2Z")
        sourceoutput = codepipeline.Artifact()
        sourceaction = actions.GitHubSourceAction(
            oauth_token=token,
            output=sourceoutput,
            owner="haimila",
            branch="master",
            repo="cfpipeline",
            action_name="SourceAction"
        )
        iam_capabilities = core.CfnCapabilities.NAMED_IAM
        templatepath = codepipeline.ArtifactPath(sourceoutput, "cfpipeline.yml")
        deployaction = actions.CloudFormationCreateUpdateStackAction(
            admin_permissions=True,
            stack_name="CdkPipelineStack",
            template_path=templatepath,
            replace_on_failure=True,
            action_name="DeployAction",
            capabilities=[iam_capabilities]
        )

        sourcestage = pipeline.add_stage(
            stage_name="Source",
            actions=[sourceaction]
        )

        pipeline.add_stage(
            stage_name="Deploy",
            actions=[deployaction],
            placement={"just_after": sourcestage}
        )
def create_cloudformation_action(scope,
                                 action_name,
                                 stack_name,
                                 source_output,
                                 template_file,
                                 template_parameters_file,
                                 run_order=1):
    """
    create_cloudformation_actio a CloudFormation action to be added to AWS Codepipeline stage

    :scope: CDK Construct scope that's needed to create CDK resources
    :action_name: name of the StackSet action
    :stack_name: name of the stack to be deployed
    :source_output: CDK object of the Source action's output
    :template_file: name of the Cloudformation template to be deployed
    :template_parameters_file: name of the template parameters
    :return: codepipeline CloudFormation action in a form of a CDK object that can be attached to a codepipeline stage
    """

    # Create codepipeline's cloudformation action
    create_cloudformation_action = codepipeline_actions.CloudFormationCreateUpdateStackAction(
        action_name=action_name,
        stack_name=stack_name,
        capabilities=[cloudformation.CloudFormationCapabilities.NAMED_IAM],
        template_path=source_output.at_path(template_file),
        # Admin permissions are added to the deployement role used by the CF action for simplicity
        # and deploy different resources by different MLOps pipelines. Roles are defined by the
        # pipelines' cloudformation templates.
        admin_permissions=True,
        template_configuration=source_output.at_path(template_parameters_file),
        variables_namespace=f"{action_name}-namespace",
        replace_on_failure=True,
        run_order=run_order,
    )

    return create_cloudformation_action
Пример #4
0
    def __init__(self, scope: core.Construct, id: str,
                 lambda_code: _lambda.CfnParametersCode,
                 custom_resource: _lambda.CfnParametersCode, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # The code that defines your stack goes here

        self.lambda_code = lambda_code
        self.custom_resource = custom_resource

        code = _commit.Repository(
            self,
            'CustomerServerlessCode',
            repository_name='spring-petclinic-customers-serverless')

        lambda_project = _build.PipelineProject(
            self,
            'CustomerLambdaBuild',
            build_spec=_build.BuildSpec.from_object({
                'version': 0.2,
                'phases': {
                    'install': {
                        'runtime-versions': {
                            'java': 'openjdk8'
                        },
                        'commands': []
                    },
                    'build': {
                        'commands': 'mvn package',
                    },
                    'post_build': {
                        'commands': [
                            'mkdir deploy',
                            'cp target/spring-petclinic-customers-serverless-2.0.7.RELEASE.jar deploy/',
                            'cd deploy && jar xvf spring-petclinic-customers-serverless-2.0.7.RELEASE.jar',
                            'rm spring-petclinic-customers-serverless-2.0.7.RELEASE.jar',
                        ]
                    }
                },
                'artifacts': {
                    'base-directory': 'deploy',
                    'files': ['**/*']
                },
            }),
            environment=_build.BuildEnvironment(
                build_image=_build.LinuxBuildImage.STANDARD_2_0))

        cdk_project = _build.PipelineProject(
            self,
            'CustomerCdkBuild',
            build_spec=_build.BuildSpec.from_object({
                'version': 0.2,
                'phases': {
                    'install': {
                        'runtime-versions': {
                            'python': '3.7',
                            'nodejs': '10'
                        },
                        'commands': [
                            'npm install -g [email protected]',
                            'pip install aws-cdk.core==1.10.0',
                            'pip install -r requirements.txt'
                        ]
                    },
                    'build': {
                        'commands': [
                            'cdk synth -o dist',
                        ]
                    }
                },
                'artifacts': {
                    'secondary-artifacts': {
                        'CdkBuildOutput': {
                            'base-directory': 'dist',
                            'files': ['customer-lambda-stack.template.json']
                        },
                        'CustomRecoureOutput': {
                            'base-directory': 'custom-resource-code',
                            'discard-paths': 'yes',
                            'files':
                            ['index.py', 'owner.json', 'cfnresponse.py']
                        }
                    }
                }
            }),
            environment=_build.BuildEnvironment(
                build_image=_build.LinuxBuildImage.STANDARD_2_0))

        source_output = _pipeline.Artifact('SourceOutput')
        cdk_build_output = _pipeline.Artifact('CdkBuildOutput')
        lambda_build_output = _pipeline.Artifact('LambdaBuildOutput')
        custom_resource_output = _pipeline.Artifact('CustomRecoureOutput')

        pipline = _pipeline.Pipeline(
            self,
            'ServerlessPipeline',
            stages=[{
                'stageName':
                'Source',
                'actions': [
                    _action.CodeCommitSourceAction(
                        action_name='CodeCommit_Source',
                        repository=code,
                        output=source_output)
                ]
            }, {
                'stageName':
                'Build',
                'actions': [
                    _action.CodeBuildAction(
                        action_name='CodeBuild_CDK',
                        project=cdk_project,
                        input=source_output,
                        outputs=[cdk_build_output, custom_resource_output]),
                    _action.CodeBuildAction(action_name='CodeBuild_Lambda',
                                            project=lambda_project,
                                            input=source_output,
                                            outputs=[lambda_build_output])
                ]
            }, {
                'stageName':
                'Deploy',
                'actions': [
                    _action.CloudFormationCreateUpdateStackAction(
                        action_name='Lambda_CFN_Deploy',
                        template_path=cdk_build_output.at_path(
                            'customer-lambda-stack.template.json'),
                        stack_name='customer-lambda-stack',
                        admin_permissions=True,
                        parameter_overrides={
                            **self.lambda_code.assign(bucket_name=lambda_build_output.bucket_name,
                                                      object_key=lambda_build_output.object_key),
                            **self.custom_resource.assign(bucket_name=custom_resource_output.bucket_name,
                                                          object_key=custom_resource_output.object_key)
                        },
                        extra_inputs=[
                            lambda_build_output, custom_resource_output
                        ])
                ]
            }])
Пример #5
0
def create_action(
    scope: core.Construct,
    id: str,
    action_def: Union[CodeCommitAction, CodeBuildAction,
                      CloudFormationCreateUpdateStackAction, ApprovalAction,
                      LambdaInvokeAction, S3SourceAction, ],
):
    action_name = action_def.pop("name")
    run_order = action_def.get("run_order", 1)
    variables_namespace = action_def.get("variables_namespace")
    role = (aws_iam.Role.from_role_arn(scope, f"{id}RoleRef",
                                       action_def["role_arn"])
            if "role_arn" in action_def else None)

    if action_def["type"] == "CODECOMMIT":
        action_def = cast(CodeCommitAction, action_def)
        repository = aws_codecommit.Repository.from_repository_name(
            scope, f"{id}Repo", action_def["repository"])
        output = aws_codepipeline.Artifact(action_def["output"])
        return aws_codepipeline_actions.CodeCommitSourceAction(
            action_name=action_name,
            output=output,
            repository=repository,
            branch=action_def.get("branch", "master"),
            run_order=run_order,
            role=role,
            variables_namespace=variables_namespace,
        )
    elif action_def["type"] == "S3_SOURCE":
        action_def = cast(S3SourceAction, action_def)
        output = aws_codepipeline.Artifact(action_def["output"])
        if "kms_key_arn" in action_def:
            role = aws_iam.Role(
                scope,
                f"{id}Role",
                assumed_by=aws_iam.AccountRootPrincipal(),
            )
            aws_kms.Key.from_key_arn(
                scope, f"{id}KeyRef",
                key_arn=action_def["kms_key_arn"]).grant_decrypt(role)
        if "bucket" in action_def:
            bucket = aws_s3.Bucket.from_bucket_name(scope,
                                                    f"{id}SourceBucketRef",
                                                    action_def["bucket"])
        else:
            bucket = aws_s3.Bucket(
                scope,
                f"{id}SourceBucket",
                block_public_access=aws_s3.BlockPublicAccess.BLOCK_ALL,
                removal_policy=core.RemovalPolicy.DESTROY,
            )
            core.CfnOutput(scope,
                           f"{id}SourceBucketName",
                           value=bucket.bucket_name)
        return aws_codepipeline_actions.S3SourceAction(
            action_name=action_name,
            output=output,
            run_order=run_order,
            role=role,
            bucket=bucket,
            bucket_key=action_def["key"],
        )
    elif action_def["type"] == "CODEBUILD":
        action_def = cast(CodeBuildAction, action_def)
        # Set up CodeBuild project
        project_params = {
            "build_spec":
            aws_codebuild.BuildSpec.from_source_filename(
                action_def.get("build_spec", "buildspec.yaml")),
            "timeout":
            core.Duration.minutes(int(action_def.get("timeout_minutes", 60))),
        }
        project_params["environment"] = {
            "build_image": aws_codebuild.LinuxBuildImage.AMAZON_LINUX_2_3
        }
        if "environment" in action_def:
            if "build_image" in action_def["environment"]:
                project_params["environment"]["build_image"] = getattr(
                    aws_codebuild.LinuxBuildImage,
                    action_def["environment"].pop("build_image"),
                )
            if "compute_type" in action_def["environment"]:
                project_params["environment"]["compute_type"] = getattr(
                    aws_codebuild.ComputeType,
                    action_def["environment"].pop("compute_type"),
                )
            project_params["environment"].update(**action_def["environment"])
        project_role = aws_iam.Role(
            scope,
            f"{id}CodeBuildRole",
            path="/codebuild/",
            assumed_by=aws_iam.ServicePrincipal(
                service="codebuild.amazonaws.com"),
        )
        project_role.add_to_policy(
            aws_iam.PolicyStatement(actions=["*"],
                                    resources=["*"],
                                    effect=aws_iam.Effect.ALLOW))
        project_environment_variables = ({
            var_key: aws_codebuild.BuildEnvironmentVariable(
                value=str(var_value),
                type=aws_codebuild.BuildEnvironmentVariableType.PLAINTEXT,
            )
            for var_key, var_value in
            action_def["environment_variables"].items()
            if "#" not in str(var_value)
        } if "environment_variables" in action_def else None)
        project = aws_codebuild.PipelineProject(
            scope,
            f"{id}Project",
            project_name=id,
            role=project_role,
            environment_variables=project_environment_variables,
            **project_params,
        )
        pipeline_environment_variables = ({
            var_key: aws_codebuild.BuildEnvironmentVariable(
                value=str(var_value),
                type=aws_codebuild.BuildEnvironmentVariableType.PLAINTEXT,
            )
            for var_key, var_value in
            action_def["environment_variables"].items()
            if "#" in str(var_value)
        } if "environment_variables" in action_def else None)
        extra_inputs = ([
            aws_codepipeline.Artifact(input_)
            for input_ in action_def["extra_inputs"]
        ] if "extra_inputs" in action_def else None)
        outputs = ([
            aws_codepipeline.Artifact(output)
            for output in action_def["outputs"]
        ] if "outputs" in action_def else None)
        return aws_codepipeline_actions.CodeBuildAction(
            action_name=action_name,
            input=aws_codepipeline.Artifact(action_def["input"]),
            project=project,
            run_order=run_order,
            role=role,
            variables_namespace=variables_namespace,
            environment_variables=pipeline_environment_variables,
            extra_inputs=extra_inputs,
            outputs=outputs,
        )
    elif action_def["type"] == "CLOUDFORMATION":
        action_def = cast(CloudFormationCreateUpdateStackAction, action_def)
        return aws_codepipeline_actions.CloudFormationCreateUpdateStackAction(
            action_name=action_name,
            admin_permissions=False,
            stack_name=action_def["stack_name"],
            template_path=aws_codepipeline.ArtifactPath(
                aws_codepipeline.Artifact(action_def["input"]),
                action_def.get("template_path", "template.yaml"),
            ),
            capabilities=[
                # This lstrip does not support all possibilties, but is good enough for now
                aws_cloudformation.CloudFormationCapabilities[
                    capability.lstrip("CAPABILITY_")]
                for capability in action_def["capabilities"]
            ] if "capabilities" in action_def else None,
            deployment_role=role,
            role=role,
            parameter_overrides=action_def.get("parameter_overrides"),
            run_order=run_order,
            variables_namespace=variables_namespace,
        )
    elif action_def["type"] == "APPROVAL":
        action_def = cast(ApprovalAction, action_def)
        return aws_codepipeline_actions.ManualApprovalAction(
            action_name=action_name,
            run_order=run_order,
            role=role,
            additional_information=action_def.get("additional_information"),
            external_entity_link=action_def.get("external_entity_link"),
            notification_topic=action_def.get("notification_topic"),
            variables_namespace=variables_namespace,
        )
    elif action_def["type"] == "LAMBDA":
        action_def = cast(LambdaInvokeAction, action_def)
        user_parameters = action_def.get("user_parameters")
        return aws_codepipeline_actions.LambdaInvokeAction(
            action_name=action_name,
            run_order=run_order,
            lambda_=aws_lambda.Function.from_function_arn(
                scope, f"{id}Lambda", action_def["function_arn"]),
            user_parameters=user_parameters,
            role=role,
            variables_namespace=variables_namespace,
        )
    def __init__(self,
                 scope: core.Construct,
                 id: str,
                 *,
                 lambda_code: lambda_.CfnParametersCode = None,
                 sns_target,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # [ CodeCommit: Repository ]
        #
        # Grabs the repository the pipeline will be pulling from.

        code = codecommit.Repository.from_repository_name(
            self, "ImportedRepo", "CodeCommitRepo")

        # [ CodeBuild: Project: CDK ]
        #
        # Creates the project for building the Lambda CloudFormation template using CDK.

        cdk_build = codebuild.PipelineProject(
            self,
            "CdkBuild",
            build_spec=codebuild.BuildSpec.from_object(
                dict(version="0.2",
                     phases=dict(install=dict(commands=[
                         "npm install -g aws-cdk", "cdk --version",
                         "python --version", "pip install -r requirements.txt"
                     ]),
                                 pre_build=dict(
                                     commands=["python -m pytest tests"]),
                                 build=dict(commands=["cdk synth -o dist"])),
                     artifacts={
                         "base-directory": "dist",
                         "files": ["LambdaStack.template.json"]
                     },
                     environment=dict(
                         buildImage=codebuild.LinuxBuildImage.STANDARD_2_0))))

        # [ CodeBuild: Project: Lambda ]
        #
        # Creates the project for building the Lambda Functions.

        lambda_build = codebuild.PipelineProject(
            self,
            'LambdaBuild',
            build_spec=codebuild.BuildSpec.from_object(
                dict(version="0.2",
                     phases=dict(install=dict(commands=[
                         "cd lambda", "pip install -r requirements.txt"
                     ]),
                                 post_build=dict(commands=["pytest"])),
                     artifacts={
                         "base-directory": "lambda",
                         "files": ["index.py"]
                     },
                     environment=dict(
                         buildImage=codebuild.LinuxBuildImage.STANDARD_2_0))))

        # [ CodePipeline: Artifacts ]
        #
        # Creates the artifacts.

        source_output = codepipeline.Artifact()
        cdk_build_output = codepipeline.Artifact("CdkBuildOutput")
        lambda_build_output = codepipeline.Artifact("LambdaBuildOutput")

        # [ S3: Location ]

        lambda_location = lambda_build_output.s3_location

        # [ CodePipeline: Stages: Actions ]
        #
        # Creates the pipeline stages actions.

        repo_source_action = codepipeline_actions.CodeCommitSourceAction(
            action_name="CodeCommit_Source",
            repository=code,
            output=source_output)

        lambda_build_action = codepipeline_actions.CodeBuildAction(
            action_name="Lambda_Build",
            project=lambda_build,
            input=source_output,
            outputs=[lambda_build_output])

        cdk_build_action = codepipeline_actions.CodeBuildAction(
            action_name="CDK_Build",
            project=cdk_build,
            input=source_output,
            outputs=[cdk_build_output])

        cdk_deploy_action = codepipeline_actions.CloudFormationCreateUpdateStackAction(
            action_name="Lambda_CFN_Deploy",
            template_path=cdk_build_output.at_path(
                "LambdaStack.template.json"),
            stack_name="LambdaDeploymentStack",
            admin_permissions=True,
            parameter_overrides=dict(
                lambda_code.assign(
                    bucket_name=lambda_location.bucket_name,
                    object_key=lambda_location.object_key,
                    object_version=lambda_location.object_version)),
            extra_inputs=[lambda_build_output])

        # [ CodePipeline ]
        #
        # Creates the pipelines.

        pipeline = codepipeline.Pipeline(
            self,
            "Pipeline",
            stages=[
                codepipeline.StageProps(stage_name="Source",
                                        actions=[repo_source_action]),
                codepipeline.StageProps(
                    stage_name="Build",
                    actions=[lambda_build_action, cdk_build_action]),
                codepipeline.StageProps(stage_name="Deploy",
                                        actions=[cdk_deploy_action])
            ])

        # [ CodePipeline: Events ]
        #
        # Creates the events for the pipeline, stages, and actions.

        repo_source_action.on_state_change(
            'RepoSourceStateChange',
            target=sns_target,
            event_pattern=event.EventPattern(detail={'state': ['FAILED']}))

        lambda_build_action.on_state_change(
            'LambdaBuildStateChange',
            target=sns_target,
            event_pattern=event.EventPattern(detail={'state': ['FAILED']}))

        cdk_build_action.on_state_change(
            'CDKBuildStateChange',
            target=sns_target,
            event_pattern=event.EventPattern(detail={'state': ['FAILED']}))

        cdk_deploy_action.on_state_change(
            'CDKDeployStateChange',
            target=sns_target,
            event_pattern=event.EventPattern(detail={'state': ['FAILED']}))

        pipeline.on_state_change(
            'PipelineStateChange',
            target=sns_target,
            event_pattern=event.EventPattern(detail={'state': ['SUCCEEDED']}))